clang 的asm goto是从gcc而来的,它意在实现从inline asm 内部 跳转 到inline asm 外部label的功能。
用例
1 int test1(int cond) {
2 asm volatile goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop);
// ^0: cond ^ 1: label_true ^ 注意 多了个 “:”
// asm.fallthrough:
3 return 0;
4 loop:
5 return 1;
6 label_true:
7 return 2;
8 }
9
10 int main(){
11 int ret = test1(1);
12 return ret;
13 }
上面的例子(行2) 实际上是实现 从inline asm内部jump到 label_true(或fallthrough)的功能。
注意
asm goto 与普通的inline asm相比,主要多了一个“:”。所以
asm goto其实就是在outputs,inputs,registers-modified之外提供了嵌入式汇编的第4个“:”,后面可以跟一系列的c语言的label,然后你可以在嵌入式汇编中go to到这些label中一个。
IR
生成的IR如下:
在IR中 callbr 实现且仅用于实现 asm goto
clang -target x86_64-pc-linux-gnu -O0 -emit-llvm -S
7 define dso_local i32 @test1(i32 noundef %cond) #0 {
8 entry:
9 %retval = alloca i32, align 4
10 %cond.addr = alloca i32, align 4
11 store i32 %cond, i32* %cond.addr, align 4
12 %0 = load i32, i32* %cond.addr, align 4
13 callbr void asm sideeffect "testl $0, $0; jne ${1:l};",
"r,!i,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) #1
14 to label %asm.fallthrough [label %label_true, label %loop], !srcloc !4
15
16 asm.fallthrough: ; preds = %entry
17 store i32 0, i32* %retval, align 4
18 br label %return
19
20 loop: ; preds = %entry
21 store i32 1, i32* %retval, align 4
22 br label %return
23
24 label_true: ; preds = %entry
25 store i32 2, i32* %retval, align 4
26 br label %return
27
28 return: ; preds = %label_true, %loop, %asm.fallthrough
29 %1 = load i32, i32* %retval, align 4
30 ret i32 %1
31 }
clang -target x86_64-pc-linux-gnu -O2 -emit-llvm -S
由于loop不会被jump到,所以应该可以被优化,但实际-O2 也没有优化掉:
(不过这是个很好的 PHI多入口例子,见IR 行19)
7 define dso_local i32 @test1(i32 noundef %cond) local_unnamed_addr #0 {
8 entry:
9 callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,!i,!i,~{dirflag},~{fpsr},~{flags}"(i32 %cond) #1
10 to label %return [label %label_true, label %loop], !srcloc !3
11
12 loop: ; preds = %entry
13 br label %return
14
15 label_true: ; preds = %entry
16 br label %return
17
18 return: ; preds = %entry, %label_true, %loop
19 %retval.0 = phi i32 [ 1, %loop ], [ 2, %label_true ], [ 0, %entry ]
20 ret i32 %retval.0
21 }
汇编
生成的汇编如下,由于代码不多,我们直接用 O0 生成汇编
clang -target x86_64-pc-linux-gnu -O0 -S
6 test1: # @test1
7 .cfi_startproc
8 # %bb.0: # %entry
9 pushq %rbp
10 .cfi_def_cfa_offset 16
11 .cfi_offset %rbp, -16
12 movq %rsp, %rbp
13 .cfi_def_cfa_register %rbp
14 movl %edi, -8(%rbp)
15 movl -8(%rbp), %eax
16 #APP
17 testl %eax, %eax
18 jne .Ltmp0
19
20 #NO_APP
21 jmp .LBB0_1
22 .LBB0_1: # %asm.fallthrough
23 movl $0, -4(%rbp)
24 jmp .LBB0_4
25 .Ltmp1: # Block address taken
26 .LBB0_2: # %loop
27 movl $1, -4(%rbp)
28 jmp .LBB0_4
29 .Ltmp0: # Block address taken
30 .LBB0_3: # %label_true
31 movl $2, -4(%rbp)
32 .LBB0_4: # %return
33 movl -4(%rbp), %eax
34 popq %rbp
35 .cfi_def_cfa %rsp, 8
36 retq
完 : )