diff --git a/llvm/include/llvm/CodeGen/CallingConvLower.h b/llvm/include/llvm/CodeGen/CallingConvLower.h --- a/llvm/include/llvm/CodeGen/CallingConvLower.h +++ b/llvm/include/llvm/CodeGen/CallingConvLower.h @@ -91,14 +91,14 @@ return getReg(ValNo, ValVT, RegNo, LocVT, HTP, /*IsCustom=*/true); } - static CCValAssign getMem(unsigned ValNo, MVT ValVT, unsigned Offset, + static CCValAssign getMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP, bool IsCustom = false) { CCValAssign Ret(HTP, ValNo, ValVT, LocVT, IsCustom); - Ret.Data = int64_t(Offset); + Ret.Data = Offset; return Ret; } - static CCValAssign getCustomMem(unsigned ValNo, MVT ValVT, unsigned Offset, + static CCValAssign getCustomMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP) { return getMem(ValNo, ValVT, Offset, LocVT, HTP, /*IsCustom=*/true); } @@ -112,7 +112,7 @@ void convertToReg(unsigned RegNo) { Data = Register(RegNo); } - void convertToMem(unsigned Offset) { Data = int64_t(Offset); } + void convertToMem(int64_t Offset) { Data = Offset; } unsigned getValNo() const { return ValNo; } MVT getValVT() const { return ValVT; } @@ -124,7 +124,7 @@ bool needsCustom() const { return isCustom; } Register getLocReg() const { return std::get(Data); } - unsigned getLocMemOffset() const { return std::get(Data); } + int64_t getLocMemOffset() const { return std::get(Data); } unsigned getExtraInfo() const { return std::get(Data); } MVT getLocVT() const { return LocVT; } @@ -174,8 +174,10 @@ const TargetRegisterInfo &TRI; SmallVectorImpl &Locs; LLVMContext &Context; + // True if arguments should be allocated at negative offsets. + bool NegativeOffsets; - unsigned StackSize; + uint64_t StackSize; Align MaxStackArgAlign; SmallVector UsedRegs; SmallVector PendingLocs; @@ -224,8 +226,9 @@ unsigned InRegsParamsProcessed; public: - CCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF, - SmallVectorImpl &locs, LLVMContext &C); + CCState(CallingConv::ID CC, bool IsVarArg, MachineFunction &MF, + SmallVectorImpl &Locs, LLVMContext &Context, + bool NegativeOffsets = false); void addLoc(const CCValAssign &V) { Locs.push_back(V); @@ -237,12 +240,12 @@ bool isVarArg() const { return IsVarArg; } /// Returns the size of the currently allocated portion of the stack. - unsigned getStackSize() const { return StackSize; } + uint64_t getStackSize() const { return StackSize; } /// getAlignedCallFrameSize - Return the size of the call frame needed to /// be able to store all arguments and such that the alignment requirement /// of each of the arguments is satisfied. - unsigned getAlignedCallFrameSize() const { + uint64_t getAlignedCallFrameSize() const { return alignTo(StackSize, MaxStackArgAlign); } @@ -396,21 +399,26 @@ /// AllocateStack - Allocate a chunk of stack space with the specified size /// and alignment. - unsigned AllocateStack(unsigned Size, Align Alignment) { - StackSize = alignTo(StackSize, Alignment); - unsigned Result = StackSize; - StackSize += Size; + int64_t AllocateStack(unsigned Size, Align Alignment) { + int64_t Offset; + if (NegativeOffsets) { + StackSize = alignTo(StackSize + Size, Alignment); + Offset = -StackSize; + } else { + Offset = alignTo(StackSize, Alignment); + StackSize = Offset + Size; + } MaxStackArgAlign = std::max(Alignment, MaxStackArgAlign); ensureMaxAlignment(Alignment); - return Result; + return Offset; } void ensureMaxAlignment(Align Alignment); /// Version of AllocateStack with list of extra registers to be shadowed. /// Note that, unlike AllocateReg, this shadows ALL of the shadow registers. - unsigned AllocateStack(unsigned Size, Align Alignment, - ArrayRef ShadowRegs) { + int64_t AllocateStack(unsigned Size, Align Alignment, + ArrayRef ShadowRegs) { for (MCPhysReg Reg : ShadowRegs) MarkAllocated(Reg); return AllocateStack(Size, Alignment); diff --git a/llvm/lib/CodeGen/CallingConvLower.cpp b/llvm/lib/CodeGen/CallingConvLower.cpp --- a/llvm/lib/CodeGen/CallingConvLower.cpp +++ b/llvm/lib/CodeGen/CallingConvLower.cpp @@ -25,10 +25,13 @@ using namespace llvm; -CCState::CCState(CallingConv::ID CC, bool isVarArg, MachineFunction &mf, - SmallVectorImpl &locs, LLVMContext &C) - : CallingConv(CC), IsVarArg(isVarArg), MF(mf), - TRI(*MF.getSubtarget().getRegisterInfo()), Locs(locs), Context(C) { +CCState::CCState(CallingConv::ID CC, bool IsVarArg, MachineFunction &MF, + SmallVectorImpl &Locs, LLVMContext &Context, + bool NegativeOffsets) + : CallingConv(CC), IsVarArg(IsVarArg), MF(MF), + TRI(*MF.getSubtarget().getRegisterInfo()), Locs(Locs), Context(Context), + NegativeOffsets(NegativeOffsets) { + // No stack is used. StackSize = 0; @@ -51,7 +54,7 @@ ensureMaxAlignment(Alignment); MF.getSubtarget().getTargetLowering()->HandleByVal(this, Size, Alignment); Size = unsigned(alignTo(Size, MinAlign)); - unsigned Offset = AllocateStack(Size, Alignment); + uint64_t Offset = AllocateStack(Size, Alignment); addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); } @@ -197,7 +200,7 @@ void CCState::getRemainingRegParmsForType(SmallVectorImpl &Regs, MVT VT, CCAssignFn Fn) { - unsigned SavedStackSize = StackSize; + uint64_t SavedStackSize = StackSize; Align SavedMaxStackArgAlign = MaxStackArgAlign; unsigned NumLocs = Locs.size(); diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -7222,8 +7222,8 @@ // On AIX a minimum of 8 words is saved to the parameter save area. const unsigned MinParameterSaveArea = 8 * PtrByteSize; // Area that is at least reserved in the caller of this function. - unsigned CallerReservedArea = - std::max(CCInfo.getStackSize(), LinkageSize + MinParameterSaveArea); + unsigned CallerReservedArea = std::max( + CCInfo.getStackSize(), LinkageSize + MinParameterSaveArea); // Set the size that is at least reserved in caller of this function. Tail // call optimized function's reserved stack space needs to be aligned so @@ -7315,8 +7315,8 @@ // conservatively assume that it is needed. As such, make sure we have at // least enough stack space for the caller to store the 8 GPRs. const unsigned MinParameterSaveAreaSize = 8 * PtrByteSize; - const unsigned NumBytes = - std::max(LinkageSize + MinParameterSaveAreaSize, CCInfo.getStackSize()); + const unsigned NumBytes = std::max( + LinkageSize + MinParameterSaveAreaSize, CCInfo.getStackSize()); // Adjust the stack pointer for the new arguments... // These operations are automatically eliminated by the prolog/epilog pass. diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -1204,7 +1204,7 @@ // Called functions expect 6 argument words to exist in the stack frame, used // or not. unsigned StackReserved = 6 * 8u; - unsigned ArgsSize = std::max(StackReserved, CCInfo.getStackSize()); + unsigned ArgsSize = std::max(StackReserved, CCInfo.getStackSize()); // Keep stack frames 16-byte aligned. ArgsSize = alignTo(ArgsSize, 16); diff --git a/llvm/unittests/CodeGen/CCStateTest.cpp b/llvm/unittests/CodeGen/CCStateTest.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/CodeGen/CCStateTest.cpp @@ -0,0 +1,49 @@ +//===- CCStateTest.cpp ----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetLowering.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +#include "MFCommon.inc" + +TEST(CCStateTest, NegativeOffsets) { + LLVMContext Ctx; + Module Mod("Module", Ctx); + auto MF = createMachineFunction(Ctx, Mod); + + SmallVector Locs; + CCState Info(CallingConv::C, /*IsVarArg=*/false, *MF, Locs, Ctx, + /*NegativeOffsets=*/true); + + ASSERT_EQ(Info.AllocateStack(1, Align(1)), -1); + ASSERT_EQ(Info.AllocateStack(1, Align(2)), -2); + ASSERT_EQ(Info.AllocateStack(1, Align(2)), -4); + ASSERT_EQ(Info.AllocateStack(1, Align(1)), -5); + ASSERT_EQ(Info.AllocateStack(2, Align(2)), -8); + ASSERT_EQ(Info.AllocateStack(2, Align(2)), -10); + ASSERT_EQ(Info.AllocateStack(2, Align(1)), -12); + ASSERT_EQ(Info.AllocateStack(1, Align(1)), -13); + ASSERT_EQ(Info.getStackSize(), 13u); + ASSERT_EQ(Info.getAlignedCallFrameSize(), 14u); +} + +} // namespace diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt --- a/llvm/unittests/CodeGen/CMakeLists.txt +++ b/llvm/unittests/CodeGen/CMakeLists.txt @@ -20,6 +20,7 @@ AllocationOrderTest.cpp AMDGPUMetadataTest.cpp AsmPrinterDwarfTest.cpp + CCStateTest.cpp DIEHashTest.cpp DIETest.cpp DwarfStringPoolEntryRefTest.cpp diff --git a/llvm/utils/TableGen/CallingConvEmitter.cpp b/llvm/utils/TableGen/CallingConvEmitter.cpp --- a/llvm/utils/TableGen/CallingConvEmitter.cpp +++ b/llvm/utils/TableGen/CallingConvEmitter.cpp @@ -251,7 +251,7 @@ int Size = Action->getValueAsInt("Size"); int Align = Action->getValueAsInt("Align"); - O << IndentStr << "unsigned Offset" << ++Counter + O << IndentStr << "int64_t Offset" << ++Counter << " = State.AllocateStack("; if (Size) O << Size << ", "; @@ -287,7 +287,7 @@ O << LS << getQualifiedName(ShadowRegList->getElementAsRecord(i)); O << "\n" << IndentStr << "};\n"; - O << IndentStr << "unsigned Offset" << ++Counter + O << IndentStr << "int64_t Offset" << ++Counter << " = State.AllocateStack(" << Size << ", Align(" << Align << "), " << "ShadowRegList" << ShadowRegListNumber << ");\n"; O << IndentStr << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset"