From the command line it is possible to tell clang to disable use of some features, for example -mno-mmx
or -mno-popcnt
. However, while cmov
is a feature tracked by llvm, there is no -mno-cmov
for x86 processors (although you can disable conditional moves for other processor targets).
As a work around, I can directly tell the llvm component to not include "cmov" in the list of processor features. But, and maybe this is a bug or I am doing something wrong, even turning off this feature it still generates cmov instructions.
How do I get clang/llvm to not generate cmov instructions?
(In my particular use case, keeping conditionals as branches is useful for automated coverage tracking analysis, and -O0
is very harsh and possibly still not guaranteed to prevent this if the code uses ternary operators.)
Here is a code example with some tests
file:a.c
void report(char *);
int foo(int x)
{
if (x==1) {
report("x is one");
}
else {
report("x is not one");
}
return 1;
}
console snippet showing normal compiling
$ 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
console snippet showing emitting as llvm with cmov target-feature turned off
then compiling llvm -> machine instructions
$ 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
...