从命令行可以告诉 clang 禁用某些功能,例如-mno-mmx
或-mno-popcnt
. 但是,虽然cmov
是 llvm 跟踪的功能,但-mno-cmov
x86 处理器没有(尽管您可以禁用其他处理器目标的条件移动)。
作为一种解决方法,我可以直接告诉 llvm 组件不要在处理器功能列表中包含“cmov”。但是,也许这是一个错误或者我做错了什么,即使关闭此功能它仍然会生成 cmov 指令。
如何让 clang/llvm 不生成 cmov 指令?
(在我的特定用例中,将条件保留为分支对于自动覆盖跟踪分析很有用,并且-O0
非常苛刻,如果代码使用三元运算符,可能仍不能保证防止这种情况发生。)
这是一个带有一些测试的代码示例
文件:ac
void report(char *);
int foo(int x)
{
if (x==1) {
report("x is one");
}
else {
report("x is not one");
}
return 1;
}
显示正常编译的控制台片段
$ clang-10 --version
clang version 10.0.0-4ubuntu1~18.04.1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ clang-10 -O2 -c a.c
$ objdump -M intel -d a.o
...
0000000000000000 <foo>:
0: 50 push rax
1: 83 ff 01 cmp edi,0x1
4: b8 00 00 00 00 mov eax,0x0
9: bf 00 00 00 00 mov edi,0x0
e: 48 0f 44 f8 cmove rdi,rax
12: e8 00 00 00 00 call 17 <foo+0x17>
17: b8 01 00 00 00 mov eax,0x1
1c: 59 pop rcx
1d: c3 ret
控制台片段显示作为 llvm 发出,并关闭 cmov 目标功能,
然后编译 llvm -> 机器指令
$ clang-10 -O2 -Xclang -target-feature -Xclang -cmov -S -emit-llvm a.c
$ cat a.ll
...
define dso_local i32 @foo(i32 %0) local_unnamed_addr #0 {
%2 = icmp eq i32 %0, 1
%3 = select i1 %2,
i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str, i64 0, i64 0),
i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.1, i64 0, i64 0)
call void @report(i8* %3) #2
ret i32 1
}
...
attributes #0 = {
...
"target-cpu"="x86-64"
"target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87,-cmov"
"unsafe-fp-math"="false"
"use-soft-float"="false"
}
...
$ llc-10 --x86-asm-syntax=intel a.ll
$ cat a.s
...
foo: # @foo
.cfi_startproc
# %bb.0:
push rax
.cfi_def_cfa_offset 16
cmp edi, 1
mov eax, offset .L.str
mov edi, offset .L.str.1
cmove rdi, rax
call report
mov eax, 1
pop rcx
.cfi_def_cfa_offset 8
ret
...