MF.getInfo<X86MachineFunctionInfo>()->getHasPushSequences();
}
+/// usesTheStack - This function checks if any of the users of EFLAGS
+/// copies the EFLAGS. We know that the code that lowers COPY of EFLAGS has
+/// to use the stack, and if we don't adjust the stack we clobber the first
+/// frame index.
+/// See X86InstrInfo::copyPhysReg.
+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(); });
+}
+
+static bool doesStackUseImplyFP(const MachineFunction &MF) {
+ bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
+ return IsWin64Prologue && usesTheStack(MF);
+}
+
/// hasFP - Return true if the specified function should have a dedicated frame
/// pointer register. This is true if the function has variable sized allocas
/// or if frame pointer elimination is disabled.
MFI->isFrameAddressTaken() || MFI->hasOpaqueSPAdjustment() ||
MF.getInfo<X86MachineFunctionInfo>()->getForceFramePointer() ||
MMI.callsUnwindInit() || MMI.hasEHFunclets() || MMI.callsEHReturn() ||
- MFI->hasStackMap() || MFI->hasPatchPoint());
+ MFI->hasStackMap() || MFI->hasPatchPoint() ||
+ doesStackUseImplyFP(MF));
}
static unsigned getSUBriOpcode(unsigned IsLP64, int64_t Imm) {
}
}
-/// usesTheStack - This function checks if any of the users of EFLAGS
-/// copies the EFLAGS. We know that the code that lowers COPY of EFLAGS has
-/// to use the stack, and if we don't adjust the stack we clobber the first
-/// frame index.
-/// See X86InstrInfo::copyPhysReg.
-static bool usesTheStack(const MachineFunction &MF) {
- const MachineRegisterInfo &MRI = MF.getRegInfo();
-
- for (MachineRegisterInfo::reg_instr_iterator
- ri = MRI.reg_instr_begin(X86::EFLAGS), re = MRI.reg_instr_end();
- ri != re; ++ri)
- if (ri->isCopy())
- return true;
-
- return false;
-}
-
MachineInstr *X86FrameLowering::emitStackProbe(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
"Not having LAHF/SAHF only happens on 64-bit.");
// Moving EFLAGS to / from another register requires a push and a pop.
// Notice that we have to adjust the stack if we don't want to clobber the
- // first frame index. See X86FrameLowering.cpp - clobbersTheStack.
+ // first frame index. See X86FrameLowering.cpp - usesTheStack.
if (FromEFLAGS) {
BuildMI(MBB, MI, DL, get(PushF));
BuildMI(MBB, MI, DL, get(Pop), DestReg);
// such as TF/IF/DF, which LLVM doesn't model.
//
// Notice that we have to adjust the stack if we don't want to clobber the
- // first frame index. See X86FrameLowering.cpp - clobbersTheStack.
+ // first frame index. See X86FrameLowering.cpp - usesTheStack.
bool AXDead = (Reg == AX) ||
; RUN: llc -mcpu=generic -mtriple=x86_64-mingw32 < %s | FileCheck %s
-; CHECK: subq $40, %rsp
-; CHECK: movaps %xmm8, 16(%rsp)
-; CHECK: movaps %xmm7, (%rsp)
+; CHECK: pushq %rbp
+; CHECK: subq $32, %rsp
+; CHECK: leaq 32(%rsp), %rbp
+; CHECK: movaps %xmm8, -16(%rbp)
+; CHECK: movaps %xmm7, -32(%rbp)
define i32 @a() nounwind {
entry:
;
; X64-LABEL: nop:
; X64: # BB#0:
+; X64-NEXT: subq $24, %rsp
; X64-NEXT: #APP
; X64-NEXT: #NO_APP
-; X64-NEXT: movaps %xmm0, -{{[0-9]+}}(%rsp)
+; X64-NEXT: movaps %xmm0, (%rsp)
+; X64-NEXT: addq $24, %rsp
; X64-NEXT: retq
%1 = alloca <4 x float>, align 16
%2 = call <4 x float> asm "", "=x,~{dirflag},~{fpsr},~{flags}"()
; 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, -8(%rsp)
-; CHECK-NEXT: movq -8(%rsp), %rdx
+; CHECK-NEXT: movq %rax, (%rsp)
+; CHECK-NEXT: movq (%rsp), %rdx
; CHECK-NEXT: #APP
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: movq %rdx, %rax
-; CHECK-NEXT: movq %rdx, -8(%rsp)
+; CHECK-NEXT: movq %rdx, (%rsp)
+; CHECK-NEXT: popq %rcx
; CHECK-NEXT: ret
define i64 @foo() {
-; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck %s
+; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck %s --check-prefix=CHECK --check-prefix=PUSHF
+; RUN: llc < %s -mtriple=x86_64-pc-win32 -mattr=+sahf | FileCheck %s --check-prefix=SAHF
define i32 @f1(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5) "no-frame-pointer-elim"="true" {
; CHECK-LABEL: f1:
; CHECK: leaq 224(%rbp), %rsp
}
+define i64 @f9() {
+entry:
+ ; CHECK-LABEL: f9:
+ ; CHECK: pushq %rbp
+ ; CHECK: .seh_pushreg 5
+ ; CHECK-NEXT: movq %rsp, %rbp
+ ; 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
+ ; CHECK-NEXT: pushfq
+ ; CHECK-NEXT: popq %rax
+ ; CHECK: #NO_APP
+
+ ret i64 %call
+ ; CHECK-NEXT: popq %rbp
+ ; CHECK-NEXT: retq
+}
+
+declare i64 @dummy()
+
+define i64 @f10(i64* %foo, i64 %bar, i64 %baz) {
+ ; CHECK-LABEL: f10:
+ ; CHECK: pushq %rbp
+ ; CHECK: .seh_pushreg 5
+ ; CHECK: pushq %rsi
+ ; CHECK: .seh_pushreg 6
+ ; CHECK: pushq %rdi
+ ; CHECK: .seh_pushreg 7
+ ; CHECK: subq $32, %rsp
+ ; CHECK: .seh_stackalloc 32
+ ; CHECK: leaq 32(%rsp), %rbp
+ ; CHECK: .seh_setframe 5, 32
+ ; CHECK: .seh_endprologue
+
+ %cx = cmpxchg i64* %foo, i64 %bar, i64 %baz seq_cst seq_cst
+ ; PUSHF: lock cmpxchgq
+ ; PUSHF-NEXT: pushfq
+ ; PUSHF-NEXT: popq %[[REG:.*]]
+ ; SAHF: lock cmpxchgq
+ ; SAHF-NEXT: seto %al
+ ; SAHF-NEXT: lahf
+
+ %v = extractvalue { i64, i1 } %cx, 0
+ %p = extractvalue { i64, i1 } %cx, 1
+
+ %call = call i64 @dummy()
+ ; PUSHF: callq dummy
+ ; PUSHF-NEXT: pushq %[[REG]]
+ ; PUSHF-NEXT: popfq
+ ; SAHF: callq dummy
+ ; SAHF-NEXT: pushq
+ ; SAHF: addb $127, %al
+ ; SAHF-NEXT: sahf
+ ; SAHF-NEXT: popq
+
+ %sel = select i1 %p, i64 %call, i64 %bar
+ ; CHECK-NEXT: cmovneq
+
+ ret i64 %sel
+ ; CHECK-NEXT: addq $32, %rsp
+ ; CHECK-NEXT: popq %rdi
+ ; CHECK-NEXT: popq %rsi
+ ; CHECK-NEXT: popq %rbp
+}
+
declare i8* @llvm.returnaddress(i32) nounwind readnone
declare void @llvm.va_start(i8*) nounwind
; 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 {
;
; Prologue code.
; Make sure we save the CSR used in the inline asm: rbx.
+; CHECK: pushq %rbp
; CHECK: pushq %rbx
;
; DISABLE: testl %ecx, %ecx
; DISABLE: jmp [[EPILOG_BB:.LBB[0-9_]+]]
;
; ENABLE-NEXT: popq %rbx
+; ENABLE-NEXT: popq %rbp
; ENABLE-NEXT: retq
;
; CHECK: [[ELSE_LABEL]]: # %if.else
; X64-NEXT: .L{{.*}}:{{$}}
; X64-NEXT: [[START:.*]]:{{$}}
; X64: # BB
-; X64: subq $40, %rsp
+; X64: pushq %rbp
+; X64-NEXT: subq $32, %rsp
+; X64-NEXT: leaq 32(%rsp), %rbp
; X64-NEXT: [[ASM_LINE:.*]]:{{$}}
; X64: [[CALL_LINE:.*]]:{{$}}
; X64: callq g
; X64-NEXT: [[EPILOG_AND_RET:.*]]:
-; X64: addq $40, %rsp
+; X64: addq $32, %rsp
+; X64-NEXT: popq %rbp
; X64-NEXT: ret
; X64-NEXT: [[END_OF_F:.*]]:
;
; OBJ64: ProcStart {
; OBJ64-NEXT: DisplayName: f
; OBJ64-NEXT: Section: f
-; OBJ64-NEXT: CodeSize: 0xE
+; OBJ64-NEXT: CodeSize: 0x17
; OBJ64-NEXT: }
; OBJ64-NEXT: ProcEnd
; OBJ64-NEXT: ]
; OBJ64: FunctionLineTable [
; OBJ64-NEXT: Name: f
; OBJ64-NEXT: Flags: 0x1
-; OBJ64-NEXT: CodeSize: 0xE
+; OBJ64-NEXT: CodeSize: 0x17
; 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: +0x4: 4
-; OBJ64-NEXT: +0x4: 5
-; OBJ64-NEXT: +0x9: 6
+; OBJ64-NEXT: +0xA: 4
+; OBJ64-NEXT: +0xC: 5
+; OBJ64-NEXT: +0x11: 6
; OBJ64-NEXT: ColStart: 0
; OBJ64-NEXT: ColEnd: 0
; OBJ64-NEXT: ColStart: 0