# 2022q1 Homework3 (quiz3) contributed by <`yaohwang99` > > [quiz3](https://hackmd.io/@sysprog/linux2022-quiz3) ## Problem 1 In Linux kernel,`GENMASK` gernerates bitmask for the given range. + GENMASK(6, 4) produces 01110000~2~ + GENMASK(39, 21) produces 0x000000FFFFE00000 For the above 2 examples to be true, we can deduct that ==`LEFT` is `63 - h` and `RIGHT` is `l`==. 1. To clear the more significant bits, ==`LEFT` must be `63 - h`==. 2. To clear the less significant bits, ==`RIGHT` is `l`==. ```c #define GENMASK(h, l) \ (((~0UL) >> (LEFT)) & ((~0UL) >> (l) << (RIGHT))) ``` :::danger **However, I believe that the code is not correct because:** + GENMASK(63, 8) produces `0xFFFFFFFFFFFFFFFF & 0x00FFFFFFFFFFFF00 == 0x00FFFFFFFFFFFF00 `which is not the correct result. ::: I believe the following code is correct. ```c #define GENMASK(h, l) \ (((~0UL) >> (63-h) & ((~0UL) << l))) ``` ## Problem 2 ### Memory alignment ```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}; } ``` The function `to_fd` use the parameter `v` , align down to 4, and use it as the address of `*foo`. Align down to 4 means that we clear the last 2 bits of `v`, therefore, ==EXP1 is `v & ~3`==. ## Problem 3 ```c= #include <stdint.h> uint8_t rev8(uint8_t x) { x = (x >> 4) | (x << 4); x = ((x & 0xCC) >> 2) | (EXP2); x = ((x & 0xAA) >> 1) | (EXP3); return x; } ``` 0xCC = 11001100~2~ 0xAA = 10101010~2~ line 4 swaps the most significant 4 bits with the less significant 4 bits line 5 swaps every 2 bits line 6 swaps every bit. ==EXP2: `x & 0x33) << 2`== ==EXP3: `x & 0x55) << 2`== ## Problem 4 ```c int i; foreach_int(i, 0, -1, 100, 0, -99) { printf("i is %i\n", i); } const char *p; foreach_ptr(p, "Hello", "world") { printf("p is %s\n", p); } ``` ```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__}))) ``` From [C99 Standard](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf) > **6.5.17 Comma operator** **Syntax** >+ expression: + *assignment-expression* + *expression , assignment-expression* >**Semantics** The left operand of a comma operator is evaluated as a void expression; there is a sequence point between its evaluation and that of the right operand. Then the right operand is evaluated; the result has its type and value. For example, the function `f(a, (t=3, t+2), c)` has three arguments, the second of which has the value 5. `unsigned _foreach_i = (((i) = ((int[]){__VA_ARGS__})[0]), 0)` assigns `((int[]){__VA_ARGS__})[0])` to `i`, then assign the second `0` to `_foreach_i ` Just like a common `for(int i = 0; i < n; ++i)` , we can deduct that ==EXP4 and EXP5 is `++_foreach_1`==. ## Problem 5 ```c #include <limits.h> int divide(int dividend, int divisor) { int signal = 1; unsigned int dvd = dividend; if (dividend < 0) { signal *= -1; dvd = ~dvd + 1; } unsigned int dvs = divisor; if (divisor < 0) { signal *= -1; dvs = ~dvs + 1; } int shift = 0; while (dvd > (EXP6)) shift++; unsigned int res = 0; while (dvd >= dvs) { while (dvd < (dvs << shift)) shift--; res |= (unsigned int) 1 << shift; EXP7; } if (signal == 1 && res >= INT_MAX) return INT_MAX; return res * signal; } ``` ## Problem 6 ```graphviz digraph { rankdir = LR compound = true subgraph cluster0{ style = filled color = gray90 node1[shape = record label = "heads[0]|<1>heads[1]|...|heads[slope_size-1]"] } subgraph cluster1{ style = filled color = gray90 label = point_node node2[shape = record label = "p1|p2|<link>link"] } subgraph cluster2{ style = filled color = gray90 label = point_node node3[shape = record label = "p1|p2|<link>link"] } node1:1 -> node2:link[dir = both] node2:link -> node3:link[dir = both] } ``` ```c= for (i = 0; i < pointsSize; i++) { for (j = i + 1; j < pointsSize; j++) { if (points[i].x == points[j].x) hori_cnts[i]++, hori_cnts[j]++; if (points[i].y == points[j].y) vert_cnts[i]++, vert_cnts[j]++; if (points[i].x == points[j].x && points[i].y == points[j].y) dup_cnts[i]++, dup_cnts[j]++; if (points[i].x != points[j].x && points[i].y != points[j].y) { int dx = points[j].x - points[i].x; int dy = points[j].y - points[i].y; int tmp = gcd(dx, dy); dx /= tmp; dy /= tmp; int hash = dx * dy - 1333 * (dx + dy); if (hash < 0) hash = -hash; hash %= slope_size; if (can_insert(&heads[hash], i, j)) { struct point_node *pn = malloc(sizeof(*pn)); pn->p1 = i; pn->p2 = j; EXP9; } } } } ``` Line 3 to 7 counts the number of points in a vertical line and horizontal line for a given point. For example, if `hori_cnts[1]` is 5, that means `points[1]` is in a horizontal line consist of other 5 points and itself. Line 9 and 10 counts the number of duplicated points for a given point. For example, if `dup_cnts[2]` is `2`, that means there are 2 other identical points. Line 12 to 28 uses different slope as hash and put the points into the hash. Therefore, ==EXP9 is `list_add(pn, &heads[hash])`== In line 22, we first check if we can insert the pair. ```c static bool can_insert(struct list_head *head, int p1, int p2) { struct point_node *pn; list_for_each_entry (pn, head, link) return EXP8; return true; } ``` To deduct EXP8, consider the following example. ![](https://i.imgur.com/NaF01fB.png) The traverse order is <`points[1]`, `points[2]`> $\to$ <`points[1]`, `points[3]`> $\to$ <`points[1]`, `points[4]`> $\to$,<`points[2]`, `points[3]`> $\to$<`points[2]`, `points[4]`> $\to$ <`points[3], points[4]`>. To count the correct number of points in the line, we need each pair consist of the point with the smallest index(because of the traverse order). Therefore, we check if we can insert by ==EXP8: `p1 == pn->p1`==. ## Problem 7 If `v > 0`, then `ret` must be greater or equal to 1. Check if any of the 32 more significant bits are set. If so, then `ret` must be greater then 32. Set `v` as the remaining 32 bits. ```c int ilog32(uint32_t v) { int ret = v > 0; int m = (v > 0xFFFFU) << 4; v >>= m; ret |= m; ``` Check if any of the 16 more significant bits are set. If so, then `ret` must be greater then 16. Set `v` as the remaining 16 bits. Repeat the same process for 8,4,2 more significant bits. Therefore, ==EXP10 is `(v > 0x3) << 1`== ```c m = (v > 0xFFU) << 3; v >>= m; ret |= m; m = (v > 0xFU) << 2; v >>= m; ret |= m; m = EXP10; v >>= m; ret |= m; ``` `v` then becomes 01~2~, 10~2~,or 11~2~ We will need one more bit if `v > 1`, therefore, ==EXP11 is `ret += v > 1`== ```c EXP11; return ret; } ``` ## Problem 8 ```graphviz digraph { compound = true subgraph cluster0{ label = tnode style = filled color = gray90 node0[shape = record, label ="data|<l>left|<r>right"] } subgraph cluster1{ label = tnode style = filled color = gray90 node1[shape = record, label ="{data}|<l>left|<r>right"] } subgraph cluster2{ label = tnode style = filled color = gray90 node2[shape = record, label ="data|<l>left|<r>right"] } subgraph cluster3{ label = tnode style = filled color = gray90 node3[shape = record, label ="data|<l>left|<r>right"] } subgraph cluster4{ label = tnode style = filled color = gray90 node4[shape = record, label ="data|<l>left|<r>right"] } node0:l->node1[lhead = cluster1] node0:r->node2[lhead = cluster2] node1:l->node3[lhead = cluster3] node1:r->node4[lhead = cluster4] } ``` Use the technique of indirect pointer. ```c void remove_data(tree &t, int d) { tnode **p = &t; while (*p != 0 && (*p)->data != d) { if (d < (*p)->data) EXP12; else EXP13; } ``` Traverse to left or right child according to current value. ==EXP12: `p = &(*p)->left`== ==EXP13: `p = &(*p)->right`== ```graphviz digraph { compound = true subgraph cluster0{ label = tnode style = filled color = gray90 node0[shape = record, label ="data|<l>left|<r>right"] } subgraph cluster1{ label = tnode style = filled color = gray90 node1[shape = record, label ="{data}|<l>left|<r>right"] } subgraph cluster2{ label = tnode style = filled color = gray90 node2[shape = record, label ="data|<l>left|<r>right"] } subgraph cluster3{ label = tnode style = filled color = gray90 node3[shape = record, label ="data|<l>left|<r>right"] } subgraph cluster4{ label = tnode style = filled color = pink node4[shape = record, label ="data = d|<l>left|<r>right"] } lsubtree[label = "left subtree", shape = triangle] rsubtree[label = "right subtree", shape = triangle] node0:l->node1[lhead = cluster1] node0:r->node2[lhead = cluster2] node1:l->node3[lhead = cluster3] node1:r->node4[lhead = cluster4] node4:l->lsubtree node4:r->rsubtree } ``` For a binary tree, after removing the target, move the smallest child element in the right subtree to target, or move the largest element in the left subtree to target. In the following code, we move the smallest child element in the right subtree to target. ```c tnode *q = *p; if (!q) return; if (!q->left) *p = q->right; else if (!q->right) *p = q->left; else { tnode **r = &q->right; while ((*r)->left) r = EXP14; q->data = (*r)->data; q = *r; *r = q->right; } delete q; } ``` Therefore, ==EXP14 is `r = &(*r)->left`== ## Problem 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 - MMM) & ~(NNN)) ``` Using the fact that $\lceil\frac{a}{b}\rceil =\lfloor\frac{a}{b}+\frac{b-1}{b}\rfloor$ x round up to 16 $= \lceil\frac{x}{16}\rceil *16=\lfloor\frac{x+15}{16}\rfloor *16$ Therefore, ==MMM is `1`, NNN is `MAX_ALIGNMENT-1`== ## Problem 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)); \ }) ``` $round(\frac{a}{b})=\lfloor\frac{a+\frac{b}{2}}{b}\rfloor$ If 1. x or divisor is unsigned 2. x and divisor is both positive or negetive then return `(__x)+(__d)>>1` otherwise, return `-(__x)+(__d)>>1` Therefore, ==RRR is `(__x)+(__d)>>1`, SSS is `-(__x)+(__d)>>1`==. ## Problem 11 `fls()` returns the position of the most significant bit. 1. Set the current value to 63, the greatest possible number. 2. If all of the 32 more significant bit is 0, the reult is 32 less than the current number. 3. Repeat step 2. for 16, 8, 4, 2, 1, return the final number. ```c static inline unsigned long fls(unsigned long word) { int num = 64 - 1; if (!(word & (~0ul << 32))) { num -= 32; word <<= 32; } if (!(word & (~0ul << (64 - 16)))) { num -= 16; word <<= 16; } if (!(word & (~0ul << (64 - 8)))) { num -= 8; word <<= 8; } if (!(word & (~0ul << (64 - 4)))) { num -= 4; word <<= 4; } if (!(word & (~0ul << (64 - 2)))) { num -= 2; word <<= 2; } if (!(word & (~0ul << (64 - 1)))) num -= 1; return num; } ``` The following code is used fore calculating $\lfloor\sqrt{x}\rfloor$ ```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; XXX; if (x >= b) { YYY; y += m; } ZZZ; } return y; } ``` To understand how the code works, we need to know how to calculate the square root of a binary number. [source](https://www.cantorsparadise.com/the-square-root-algorithm-f97ab5c29d6d) ![](https://i.imgur.com/5FYjtKQ.png) 1. We calculate the answer every two digits. 2. `y` corresponds the leftmost column. 3. `m = 1UL << (fls(x) & ~1UL);` the return value of fls() is rounded down to even number. For the above example, $x = 169_10 = 10101001_2$, $fls(x) = 7$, $m = 1000000_2$ `y` of the next iteration is equal to `(y+m)>>1` if `x > y + m`. Therefore,==XXX is `y >>= 1`, YYY is `x -= b`, ZZZ is `m >>= 2`==.