Index: include/llvm/Target/TargetFrameLowering.h =================================================================== --- include/llvm/Target/TargetFrameLowering.h +++ include/llvm/Target/TargetFrameLowering.h @@ -249,9 +249,11 @@ /// 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. + /// This will return false if it's not possible to statically address the + /// frame object from SP. /// TODO: This should really be a parameterizable choice. - virtual int getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, - unsigned &FrameReg) const { + virtual bool getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, + unsigned &FrameReg, int &SPOffset) const { // default to calling normal version, we override this on x86 only llvm_unreachable("unimplemented for non-x86"); return 0; Index: lib/Analysis/AliasAnalysis.cpp =================================================================== --- lib/Analysis/AliasAnalysis.cpp +++ lib/Analysis/AliasAnalysis.cpp @@ -445,7 +445,7 @@ unsigned ArgNo = 0; ModRefInfo R = MRI_NoModRef; - for (ImmutableCallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end(); + for (auto CI = CS.data_operands_begin(), CE = CS.data_operands_end(); CI != CE; ++CI, ++ArgNo) { // Only look at the no-capture or byval pointer arguments. If this // pointer were passed to arguments that were neither of these, then it Index: lib/CodeGen/AsmPrinter/WinException.cpp =================================================================== --- lib/CodeGen/AsmPrinter/WinException.cpp +++ lib/CodeGen/AsmPrinter/WinException.cpp @@ -301,8 +301,13 @@ const WinEHFuncInfo &FuncInfo) { const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering(); unsigned UnusedReg; - if (Asm->MAI->usesWindowsCFI()) - return TFI.getFrameIndexReferenceFromSP(*Asm->MF, FrameIndex, UnusedReg); + if (Asm->MAI->usesWindowsCFI()) { + int SPOffset; + bool Success = TFI.getFrameIndexReferenceFromSP(*Asm->MF, FrameIndex, + UnusedReg, SPOffset); + assert(Success); + return SPOffset; + } // 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); Index: lib/CodeGen/PrologEpilogInserter.cpp =================================================================== --- lib/CodeGen/PrologEpilogInserter.cpp +++ lib/CodeGen/PrologEpilogInserter.cpp @@ -1093,9 +1093,15 @@ "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 + if (!TFI->hasReservedCallFrame(Fn) || + !TFI->getFrameIndexReferenceFromSP(Fn, MI->getOperand(i).getIndex(), + Reg, refOffset)) { + refOffset = TFI->getFrameIndexReference(Fn, MI->getOperand(i).getIndex(), + Reg); + } Offset.setImm(Offset.getImm() + refOffset); MI->getOperand(i).ChangeToRegister(Reg, false /*isDef*/); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -7180,8 +7180,8 @@ // Populate the argument list. // Attributes for args start at offset 1, after the return attribute. - for (unsigned ArgI = ArgIdx, ArgE = ArgIdx + NumArgs, AttrI = ArgIdx + 1; - ArgI != ArgE; ++ArgI) { + for (unsigned ArgI = ArgIdx, ArgE = ArgIdx + NumArgs, AttrI = ArgIdx+1; + ArgI != ArgE; ++ArgI, ++AttrI) { const Value *V = CS->getOperand(ArgI); assert(!V->getType()->isEmptyTy() && "Empty type passed to intrinsic."); Index: lib/Target/X86/X86FrameLowering.h =================================================================== --- lib/Target/X86/X86FrameLowering.h +++ lib/Target/X86/X86FrameLowering.h @@ -100,8 +100,8 @@ int getFrameIndexReference(const MachineFunction &MF, int FI, unsigned &FrameReg) const override; - int getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, - unsigned &FrameReg) const override; + bool getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, + unsigned &FrameReg, int &Offset) const override; MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, Index: lib/Target/X86/X86FrameLowering.cpp =================================================================== --- lib/Target/X86/X86FrameLowering.cpp +++ lib/Target/X86/X86FrameLowering.cpp @@ -1436,7 +1436,10 @@ // 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; + bool Success = getFrameIndexReferenceFromSP(MF, Info.PSPSymFrameIdx, + SPReg, Offset); + assert(Success); assert(Offset >= 0); return static_cast(Offset); } @@ -1722,58 +1725,55 @@ } // Simplified from getFrameIndexReference keeping only StackPointer cases -int X86FrameLowering::getFrameIndexReferenceFromSP(const MachineFunction &MF, - int FI, - unsigned &FrameReg) const { +bool X86FrameLowering::getFrameIndexReferenceFromSP(const MachineFunction &MF, + int FI, unsigned &FrameReg, + int &SPOffset) 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 false; } + // 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(); @@ -1805,8 +1805,8 @@ // Get the Offset from the StackPointer int Offset = MFI->getObjectOffset(FI) - getOffsetOfLocalArea(); - - return Offset + StackSize; + SPOffset = Offset + StackSize; + return true; } bool X86FrameLowering::assignCalleeSavedSpillSlots( Index: test/CodeGen/X86/statepoint-attributes.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/statepoint-attributes.ll @@ -0,0 +1,22 @@ +; RUN: llc < %s 2>&1 | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.struct6 = type { i64, i64, i64 } + +@f.I = private unnamed_addr constant %struct.struct6 { i64 1, i64 2, i64 3 }, align 8 + +define i64 @f() { + ; if the byval attribute is copied correctly by statepoint lowering + ; we should not use dx to pass the argument as a pointer but the stack instead + ; CHECK-NOT: edx + ; CHECK-NOT: rdx + %O = alloca %struct.struct6, align 8 + %1 = bitcast %struct.struct6* %O to i8* + call void @test_6(%struct.struct6* nonnull sret %O, %struct.struct6* byval nonnull align 8 @f.I, i64 4) [ "deopt"(i8* %1) ] + %2 = getelementptr inbounds %struct.struct6, %struct.struct6* %O, i64 0, i32 2 + %3 = load i64, i64* %2, align 8 + ret i64 %3 +} + +declare void @test_6(%struct.struct6* sret, %struct.struct6* byval align 8, i64) Index: test/CodeGen/X86/statepoint-memdep.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/statepoint-memdep.ll @@ -0,0 +1,16 @@ +; RUN: opt -S -dse < %s 2>&1 | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @f() { + %s = alloca i64 + ; verify that this first store is not considered killed by the second one + ; since it could be observed from the deopt continuation + ; CHECK: store i64 1, i64* %s + store i64 1, i64* %s + call void @g() [ "deopt"(i64* %s) ] + store i64 0, i64* %s + ret void +} + +declare void @g() Index: test/CodeGen/X86/statepoint-nosp.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/statepoint-nosp.ll @@ -0,0 +1,15 @@ +; RUN: llc -debug-only=stackmaps < %s 2>&1 | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @f(i64 %n) { + %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 + ; CHECK: Loc 3: Direct 6 + call void @g(i64* %vl) [ "deopt"(i64* %s) ] + ret void +} + +declare void @g(i64* %vl)