# 2023q1 Homework2 (quiz2)
[quiz2](https://hackmd.io/@sysprog/linux2023-quiz2)
## 測驗 1
### 解釋上述程式碼原理
假設輸入 `x`
```graphviz
digraph structs {
node [shape=record];
struct1 [label="0|...|0|1|x|...|x"];
}
```
目標是把 `x` 最高位元的 set 之後的位元都轉為 set
```graphviz
digraph structs {
node [shape=record];
struct1 [label="0|...|0|1|1|...|1"];
}
```
最後返回 `x + 1`
```graphviz
digraph structs {
node [shape=record];
struct1 [label="0|...|1|0|0|...|0"];
}
```
輸入 `x` 執行一次 `x |= x >> 1;` 後, 便把最高位元的 set 之後 1 個位元轉為 set
```graphviz
digraph structs {
node [shape=record];
struct1 [label="0|...|0|1|1|x|...|x"];
}
```
執行 7 次後, 把最高位元的 set 之後 7 個位元轉為 set
```graphviz
digraph structs {
node [shape=record];
struct1 [label="0|...|0|1|1|1|1|1|1|1|1|x|...|x"];
}
```
執行 `x |= x >> 8;` 後, 把最高位元的 set 之後 7 + 8 個位元轉為 set。如此類推, 共把最高位元的 set 之後 7 + 8 + 16 + 32 = 63 個位元轉為 set。
所以此算法能把 64 bit 寬的無號整數 `x` 最高位元 set 之後的位元都轉為 set。
### 用 __builtin_clzl 改寫
```c
uint64_t next_pow2(uint64_t x) {
int clz = __builtin_clz(x);
return 1 << (64 - clz);
}
```
### 當上述 clz 內建函式已運用時,編譯器能否產生對應的 x86 指令?
找到 bsr 指令如下:
```shell
XPS:~/linux2023/quiz2$ cat 1.s | grep -n5 bsr
47- .type next_pow2, @function
48-next_pow2:
49-.LFB14:
50- .cfi_startproc
51- endbr64
52: bsrl %edi, %edi
53- movl $64, %ecx
54- movl $1, %eax
55- xorl $31, %edi
56- subl %edi, %ecx
57- sall %cl, %eax
```
## 測驗 3
### 解釋上述程式碼運作原理
觀察 UTF-8 位元組字元規則後, 目標是找出共有多少個後續位元組 (continuation byte(s)), 然後輸出總長度減去後續位元組的數量。
#### 找出 continuation byte 的方法
只觀察 bit7 和 bit6 共有以下可能組合: `B0`
```graphviz
digraph structs {
node [shape=record]
struct1 [label="0|0|x...x"]
struct2 [label="0|1|x...x"]
subgraph cluster_c {
label="continuation byte"
struct3 [label="1|0|x...x"]
}
struct4 [label="1|1|x...x"]
}
```
反向運算 (not bit6): `B1 = ~B0`
```graphviz
digraph structs {
node [shape=record]
struct1 [label="1|1|x...x"]
struct2 [label="1|0|x...x"]
subgraph cluster_c {
label="continuation byte"
struct3 [label="0|1|x...x"]
}
struct4 [label="0|0|x...x"]
}
```
隔離反向的第 6 個位元: `B2 = B1 & 0x40`
```graphviz
digraph structs {
node [shape=record]
struct1 [label="0|1|0...0"]
struct2 [label="0|0|0...0"]
subgraph cluster_c {
label="continuation byte"
struct3 [label="0|1|0...0"]
}
struct4 [label="0|0|0...0"]
}
```
對第 6 個位元,向左位移 1 個位元 (移至第 7 個位元的位置): `B3 = B2 + B2`
```graphviz
digraph structs {
node [shape=record]
struct1 [label="1|0|0...0"]
struct2 [label="0|0|0...0"]
subgraph cluster_c {
label="continuation byte"
struct3 [label="1|0|0...0"]
}
struct4 [label="0|0|0...0"]
}
```
進行 not bit6, and bit7: `B4 = B0 & B3`
```graphviz
digraph structs {
node [shape=record]
struct1 [label="0|0|0...0"]
struct2 [label="0|0|0...0"]
subgraph cluster_c {
label="continuation byte"
struct3 [label="1|0|0...0"]
}
struct4 [label="0|0|0...0"]
}
```
最後只剩下 continuation byte 的 population count 為 1, 其餘為 0。
#### 結合 SWAR 運用於 64 位元微處理器架構
程式碼以 8 個位元組為一組進行上述 bitwise 操作, 並以 `__builtin_popcountll` 得到 population count, 累加算出共有多少 continuation byte。
### 比較 SWAR 和原本的實作效能落差
## 測驗 4
```c
bool is_pattern(uint16_t x)
{
const uint16_t n = ~x + 1;
return (n ^ x) < x;
}
```
### 解釋上述程式碼運作原理
#### 符合 pattern 的 `x` 模樣
```graphviz
digraph structs {
node [shape=record];
struct1 [label="1|...|1|0|...|0"];
}
```
`~x`
```graphviz
digraph structs {
node [shape=record];
struct1 [label="0|...|0|1|...|1"];
}
```
`n = ~x + 1`
```graphviz
digraph structs {
node [shape=record];
clear [shape=none,label="進位"]
clear -> struct1:f1
struct1 [label="0|...|<f1>1|0|...|0"];
}
```
`n ^ x`
```graphviz
digraph structs {
node [shape=record]
clear [shape=none]
clear -> struct1:f1
struct1 [label="1|...|<f1>0|0|...|0"];
}
```
`(n ^ x) < x` 為 Ture
#### 不符合 pattern 的 `x` 模樣
```graphviz
digraph structs {
node [shape=record];
struct1 [label="1|...|1|0|...|1|..."];
}
```
`~x`
```graphviz
digraph structs {
node [shape=record];
struct1 [label="0|...|0|1|...|0|..."];
}
```
`n = ~x + 1`
```graphviz
digraph structs {
node [shape=record];
clear [shape=none,label="進位或 set"]
clear -> struct1:f1
struct1 [label="0|...|0|1|...|<f1>1|..."];
}
```
`n ^ x`
```graphviz
digraph structs {
node [shape=record]
clear [shape=none]
clear -> struct1:f1
set [shape=none]
set -> struct1:f2
struct1 [label="1|...|1|<f2>1|...|<f1>0|..."];
}
```
`(n ^ x) < x` 為 False