[LLVMdev] optimizer clobber EFLAGS (original) (raw)

Michael Hordijk hoffbrinkle at hotmail.com
Wed Jul 29 15:11:28 PDT 2015


Using Clang/LLVM 3.6.0 we are observing a case where the optimizations are clobbering EFLAGS on x86_64. This is inconvenient when the status of bit 9 (IF), which controls interrupts, changes.

Here's a simple test program. Assume that the external function foo() modifies the IF bit in EFLAGS.


#include <stdlib.h> #include <stdbool.h>

void foo(void); int a;

int bar(void) { foo();

     bool const zero = a -= 1;

     asm volatile ("" : : : "cc");
     foo();

     if (zero) {
             return EXIT_FAILURE;
     }

     foo();

     return EXIT_SUCCESS;

}


And it's compiled using the following command line:


$ clang -O2 -c -o clang-eflag.o clang-eflag.c


Produces this output:


$ objdump -S clang-eflag.o

clang-eflag.o: file format elf64-x86-64

Disassembly of section .text:

0000000000000000 : 0: 53 push %rbx 1: e8 00 00 00 00 callq 6 <bar+0x6> 6: ff 0d 00 00 00 00 decl 0x0(%rip) # c <bar+0xc> c: 9c pushfq d: 5b pop %rbx e: e8 00 00 00 00 callq 13 <bar+0x13> 13: b8 01 00 00 00 mov $0x1,%eax 18: 53 push %rbx 19: 9d popfq 1a: 75 07 jne 23 <bar+0x23> 1c: e8 00 00 00 00 callq 21 <bar+0x21> 21: 31 c0 xor %eax,%eax 23: 5b pop %rbx 24: c3 retq


The critical bits here are that at 0xc/0xd, we save the value of EFLAGS into %rbx. We then call foo() (which changes bit 9 of EFLAGS). We then 0x18/0x19 reload EFLAGS from the stale value in %rbx thus clobbering the value of bit 9 leaving interrupts in an unexpected state.

You may notice that I've tried the asm volatile ("" : : : "cc") constraint. The LLVM IR has the what appears to be an appropriate inline ASM directive:


entry: tail call void @foo() #2 %0 = load i32* @a, align 4, !tbaa !1 %sub = add nsw i32 %0, -1 store i32 %sub, i32* @a, align 4, !tbaa !1 %tobool = icmp eq i32 %sub, 0 tail call void asm sideeffect "", "{cc},{dirflag},{fpsr},{flags}"() #2, !srcloc !5 tail call void @foo() #2 br i1 %tobool, label %if.end, label %return

if.end: ; preds = %entry tail call void @foo() #2 br label %return

return: ; preds = %entry, %if.end %retval.0 = phi i32 [ 0, %if.end ], [ 1, %entry ] ret i32 %retval.0


The constraint doesn't appear to do anything which is not totally surprising. I'm thinking that the "cc" constraint tells the optimizer that "EFLAGS has been clobbered". What we need is a way to tell the optimizer that "EFLAGS has been clobbered and the new value in EFLAGS needs to be preserved (so don't clobber it)."



More information about the llvm-dev mailing list