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 <bar>:
    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)."
- michael
I remember this bug. :) IMO, LLVM should never emit pushf / popf. I'm not sure this patch to fix it ever got committed: http://reviews.llvm.org/D6629 On Wed, Jul 29, 2015 at 3:11 PM, Michael Hordijk <hoffbrinkle at hotmail.com> wrote:> > 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 <bar>: > 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)." > > - michael > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150729/9c60bdb1/attachment.html>
Agreed, never emit pushf/popf. Sorry I never committed the patch, the cmov issue got hairy and I never got to debugging it :-) I can get back to it if there's interest! On Wed, Jul 29, 2015 at 4:12 PM, Reid Kleckner <rnk at google.com> wrote:> I remember this bug. :) IMO, LLVM should never emit pushf / popf. I'm not > sure this patch to fix it ever got committed: > http://reviews.llvm.org/D6629 > > > On Wed, Jul 29, 2015 at 3:11 PM, Michael Hordijk <hoffbrinkle at hotmail.com> > wrote: > >> >> 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 <bar>: >> 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)." >> >> - michael >> >> _______________________________________________ >> LLVM Developers mailing list >> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >> > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150729/6d9ef706/attachment.html>