[llvm] r256685 - [X86] Add intrinsics for reading and writing to the flags register

David Majnemer via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 31 22:50:03 PST 2015


Author: majnemer
Date: Fri Jan  1 00:50:01 2016
New Revision: 256685

URL: http://llvm.org/viewvc/llvm-project?rev=256685&view=rev
Log:
[X86] Add intrinsics for reading and writing to the flags register

LLVM's targets need to know if stack pointer adjustments occur after the
prologue.  This is needed to correctly determine if the red-zone is
appropriate to use or if a frame pointer is required.

Normally, LLVM can figure this out very precisely by reasoning about the
contents of the MachineFunction.  There is an interesting corner case:
inline assembly.

The vast majority of inline assembly which will perform a push or pop is
done so to pair up with pushf or popf as appropriate.  Unfortunately,
this inline assembly doesn't mark the stack pointer as clobbered
because, well, it isn't.  The stack pointer is decremented and then
immediately incremented.  Because of this, LLVM was changed in r256456
to conservatively assume that inline assembly contain a sequence of
stack operations.  This is unfortunate because the vast majority of
inline assembly will not end up manipulating the stack pointer in any
way at all.

Instead, let's provide a more principled solution: an intrinsic.
FWIW, other compilers (MSVC and GCC among them) also provide this
functionality as an intrinsic.

Added:
    llvm/trunk/test/CodeGen/X86/x86-64-flags-intrinsics.ll
    llvm/trunk/test/CodeGen/X86/x86-flags-intrinsics.ll
Modified:
    llvm/trunk/include/llvm/IR/IntrinsicsX86.td
    llvm/trunk/lib/Target/X86/X86FrameLowering.cpp
    llvm/trunk/lib/Target/X86/X86ISelLowering.cpp
    llvm/trunk/lib/Target/X86/X86InstrInfo.td
    llvm/trunk/test/CodeGen/X86/2009-06-03-Win64SpillXMM.ll
    llvm/trunk/test/CodeGen/X86/inline-sse.ll
    llvm/trunk/test/CodeGen/X86/pr11415.ll
    llvm/trunk/test/CodeGen/X86/win64_frame.ll
    llvm/trunk/test/CodeGen/X86/x86-win64-shrink-wrapping.ll
    llvm/trunk/test/DebugInfo/COFF/asm.ll

Modified: llvm/trunk/include/llvm/IR/IntrinsicsX86.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/IntrinsicsX86.td?rev=256685&r1=256684&r2=256685&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/IntrinsicsX86.td (original)
+++ llvm/trunk/include/llvm/IR/IntrinsicsX86.td Fri Jan  1 00:50:01 2016
@@ -33,6 +33,19 @@ let TargetPrefix = "x86" in {
 }
 
 //===----------------------------------------------------------------------===//
+// FLAGS.
+let TargetPrefix = "x86" in {
+  def int_x86_flags_read_u32 : GCCBuiltin<"__builtin_ia32_readeflags_u32">,
+        Intrinsic<[llvm_i32_ty], [], []>;
+  def int_x86_flags_read_u64 : GCCBuiltin<"__builtin_ia32_readeflags_u64">,
+        Intrinsic<[llvm_i64_ty], [], []>;
+  def int_x86_flags_write_u32 : GCCBuiltin<"__builtin_ia32_writeeflags_u32">,
+        Intrinsic<[], [llvm_i32_ty], []>;
+  def int_x86_flags_write_u64 : GCCBuiltin<"__builtin_ia32_writeeflags_u64">,
+        Intrinsic<[], [llvm_i64_ty], []>;
+}
+
+//===----------------------------------------------------------------------===//
 // Read Time Stamp Counter.
 let TargetPrefix = "x86" in {
   def int_x86_rdtsc : GCCBuiltin<"__builtin_ia32_rdtsc">,

Modified: llvm/trunk/lib/Target/X86/X86FrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86FrameLowering.cpp?rev=256685&r1=256684&r2=256685&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86FrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86FrameLowering.cpp Fri Jan  1 00:50:01 2016
@@ -86,10 +86,6 @@ X86FrameLowering::needsFrameIndexResolut
 static bool usesTheStack(const MachineFunction &MF) {
   const MachineRegisterInfo &MRI = MF.getRegInfo();
 
-  // Conservativley assume that inline assembly might use the stack.
-  if (MF.hasInlineAsm())
-    return true;
-
   return any_of(MRI.reg_instructions(X86::EFLAGS),
                 [](const MachineInstr &RI) { return RI.isCopy(); });
 }

Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=256685&r1=256684&r2=256685&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Fri Jan  1 00:50:01 2016
@@ -22537,6 +22537,40 @@ X86TargetLowering::EmitInstrWithCustomIn
   case X86::CMOV_V64I1:
     return EmitLoweredSelect(MI, BB);
 
+  case X86::RDFLAGS32:
+  case X86::RDFLAGS64: {
+    DebugLoc DL = MI->getDebugLoc();
+    MachineFunction *MF = BB->getParent();
+    MF->getFrameInfo()->setHasOpaqueSPAdjustment(true);
+    const TargetInstrInfo *TII = Subtarget->getInstrInfo();
+    unsigned PushF =
+        MI->getOpcode() == X86::RDFLAGS32 ? X86::PUSHF32 : X86::PUSHF64;
+    unsigned Pop =
+        MI->getOpcode() == X86::RDFLAGS32 ? X86::POP32r : X86::POP64r;
+    BuildMI(*BB, MI, DL, TII->get(PushF));
+    BuildMI(*BB, MI, DL, TII->get(Pop), MI->getOperand(0).getReg());
+
+    MI->eraseFromParent(); // The pseudo is gone now.
+    return BB;
+  }
+
+  case X86::WRFLAGS32:
+  case X86::WRFLAGS64: {
+    DebugLoc DL = MI->getDebugLoc();
+    MachineFunction *MF = BB->getParent();
+    MF->getFrameInfo()->setHasOpaqueSPAdjustment(true);
+    const TargetInstrInfo *TII = Subtarget->getInstrInfo();
+    unsigned Push =
+        MI->getOpcode() == X86::WRFLAGS32 ? X86::PUSH32r : X86::PUSH64r;
+    unsigned PopF =
+        MI->getOpcode() == X86::WRFLAGS32 ? X86::POPF32 : X86::POPF64;
+    BuildMI(*BB, MI, DL, TII->get(Push)).addReg(MI->getOperand(0).getReg());
+    BuildMI(*BB, MI, DL, TII->get(PopF));
+
+    MI->eraseFromParent(); // The pseudo is gone now.
+    return BB;
+  }
+
   case X86::RELEASE_FADD32mr:
   case X86::RELEASE_FADD64mr:
     return EmitLoweredAtomicFP(MI, BB);

Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrInfo.td?rev=256685&r1=256684&r2=256685&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86InstrInfo.td (original)
+++ llvm/trunk/lib/Target/X86/X86InstrInfo.td Fri Jan  1 00:50:01 2016
@@ -1093,6 +1093,32 @@ def PUSH32rmm: I<0xFF, MRM6m, (outs), (i
 
 }
 
+let mayLoad = 1, mayStore = 1, usesCustomInserter = 1,
+    SchedRW = [WriteRMW], Defs = [ESP] in {
+  let Uses = [ESP, EFLAGS] in
+  def RDFLAGS32 : PseudoI<(outs GR32:$dst), (ins),
+                   [(set GR32:$dst, (int_x86_flags_read_u32))]>,
+                Requires<[Not64BitMode]>;
+
+  let Uses = [RSP, EFLAGS] in
+  def RDFLAGS64 : PseudoI<(outs GR64:$dst), (ins),
+                   [(set GR64:$dst, (int_x86_flags_read_u64))]>,
+                Requires<[In64BitMode]>;
+}
+
+let mayLoad = 1, mayStore = 1, usesCustomInserter = 1,
+    SchedRW = [WriteRMW] in {
+  let Defs = [ESP, EFLAGS], Uses = [ESP] in
+  def WRFLAGS32 : PseudoI<(outs), (ins GR32:$src),
+                   [(int_x86_flags_write_u32 GR32:$src)]>,
+                Requires<[Not64BitMode]>;
+
+  let Defs = [RSP, EFLAGS], Uses = [RSP] in
+  def WRFLAGS64 : PseudoI<(outs), (ins GR64:$src),
+                   [(int_x86_flags_write_u64 GR64:$src)]>,
+                Requires<[In64BitMode]>;
+}
+
 let Defs = [ESP, EFLAGS], Uses = [ESP], mayLoad = 1, hasSideEffects=0,
     SchedRW = [WriteLoad] in {
 def POPF16   : I<0x9D, RawFrm, (outs), (ins), "popf{w}", [], IIC_POP_F>,

Modified: llvm/trunk/test/CodeGen/X86/2009-06-03-Win64SpillXMM.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/2009-06-03-Win64SpillXMM.ll?rev=256685&r1=256684&r2=256685&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/2009-06-03-Win64SpillXMM.ll (original)
+++ llvm/trunk/test/CodeGen/X86/2009-06-03-Win64SpillXMM.ll Fri Jan  1 00:50:01 2016
@@ -1,9 +1,7 @@
 ; RUN: llc -mcpu=generic -mtriple=x86_64-mingw32 < %s | FileCheck %s
-; CHECK: pushq   %rbp
-; CHECK: subq    $32, %rsp
-; CHECK: leaq    32(%rsp), %rbp
-; CHECK: movaps  %xmm8, -16(%rbp)
-; CHECK: movaps  %xmm7, -32(%rbp)
+; CHECK: subq    $40, %rsp
+; CHECK: movaps  %xmm8, 16(%rsp)
+; CHECK: movaps  %xmm7, (%rsp)
 
 define i32 @a() nounwind {
 entry:

Modified: llvm/trunk/test/CodeGen/X86/inline-sse.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/inline-sse.ll?rev=256685&r1=256684&r2=256685&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/inline-sse.ll (original)
+++ llvm/trunk/test/CodeGen/X86/inline-sse.ll Fri Jan  1 00:50:01 2016
@@ -21,11 +21,9 @@ define void @nop() nounwind {
 ;
 ; X64-LABEL: nop:
 ; X64:       # BB#0:
-; X64-NEXT:    subq    $24, %rsp
 ; X64-NEXT:    #APP
 ; X64-NEXT:    #NO_APP
-; X64-NEXT:    movaps %xmm0, (%rsp)
-; X64-NEXT:    addq    $24, %rsp
+; X64-NEXT:    movaps %xmm0, -{{[0-9]+}}(%rsp)
 ; X64-NEXT:    retq
   %1 = alloca <4 x float>, align 16
   %2 = call <4 x float> asm "", "=x,~{dirflag},~{fpsr},~{flags}"()

Modified: llvm/trunk/test/CodeGen/X86/pr11415.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/pr11415.ll?rev=256685&r1=256684&r2=256685&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/pr11415.ll (original)
+++ llvm/trunk/test/CodeGen/X86/pr11415.ll Fri Jan  1 00:50:01 2016
@@ -4,17 +4,15 @@
 ; defining %0 before it was read. This caused us to omit the
 ; movq	-8(%rsp), %rdx
 
-; CHECK: pushq	%rax
 ; CHECK: 	#APP
 ; CHECK-NEXT:	#NO_APP
 ; CHECK-NEXT:	movq	%rcx, %rax
-; CHECK-NEXT:	movq	%rax, (%rsp)
-; CHECK-NEXT:	movq	(%rsp), %rdx
+; CHECK-NEXT:	movq	%rax, -8(%rsp)
+; CHECK-NEXT:	movq	-8(%rsp), %rdx
 ; CHECK-NEXT:	#APP
 ; CHECK-NEXT:	#NO_APP
 ; CHECK-NEXT:	movq	%rdx, %rax
-; CHECK-NEXT:	movq	%rdx, (%rsp)
-; CHECK-NEXT:	popq	%rcx
+; CHECK-NEXT:	movq	%rdx, -8(%rsp)
 ; CHECK-NEXT:	ret
 
 define i64 @foo() {

Modified: llvm/trunk/test/CodeGen/X86/win64_frame.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/win64_frame.ll?rev=256685&r1=256684&r2=256685&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/win64_frame.ll (original)
+++ llvm/trunk/test/CodeGen/X86/win64_frame.ll Fri Jan  1 00:50:01 2016
@@ -128,11 +128,9 @@ entry:
   ; CHECK:      .seh_setframe 5, 0
   ; CHECK:      .seh_endprologue
 
-  %call = call i64 asm sideeffect "pushf\0A\09popq $0\0A", "=r,~{dirflag},~{fpsr},~{flags}"()
-  ; CHECK-NEXT: #APP
+  %call = call i64 @llvm.x86.flags.read.u64()
   ; CHECK-NEXT: pushfq
   ; CHECK-NEXT: popq    %rax
-  ; CHECK:      #NO_APP
 
   ret i64 %call
   ; CHECK-NEXT: popq    %rbp
@@ -187,5 +185,6 @@ define i64 @f10(i64* %foo, i64 %bar, i64
 }
 
 declare i8* @llvm.returnaddress(i32) nounwind readnone
+declare i64 @llvm.x86.flags.read.u64()
 
 declare void @llvm.va_start(i8*) nounwind

Added: llvm/trunk/test/CodeGen/X86/x86-64-flags-intrinsics.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/x86-64-flags-intrinsics.ll?rev=256685&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/X86/x86-64-flags-intrinsics.ll (added)
+++ llvm/trunk/test/CodeGen/X86/x86-64-flags-intrinsics.ll Fri Jan  1 00:50:01 2016
@@ -0,0 +1,37 @@
+; RUN: llc < %s | FileCheck %s
+target triple = "x86_64-pc-win32"
+
+declare i64 @llvm.x86.flags.read.u64()
+declare void @llvm.x86.flags.write.u64(i64)
+
+define i64 @read_flags() {
+entry:
+  %flags = call i64 @llvm.x86.flags.read.u64()
+  ret i64 %flags
+}
+
+; CHECK-LABEL: read_flags:
+; CHECK:      pushq   %rbp
+; CHECK:      .seh_pushreg 5
+; CHECK:      movq    %rsp, %rbp
+; CHECK:      .seh_setframe 5, 0
+; CHECK:      .seh_endprologue
+; CHECK-NEXT: pushfq
+; CHECK-NEXT: popq    %rax
+; CHECK-NEXT: popq    %rbp
+
+define void @write_flags(i64 %arg) {
+entry:
+  call void @llvm.x86.flags.write.u64(i64 %arg)
+  ret void
+}
+
+; CHECK-LABEL: write_flags:
+; CHECK:      pushq   %rbp
+; CHECK:      .seh_pushreg 5
+; CHECK:      movq    %rsp, %rbp
+; CHECK:      .seh_setframe 5, 0
+; CHECK:      .seh_endprologue
+; CHECK-NEXT: pushq   %rcx
+; CHECK-NEXT: popfq
+; CHECK-NEXT: popq    %rbp

Added: llvm/trunk/test/CodeGen/X86/x86-flags-intrinsics.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/x86-flags-intrinsics.ll?rev=256685&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/X86/x86-flags-intrinsics.ll (added)
+++ llvm/trunk/test/CodeGen/X86/x86-flags-intrinsics.ll Fri Jan  1 00:50:01 2016
@@ -0,0 +1,31 @@
+; RUN: llc < %s | FileCheck %s
+target triple = "i686-pc-win32"
+
+declare i32 @llvm.x86.flags.read.u32()
+declare void @llvm.x86.flags.write.u32(i32)
+
+define i32 @read_flags() {
+entry:
+  %flags = call i32 @llvm.x86.flags.read.u32()
+  ret i32 %flags
+}
+
+; CHECK-LABEL: _read_flags:
+; CHECK:      pushl   %ebp
+; CHECK-NEXT: movl    %esp, %ebp
+; CHECK-NEXT: pushfl
+; CHECK-NEXT: popl    %eax
+; CHECK-NEXT: popl    %ebp
+
+define x86_fastcallcc void @write_flags(i32 inreg %arg) {
+entry:
+  call void @llvm.x86.flags.write.u32(i32 %arg)
+  ret void
+}
+
+; CHECK-LABEL: @write_flags at 4:
+; CHECK:      pushl   %ebp
+; CHECK-NEXT: movl    %esp, %ebp
+; CHECK-NEXT: pushl   %ecx
+; CHECK-NEXT: popfl
+; CHECK-NEXT: popl    %ebp

Modified: llvm/trunk/test/CodeGen/X86/x86-win64-shrink-wrapping.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/x86-win64-shrink-wrapping.ll?rev=256685&r1=256684&r2=256685&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/x86-win64-shrink-wrapping.ll (original)
+++ llvm/trunk/test/CodeGen/X86/x86-win64-shrink-wrapping.ll Fri Jan  1 00:50:01 2016
@@ -11,10 +11,8 @@ target triple = "x86_64--windows-gnu"
 ; etc.) prior to the return and this is forbidden for Win64.
 ; CHECK-LABEL: loopInfoSaveOutsideLoop:
 ; CHECK: push
-; CHECK: push
 ; CHECK-NOT: popq
 ; CHECK: popq
-; CHECK: popq
 ; CHECK-NOT: popq
 ; CHECK-NEXT: retq
 define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) #0 {
@@ -57,7 +55,6 @@ if.end:
 ;
 ; Prologue code.
 ; Make sure we save the CSR used in the inline asm: rbx.
-; CHECK: pushq %rbp
 ; CHECK: pushq %rbx
 ;
 ; DISABLE: testl %ecx, %ecx
@@ -79,7 +76,6 @@ if.end:
 ; DISABLE: jmp [[EPILOG_BB:.LBB[0-9_]+]]
 ;
 ; ENABLE-NEXT: popq %rbx
-; ENABLE-NEXT: popq %rbp
 ; ENABLE-NEXT: retq
 ;
 ; CHECK: [[ELSE_LABEL]]: # %if.else

Modified: llvm/trunk/test/DebugInfo/COFF/asm.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/asm.ll?rev=256685&r1=256684&r2=256685&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/asm.ll (original)
+++ llvm/trunk/test/DebugInfo/COFF/asm.ll Fri Jan  1 00:50:01 2016
@@ -130,15 +130,12 @@
 ; X64-NEXT: .L{{.*}}:{{$}}
 ; X64-NEXT: [[START:.*]]:{{$}}
 ; X64:      # BB
-; X64:      pushq %rbp
-; X64-NEXT: subq    $32, %rsp
-; X64-NEXT: leaq    32(%rsp), %rbp
+; X64:      subq    $40, %rsp
 ; X64-NEXT: [[ASM_LINE:.*]]:{{$}}
 ; X64:      [[CALL_LINE:.*]]:{{$}}
 ; X64:      callq   g
 ; X64-NEXT: [[EPILOG_AND_RET:.*]]:
-; X64:      addq    $32, %rsp
-; X64-NEXT: popq %rbp
+; X64:      addq    $40, %rsp
 ; X64-NEXT: ret
 ; X64-NEXT: [[END_OF_F:.*]]:
 ;
@@ -225,22 +222,22 @@
 ; OBJ64:        ProcStart {
 ; OBJ64-NEXT:     DisplayName: f
 ; OBJ64-NEXT:     Section: f
-; OBJ64-NEXT:     CodeSize: 0x17
+; OBJ64-NEXT:     CodeSize: 0xE
 ; OBJ64-NEXT:   }
 ; OBJ64-NEXT:   ProcEnd
 ; OBJ64-NEXT: ]
 ; OBJ64:      FunctionLineTable [
 ; OBJ64-NEXT:   Name: f
 ; OBJ64-NEXT:   Flags: 0x1
-; OBJ64-NEXT:   CodeSize: 0x17
+; OBJ64-NEXT:   CodeSize: 0xE
 ; OBJ64-NEXT:   FilenameSegment [
 ; OBJ64-NEXT:     Filename: D:\asm.c
 ; OBJ64-NEXT:     +0x0: 3
 ; FIXME: An empty __asm stmt creates an extra entry.
 ; See PR18679 for the details.
-; OBJ64-NEXT:     +0xA: 4
-; OBJ64-NEXT:     +0xC: 5
-; OBJ64-NEXT:     +0x11: 6
+; OBJ64-NEXT:     +0x4: 4
+; OBJ64-NEXT:     +0x4: 5
+; OBJ64-NEXT:     +0x9: 6
 ; OBJ64-NEXT:     ColStart: 0
 ; OBJ64-NEXT:     ColEnd: 0
 ; OBJ64-NEXT:     ColStart: 0




More information about the llvm-commits mailing list