From fd0832ea89d79806a0839b57687bf884083c0dcf Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Thu, 4 Dec 2014 00:56:38 +0000 Subject: [PATCH] [X86] Restore X86 base pointer after call to llvm.eh.sjlj.setjmp Commit on - This patch fixes the bug described in http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-May/062343.html The fix allocates an extra slot just below the GPRs and stores the base pointer there. This is done only for functions containing llvm.eh.sjlj.setjmp that also need a base pointer. Because code containing llvm.eh.sjlj.setjmp saves all of the callee-save GPRs in the prologue, the offset to the extra slot can be computed before prologue generation runs. Impact at run-time on affected functions is:: - One extra store in the prologue, The store saves the base pointer. - One extra load after a llvm.eh.sjlj.setjmp. The load restores the base pointer. Because the extra slot is just above a gap between frame-pointer-relative and base-pointer-relative chunks of memory, there is no impact on other offset calculations other than ensuring there is room for the extra slot. http://reviews.llvm.org/D6388 Patch by Arch Robison git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@223329 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86FrameLowering.cpp | 13 ++++++++ lib/Target/X86/X86ISelLowering.cpp | 13 ++++++++ lib/Target/X86/X86MachineFunctionInfo.cpp | 19 ++++++++++++ lib/Target/X86/X86MachineFunctionInfo.h | 12 ++++++++ test/CodeGen/X86/sjlj-baseptr.ll | 37 +++++++++++++++++++++++ 5 files changed, 94 insertions(+) create mode 100644 test/CodeGen/X86/sjlj-baseptr.ll diff --git a/lib/Target/X86/X86FrameLowering.cpp b/lib/Target/X86/X86FrameLowering.cpp index f8ada8db292..b6e2d932d81 100644 --- a/lib/Target/X86/X86FrameLowering.cpp +++ b/lib/Target/X86/X86FrameLowering.cpp @@ -448,6 +448,8 @@ void X86FrameLowering::getStackProbeFunction(const X86Subtarget &STI, [if needs base pointer] mov %rsp, %rbx + [if needs to restore base pointer] + mov %rsp, -MMM(%rbp) ; Emit CFI info [if needs FP] @@ -570,6 +572,9 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const { if (HasFP) { // Calculate required stack adjustment. uint64_t FrameSize = StackSize - SlotSize; + // If required, include space for extra hidden slot for stashing base pointer. + if (X86FI->getRestoreBasePointer()) + FrameSize += SlotSize; if (RegInfo->needsStackRealignment(MF)) { // Callee-saved registers are pushed on stack before the stack // is realigned. @@ -838,6 +843,14 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const { BuildMI(MBB, MBBI, DL, TII.get(Opc), BasePtr) .addReg(StackPtr) .setMIFlag(MachineInstr::FrameSetup); + if (X86FI->getRestoreBasePointer()) { + // Stash value of base pointer. Saving RSP instead of EBP shortens dependence chain. + unsigned Opm = Uses64BitFramePtr ? X86::MOV64mr : X86::MOV32mr; + addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(Opm)), + FramePtr, true, X86FI->getRestoreBasePointerOffset()) + .addReg(StackPtr) + .setMIFlag(MachineInstr::FrameSetup); + } } if (((!HasFP && NumBytes) || PushedRegs) && NeedsDwarfCFI) { diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 658507ded9b..e1423fa21ce 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -20925,6 +20925,7 @@ X86TargetLowering::emitEHSjLjSetJmp(MachineInstr *MI, // v = phi(main, restore) // // restoreMBB: + // if base pointer being used, load it from frame // v_restore = 1 MachineBasicBlock *thisMBB = MBB; @@ -21008,6 +21009,18 @@ X86TargetLowering::emitEHSjLjSetJmp(MachineInstr *MI, .addReg(restoreDstReg).addMBB(restoreMBB); // restoreMBB: + if (RegInfo->hasBasePointer(*MF)) { + const X86Subtarget &STI = MF->getTarget().getSubtarget(); + const bool Uses64BitFramePtr = STI.isTarget64BitLP64() || STI.isTargetNaCl64(); + X86MachineFunctionInfo *X86FI = MF->getInfo(); + X86FI->setRestoreBasePointer(MF); + unsigned FramePtr = RegInfo->getFrameRegister(*MF); + unsigned BasePtr = RegInfo->getBaseRegister(); + unsigned Opm = Uses64BitFramePtr ? X86::MOV64rm : X86::MOV32rm; + addRegOffset(BuildMI(restoreMBB, DL, TII->get(Opm), BasePtr), + FramePtr, true, X86FI->getRestoreBasePointerOffset()) + .setMIFlag(MachineInstr::FrameSetup); + } BuildMI(restoreMBB, DL, TII->get(X86::MOV32ri), restoreDstReg).addImm(1); BuildMI(restoreMBB, DL, TII->get(X86::JMP_4)).addMBB(sinkMBB); restoreMBB->addSuccessor(sinkMBB); diff --git a/lib/Target/X86/X86MachineFunctionInfo.cpp b/lib/Target/X86/X86MachineFunctionInfo.cpp index 568dc222d9d..9518395916d 100644 --- a/lib/Target/X86/X86MachineFunctionInfo.cpp +++ b/lib/Target/X86/X86MachineFunctionInfo.cpp @@ -8,7 +8,26 @@ //===----------------------------------------------------------------------===// #include "X86MachineFunctionInfo.h" +#include "X86RegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" using namespace llvm; void X86MachineFunctionInfo::anchor() { } + +void X86MachineFunctionInfo::setRestoreBasePointer(const MachineFunction *MF) { + if (!RestoreBasePointerOffset) { + const X86RegisterInfo *RegInfo = static_cast( + MF->getSubtarget().getRegisterInfo()); + unsigned SlotSize = RegInfo->getSlotSize(); + for (const MCPhysReg *CSR = + RegInfo->X86RegisterInfo::getCalleeSavedRegs(MF); + unsigned Reg = *CSR; + ++CSR) + { + if (X86::GR64RegClass.contains(Reg) || X86::GR32RegClass.contains(Reg)) + RestoreBasePointerOffset -= SlotSize; + } + } +} + diff --git a/lib/Target/X86/X86MachineFunctionInfo.h b/lib/Target/X86/X86MachineFunctionInfo.h index 79a51b33001..2bd37eb16e0 100644 --- a/lib/Target/X86/X86MachineFunctionInfo.h +++ b/lib/Target/X86/X86MachineFunctionInfo.h @@ -31,6 +31,12 @@ class X86MachineFunctionInfo : public MachineFunctionInfo { /// contains stack pointer re-alignment code which requires FP. bool ForceFramePointer; + /// RestoreBasePointerOffset - Non-zero if the function has base pointer + /// and makes call to llvm.eh.sjlj.setjmp. When non-zero, the value is a + /// displacement from the frame pointer to a slot where the base pointer + /// is stashed. + signed char RestoreBasePointerOffset; + /// CalleeSavedFrameSize - Size of the callee-saved register portion of the /// stack frame in bytes. unsigned CalleeSavedFrameSize; @@ -89,6 +95,7 @@ private: public: X86MachineFunctionInfo() : ForceFramePointer(false), + RestoreBasePointerOffset(0), CalleeSavedFrameSize(0), BytesToPopOnReturn(0), ReturnAddrIndex(0), @@ -104,6 +111,7 @@ public: explicit X86MachineFunctionInfo(MachineFunction &MF) : ForceFramePointer(false), + RestoreBasePointerOffset(0), CalleeSavedFrameSize(0), BytesToPopOnReturn(0), ReturnAddrIndex(0), @@ -120,6 +128,10 @@ public: bool getForceFramePointer() const { return ForceFramePointer;} void setForceFramePointer(bool forceFP) { ForceFramePointer = forceFP; } + bool getRestoreBasePointer() const { return RestoreBasePointerOffset!=0; } + void setRestoreBasePointer(const MachineFunction *MF); + int getRestoreBasePointerOffset() const {return RestoreBasePointerOffset; } + unsigned getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; } void setCalleeSavedFrameSize(unsigned bytes) { CalleeSavedFrameSize = bytes; } diff --git a/test/CodeGen/X86/sjlj-baseptr.ll b/test/CodeGen/X86/sjlj-baseptr.ll new file mode 100644 index 00000000000..e439ff4dbd2 --- /dev/null +++ b/test/CodeGen/X86/sjlj-baseptr.ll @@ -0,0 +1,37 @@ +; RUN: llc < %s -mtriple=i386-pc-linux -mcpu=corei7 -relocation-model=static | FileCheck --check-prefix=X86 %s +; RUN: llc < %s -mtriple=x86_64-pc-linux -mcpu=corei7 -relocation-model=static | FileCheck --check-prefix=X64 %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +%Foo = type { [125 x i8] } + +declare i32 @llvm.eh.sjlj.setjmp(i8*) nounwind + +declare void @whatever(i64, %Foo*, i8**, i8*, i8*, i32) #0 + +attributes #0 = { nounwind uwtable "no-frame-pointer-elim"="true" } + +define i32 @test1(i64 %n, %Foo* byval nocapture readnone align 8 %f) #0 { +entry: + %buf = alloca [5 x i8*], align 16 + %p = alloca i8*, align 8 + %q = alloca i8, align 64 + %r = bitcast [5 x i8*]* %buf to i8* + %s = alloca i8, i64 %n, align 1 + store i8* %s, i8** %p, align 8 + %t = call i32 @llvm.eh.sjlj.setjmp(i8* %s) + call void @whatever(i64 %n, %Foo* %f, i8** %p, i8* %q, i8* %s, i32 %t) #1 + ret i32 0 +; X86: movl %esp, %esi +; X86: movl %esp, -16(%ebp) +; X86: {{.LBB.*:}} +; X86: movl -16(%ebp), %esi +; X86: {{.LBB.*:}} +; X64: movq %rsp, %rbx +; X64: movq %rsp, -48(%rbp) +; X64: {{.LBB.*:}} +; X64: movq -48(%rbp), %rbx +; X64: {{.LBB.*:}} +} + + -- 2.34.1