From e9f1be7f564effcae65d3d394e614d6411e3f229 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Wed, 15 Jun 2016 05:35:14 +0000 Subject: [PATCH] Don't force SP-relative addressing for statepoints Summary: ... when the offset is not statically known. Prioritize addresses relative to the stack pointer in the stackmap, but fallback gracefully to other modes of addressing if the offset to the stack pointer is not a known constant. Patch by Oscar Blumberg! Reviewers: sanjoy Subscribers: llvm-commits, majnemer, rnk, sanjoy, thanm Differential Revision: http://reviews.llvm.org/D21259 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@272756 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Target/TargetFrameLowering.h | 10 ++- lib/CodeGen/AsmPrinter/WinException.cpp | 3 +- lib/CodeGen/PrologEpilogInserter.cpp | 13 +++- lib/Target/X86/X86FrameLowering.cpp | 102 ++++++++++++++++-------------- lib/Target/X86/X86FrameLowering.h | 6 +- test/CodeGen/X86/deopt-bundles.ll | 13 ++++ 6 files changed, 89 insertions(+), 58 deletions(-) diff --git a/include/llvm/Target/TargetFrameLowering.h b/include/llvm/Target/TargetFrameLowering.h index cdde1ffe918..a71845e3e9a 100644 --- a/include/llvm/Target/TargetFrameLowering.h +++ b/include/llvm/Target/TargetFrameLowering.h @@ -249,12 +249,16 @@ public: /// Same as above, except that the 'base register' will always be RSP, not /// RBP on x86. This is generally used for emitting statepoint or EH tables /// that use offsets from RSP. + /// If AllowSPAdjustment is true, the returned offset is only guaranteed + /// to be valid with respect to the value of SP at the end of the prologue. /// TODO: This should really be a parameterizable choice. - virtual int getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, - unsigned &FrameReg) const { + virtual Optional + getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, + unsigned &FrameReg, + bool AllowSPAdjustment) const { // default to calling normal version, we override this on x86 only llvm_unreachable("unimplemented for non-x86"); - return 0; + return None; } /// This method determines which of the registers reported by diff --git a/lib/CodeGen/AsmPrinter/WinException.cpp b/lib/CodeGen/AsmPrinter/WinException.cpp index 478396556d2..083aacb3fc5 100644 --- a/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/lib/CodeGen/AsmPrinter/WinException.cpp @@ -302,7 +302,8 @@ int WinException::getFrameIndexOffset(int FrameIndex, const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering(); unsigned UnusedReg; if (Asm->MAI->usesWindowsCFI()) - return TFI.getFrameIndexReferenceFromSP(*Asm->MF, FrameIndex, UnusedReg); + return *TFI.getFrameIndexReferenceFromSP(*Asm->MF, FrameIndex, UnusedReg, + /*AllowSPAdjustment*/ true); // For 32-bit, offsets should be relative to the end of the EH registration // node. For 64-bit, it's relative to SP at the end of the prologue. assert(FuncInfo.EHRegNodeEndOffset != INT_MAX); diff --git a/lib/CodeGen/PrologEpilogInserter.cpp b/lib/CodeGen/PrologEpilogInserter.cpp index bd7f34b485e..33935c421a3 100644 --- a/lib/CodeGen/PrologEpilogInserter.cpp +++ b/lib/CodeGen/PrologEpilogInserter.cpp @@ -1094,9 +1094,16 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &Fn, "DBG_VALUE machine instruction"); unsigned Reg; MachineOperand &Offset = MI->getOperand(i + 1); - const unsigned refOffset = - TFI->getFrameIndexReferenceFromSP(Fn, MI->getOperand(i).getIndex(), - Reg); + int refOffset; + // First try to get an offset relative to SP. If that's not + // possible use whatever the target usually uses. + auto SPOffset = TFI->getFrameIndexReferenceFromSP( + Fn, MI->getOperand(i).getIndex(), Reg, /*AllowSPAdjustment*/ false); + if (SPOffset) + refOffset = *SPOffset; + else + refOffset = TFI->getFrameIndexReference( + Fn, MI->getOperand(i).getIndex(), Reg); Offset.setImm(Offset.getImm() + refOffset); MI->getOperand(i).ChangeToRegister(Reg, false /*isDef*/); diff --git a/lib/Target/X86/X86FrameLowering.cpp b/lib/Target/X86/X86FrameLowering.cpp index 393dcb9d104..975eb0c4513 100644 --- a/lib/Target/X86/X86FrameLowering.cpp +++ b/lib/Target/X86/X86FrameLowering.cpp @@ -1436,7 +1436,8 @@ X86FrameLowering::getPSPSlotOffsetFromSP(const MachineFunction &MF) const { // getFrameIndexReferenceFromSP has an out ref parameter for the stack // pointer register; pass a dummy that we ignore unsigned SPReg; - int Offset = getFrameIndexReferenceFromSP(MF, Info.PSPSymFrameIdx, SPReg); + int Offset = *getFrameIndexReferenceFromSP(MF, Info.PSPSymFrameIdx, SPReg, + /*AllowSPAdjustment*/ true); assert(Offset >= 0); return static_cast(Offset); } @@ -1722,57 +1723,60 @@ int X86FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, } // Simplified from getFrameIndexReference keeping only StackPointer cases -int X86FrameLowering::getFrameIndexReferenceFromSP(const MachineFunction &MF, - int FI, - unsigned &FrameReg) const { +Optional +X86FrameLowering::getFrameIndexReferenceFromSP(const MachineFunction &MF, + int FI, unsigned &FrameReg, + bool AllowSPAdjustment) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); // Does not include any dynamic realign. const uint64_t StackSize = MFI->getStackSize(); - { -#ifndef NDEBUG - // LLVM arranges the stack as follows: - // ... - // ARG2 - // ARG1 - // RETADDR - // PUSH RBP <-- RBP points here - // PUSH CSRs - // ~~~~~~~ <-- possible stack realignment (non-win64) - // ... - // STACK OBJECTS - // ... <-- RSP after prologue points here - // ~~~~~~~ <-- possible stack realignment (win64) - // - // if (hasVarSizedObjects()): - // ... <-- "base pointer" (ESI/RBX) points here - // DYNAMIC ALLOCAS - // ... <-- RSP points here - // - // Case 1: In the simple case of no stack realignment and no dynamic - // allocas, both "fixed" stack objects (arguments and CSRs) are addressable - // with fixed offsets from RSP. - // - // Case 2: In the case of stack realignment with no dynamic allocas, fixed - // stack objects are addressed with RBP and regular stack objects with RSP. - // - // Case 3: In the case of dynamic allocas and stack realignment, RSP is used - // to address stack arguments for outgoing calls and nothing else. The "base - // pointer" points to local variables, and RBP points to fixed objects. - // - // In cases 2 and 3, we can only answer for non-fixed stack objects, and the - // answer we give is relative to the SP after the prologue, and not the - // SP in the middle of the function. - - assert((!MFI->isFixedObjectIndex(FI) || !TRI->needsStackRealignment(MF) || - STI.isTargetWin64()) && - "offset from fixed object to SP is not static"); - - // We don't handle tail calls, and shouldn't be seeing them either. - int TailCallReturnAddrDelta = - MF.getInfo()->getTCReturnAddrDelta(); - assert(!(TailCallReturnAddrDelta < 0) && "we don't handle this case!"); -#endif - } + // LLVM arranges the stack as follows: + // ... + // ARG2 + // ARG1 + // RETADDR + // PUSH RBP <-- RBP points here + // PUSH CSRs + // ~~~~~~~ <-- possible stack realignment (non-win64) + // ... + // STACK OBJECTS + // ... <-- RSP after prologue points here + // ~~~~~~~ <-- possible stack realignment (win64) + // + // if (hasVarSizedObjects()): + // ... <-- "base pointer" (ESI/RBX) points here + // DYNAMIC ALLOCAS + // ... <-- RSP points here + // + // Case 1: In the simple case of no stack realignment and no dynamic + // allocas, both "fixed" stack objects (arguments and CSRs) are addressable + // with fixed offsets from RSP. + // + // Case 2: In the case of stack realignment with no dynamic allocas, fixed + // stack objects are addressed with RBP and regular stack objects with RSP. + // + // Case 3: In the case of dynamic allocas and stack realignment, RSP is used + // to address stack arguments for outgoing calls and nothing else. The "base + // pointer" points to local variables, and RBP points to fixed objects. + // + // In cases 2 and 3, we can only answer for non-fixed stack objects, and the + // answer we give is relative to the SP after the prologue, and not the + // SP in the middle of the function. + + if (MFI->isFixedObjectIndex(FI) && TRI->needsStackRealignment(MF) && + !STI.isTargetWin64()) + return None; + + // If !hasReservedCallFrame the function might have SP adjustement in the + // body. So, even though the offset is statically known, it depends on where + // we are in the function. + const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + if (!AllowSPAdjustment && !TFI->hasReservedCallFrame(MF)) + return None; + // We don't handle tail calls, and shouldn't be seeing them either. + int TailCallReturnAddrDelta = + MF.getInfo()->getTCReturnAddrDelta(); + assert(!(TailCallReturnAddrDelta < 0) && "we don't handle this case!"); // Fill in FrameReg output argument. FrameReg = TRI->getStackRegister(); diff --git a/lib/Target/X86/X86FrameLowering.h b/lib/Target/X86/X86FrameLowering.h index 9ec3966af33..192ec0e8b5f 100644 --- a/lib/Target/X86/X86FrameLowering.h +++ b/lib/Target/X86/X86FrameLowering.h @@ -100,8 +100,10 @@ public: int getFrameIndexReference(const MachineFunction &MF, int FI, unsigned &FrameReg) const override; - int getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, - unsigned &FrameReg) const override; + Optional + getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, + unsigned &FrameReg, + bool AllowSPAdjustment) const override; MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, diff --git a/test/CodeGen/X86/deopt-bundles.ll b/test/CodeGen/X86/deopt-bundles.ll index 4a9cf3b156d..1fb73ea252e 100644 --- a/test/CodeGen/X86/deopt-bundles.ll +++ b/test/CodeGen/X86/deopt-bundles.ll @@ -146,3 +146,16 @@ try.cont: } declare i32 @__CxxFrameHandler3(...) + +define void @f_0(i64 %n) { + ; CHECK-LABEL: _f_0 + %s = alloca i64 + %vl = alloca i64, i64 %n + ; Check that the stackmap does not reference %s through + ; SP since the offset is not static because of %vl. + ; STACKMAPS: Loc 3: Direct 6 + call void @g_0(i64* %vl) [ "deopt"(i64* %s) ] + ret void +} + +declare void @g_0(i64* %vl) -- 2.11.0