# 2022q1 Homework3 (quiz3) contributed by < `cy023` > > [測驗題](https://hackmd.io/@sysprog/linux2022-quiz3) ## 測驗 `1` ```c #define GENMASK(h, l) \ (((~0UL) >> (LEFT)) & ((~0UL) >> (l) << (RIGHT))) ``` ```c #define GENMASK(h, l) \ (((~0UL) >> (63 - h)) & ((~0UL) >> (l) << (l))) ``` <!-- Why `>> (l) << (l)`, instead of `<< (l)` --> :::success 延伸問題: - [ ] 1. 解釋上述程式碼運作原理 - [ ] 2. 比較 Linux 核心 GENMASK 巨集的實作,闡述其額外的考量 - [ ] 3. 舉出 Linux 核心原始程式碼中二處 GENMASK 巨集和 [include/linux/bitfield.h](https://github.com/torvalds/linux/blob/master/include/linux/bitfield.h) 的應用案例 ::: ## 測驗 `2` ```c struct foo; struct fd { struct foo *foo; unsigned int flags; }; enum { FOO_DEFAULT = 0, FOO_ACTION, FOO_UNLOCK, } FOO_FLAGS; static inline struct fd to_fd(unsigned long v) { return (struct fd){EXP1, v & 3}; } ``` :::success 延伸問題: - [ ] 1. 解釋上述程式碼運作原理 - [ ] 2. 在 Linux 核心原始程式碼找出類似技巧的實作 (例如檔案系統) 並解說 ::: ## 測驗 `3` ```c uint8_t rev8(uint8_t x) { x = (x >> 4) | (x << 4); x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2); x = ((x & 0xAA) >> 1) | ((x & 0x55) << 1); return x; } ``` :::success 延伸問題: - [ ] 1. 解釋上述程式碼運作原理 - [ ] 2. 在 Linux 核心原始程式碼找出類似技巧的實作並解說其應用場景 ::: ## 測驗 `4` ```c #include <assert.h> #define _foreach_no_nullval(i, p, arr) \ assert((i) >= sizeof(arr) / sizeof(arr[0]) || (p)) #define foreach_int(i, ...) \ for (unsigned _foreach_i = (((i) = ((int[]){__VA_ARGS__})[0]), 0); \ _foreach_i < sizeof((int[]){__VA_ARGS__}) / sizeof(int); \ (i) = ((int[]){__VA_ARGS__, 0})[EXP4]) #define foreach_ptr(i, ...) \ for (unsigned _foreach_i = \ (((i) = (void *) ((typeof(i)[]){__VA_ARGS__})[0]), 0); \ (i); (i) = (void *) ((typeof(i)[]){__VA_ARGS__, \ NULL})[EXP5], \ _foreach_no_nullval(_foreach_i, i, \ ((const void *[]){__VA_ARGS__}))) ``` ### 參考 C99 規格書 > 6.10.3 Macro replacement > Constraints > ... > 5 The identifier \_\_VA_ARGS\_\_ shall occur only in the replacement-list of a function-like macro that uses the ellipsis notation in the parameters. > 6.10.3.1 Argument substitution > ... > 2 An identifier \_\_VA_ARGS\_\_ that occurs in the replacement list shall be treated as if it were a parameter, and the variable arguments shall form the preprocessing tokens used to replace it. ## 測驗 `5` `dvs << shift` `dvd -= dvs << shift` ## 測驗 `6` ## 測驗 `7` ## 測驗 `8` ## 測驗 `9` ```c /* maximum alignment needed for any type on this platform, rounded up to a power of two */ #define MAX_ALIGNMENT 16 /* Given a size, round up to the next multiple of sizeof(void *) */ #define ROUND_UP_TO_ALIGNMENT_SIZE(x) \ (((x) + MAX_ALIGNMENT - 1) & ~(-MAX_ALIGNMENT)) /* Given a size, round down to the next multiple of sizeof(void *) */ #define ROUND_DOWN_TO_ALIGNMENT_SIZE(x) \ ((x) & ~(-MAX_ALIGNMENT)) ``` ## 測驗 `10` ```c #define DIVIDE_ROUND_CLOSEST(x, divisor) \ ({ \ typeof(x) __x = x; \ typeof(divisor) __d = divisor; \ (((typeof(x)) -1) > 0 || ((typeof(divisor)) -1) > 0 || \ (((__x) > 0) == ((__d) > 0))) \ ? ((RRR) / (__d)) \ : ((SSS) / (__d)); \ }) ``` ## 測驗 `11` `fls()` 函式用來找 64 bits 變數中最靠近 ```c // find left set static inline unsigned long fls(unsigned long word) { int num = 64 - 1; if (!(word & (~0ul << 32))) { // focus on bit63 ~ bit32 num -= 32; word <<= 32; } if (!(word & (~0ul << (64 - 16)))) { // focus on bit63 ~ bit48 num -= 16; word <<= 16; } if (!(word & (~0ul << (64 - 8)))) { // focus on bit63 ~ bit56 num -= 8; word <<= 8; } if (!(word & (~0ul << (64 - 4)))) { // focus on bit63 ~ bit60 num -= 4; word <<= 4; } if (!(word & (~0ul << (64 - 2)))) { // focus on bit63 ~ bit62 num -= 2; word <<= 2; } if (!(word & (~0ul << (64 - 1)))) // focus on bit63 num -= 1; return num; } ``` ```c unsigned long i_sqrt(unsigned long x) { unsigned long b, m, y = 0; if (x <= 1) return x; m = 1UL << (fls(x) & ~1UL); while (m) { b = y + m; y >>= 1; if (x >= b) { x -= b; y += m; } m >>= 2; } return y; } ``` - [lib/math/int_sqrt.c](https://github.com/torvalds/linux/blob/master/lib/math/int_sqrt.c) :::success 延伸問題: - [ ] 解釋上述程式碼運作原理,嘗試利用硬體的 clz/ctz 指令改寫 - [ ] 在 Linux 核心找出類似的巨集和程式碼,說明其應用場景 :::