Index: lib/Target/X86/X86FrameLowering.cpp =================================================================== --- lib/Target/X86/X86FrameLowering.cpp +++ lib/Target/X86/X86FrameLowering.cpp @@ -829,6 +829,33 @@ } } +// Determines if instruction pointed to by MBBI is preceded by a call +// instruction in the final emitted instruction stream. +static bool isPrecededByCall(MachineBasicBlock::iterator MBBI) { + + MachineFunction::iterator MFI(*MBBI->getParent()); + MachineFunction* MF = MFI->getParent(); +Skip: + if (MBBI == MFI->begin()) { + if (MFI == MF->begin()) + return false; + else { + --MFI; + MBBI = MFI->end(); + } + } else { + --MBBI; + } + // Pseudo's don't count because they aren't emitted. + // We also ignore JMP's, because prologue/epilogue insertion runs before + // control flow optimization, so there usually are trivial JMPs at the end + // of each MBB, which are later eliminated. + if (MBBI->isPseudo() || MBBI->isUnconditionalBranch()) + goto Skip; + + return MBBI->isCall(); +} + void X86FrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); @@ -849,6 +876,11 @@ unsigned FramePtr = RegInfo->getFrameRegister(MF); unsigned StackPtr = RegInfo->getStackRegister(); + bool IsWinEH = + MF.getTarget().getMCAsmInfo()->getExceptionHandlingType() == + ExceptionHandling::WinEH; + bool NeedsWinEH = IsWinEH && MF.getFunction()->needsUnwindTableEntry(); + switch (RetOpcode) { default: llvm_unreachable("Can only insert epilog into returning blocks"); @@ -933,15 +965,27 @@ unsigned Opc = getLEArOpcode(IsLP64); addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr), FramePtr, false, -CSSize); + --MBBI; } else { unsigned Opc = (Is64Bit ? X86::MOV64rr : X86::MOV32rr); BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr) .addReg(FramePtr); + --MBBI; } } else if (NumBytes) { // Adjust stack pointer back: ESP += numbytes. emitSPUpdate(MBB, MBBI, StackPtr, NumBytes, Is64Bit, IsLP64, UseLEA, TII, *RegInfo); + --MBBI; + } + + // Windows unwinder will not invoke function's exception handler if IP + // is either in prologue or in epilogue. This behavior causes a problem + // when a call immediately precedes an epilogue, because the return + // address points into the epilogue. To cope with that, we insert + // a nop instruction after such calls. + if (NeedsWinEH && isPrecededByCall(MBBI)) { + BuildMI(MBB, MBBI, DL, TII.get(X86::NOOP)); } // We're returning from function via eh_return. Index: test/CodeGen/X86/win64_call_epi.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/win64_call_epi.ll @@ -0,0 +1,33 @@ +; RUN: llc < %s -O0 -mcpu=corei7 -mtriple=x86_64-pc-mingw32 | FileCheck %s -check-prefix=WIN64 + +define void @foo() { + + invoke void @bar() + to label %normal + unwind label %catch + +normal: + ret void + +catch: + %1 = landingpad { i8*, i32 } personality i32 (...)* @personality cleanup + resume { i8*, i32 } %1 +} + +declare void @bar() +declare i32 @personality(...) + +; WIN64-LABEL: foo: +; WIN64: .seh_proc foo + +; Check for 'nop' between the last call and the epilogue +; WIN64: callq bar +; WIN64: nop +; WIN64: addq $40, %rsp +; WIN64: retq + +; Check for 'ud2' after noreturn call +; WIN64: callq _Unwind_Resume +; WIN64: ud2 + +; WIN64: .seh_endproc