disable use of cmov in clang

547 views Asked by At

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
...
0

There are 0 answers