[llvm] da42b28 - [CodeGen] Support allocating of arguments by decreasing offsets

Sergei Barannikov via llvm-commits llvm-commits at lists.llvm.org
Wed May 17 11:52:10 PDT 2023


Author: Sergei Barannikov
Date: 2023-05-17T21:51:52+03:00
New Revision: da42b2846c82063bd1bce78d6a046f78f218eb72

URL: https://github.com/llvm/llvm-project/commit/da42b2846c82063bd1bce78d6a046f78f218eb72
DIFF: https://github.com/llvm/llvm-project/commit/da42b2846c82063bd1bce78d6a046f78f218eb72.diff

LOG: [CodeGen] Support allocating of arguments by decreasing offsets

Previously, `CCState::AllocateStack` always allocated stack space by increasing
offsets. For targets with stack growing up (away from zero) it is more
convenient to allocate arguments by decreasing offsets, so that the first
argument is at the top of the stack. This is important when calling a function
with variable number of arguments: the callee does not know the size of the
stack, but must be able to access "fixed" arguments. For that to work, the
"fixed" arguments should have fixed offsets relative to the stack top, i.e. the
variadic arguments area should be at the stack bottom (at lowest addresses).

The in-tree target with stack growing up is AMDGPU, but it allocates
arguments by increasing addresses. It does not support variadic arguments.

A drive-by change is to promote stack size/offset to 64-bit integer.
This is what MachineFrameInfo expects.

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D149575

Added: 
    llvm/unittests/CodeGen/CCStateTest.cpp

Modified: 
    llvm/include/llvm/CodeGen/CallingConvLower.h
    llvm/lib/CodeGen/CallingConvLower.cpp
    llvm/lib/Target/PowerPC/PPCISelLowering.cpp
    llvm/lib/Target/Sparc/SparcISelLowering.cpp
    llvm/unittests/CodeGen/CMakeLists.txt
    llvm/utils/TableGen/CallingConvEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/CallingConvLower.h b/llvm/include/llvm/CodeGen/CallingConvLower.h
index 3d70f5a2d8e92..a99519252cf92 100644
--- a/llvm/include/llvm/CodeGen/CallingConvLower.h
+++ b/llvm/include/llvm/CodeGen/CallingConvLower.h
@@ -91,14 +91,14 @@ class CCValAssign {
     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 @@ class CCValAssign {
 
   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 @@ class CCValAssign {
   bool needsCustom() const { return isCustom; }
 
   Register getLocReg() const { return std::get<Register>(Data); }
-  unsigned getLocMemOffset() const { return std::get<int64_t>(Data); }
+  int64_t getLocMemOffset() const { return std::get<int64_t>(Data); }
   unsigned getExtraInfo() const { return std::get<unsigned>(Data); }
 
   MVT getLocVT() const { return LocVT; }
@@ -174,8 +174,10 @@ class CCState {
   const TargetRegisterInfo &TRI;
   SmallVectorImpl<CCValAssign> &Locs;
   LLVMContext &Context;
+  // True if arguments should be allocated at negative offsets.
+  bool NegativeOffsets;
 
-  unsigned StackSize;
+  uint64_t StackSize;
   Align MaxStackArgAlign;
   SmallVector<uint32_t, 16> UsedRegs;
   SmallVector<CCValAssign, 4> PendingLocs;
@@ -224,8 +226,9 @@ class CCState {
   unsigned InRegsParamsProcessed;
 
 public:
-  CCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF,
-          SmallVectorImpl<CCValAssign> &locs, LLVMContext &C);
+  CCState(CallingConv::ID CC, bool IsVarArg, MachineFunction &MF,
+          SmallVectorImpl<CCValAssign> &Locs, LLVMContext &Context,
+          bool NegativeOffsets = false);
 
   void addLoc(const CCValAssign &V) {
     Locs.push_back(V);
@@ -237,12 +240,12 @@ class CCState {
   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 @@ class CCState {
 
   /// 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<MCPhysReg> ShadowRegs) {
+  int64_t AllocateStack(unsigned Size, Align Alignment,
+                        ArrayRef<MCPhysReg> 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
index 0cd9b005d0747..b7152587a9fa0 100644
--- 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<CCValAssign> &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<CCValAssign> &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 @@ void CCState::HandleByVal(unsigned ValNo, MVT ValVT, MVT LocVT,
   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 @@ static bool isValueTypeInRegForCC(CallingConv::ID CC, MVT VT) {
 
 void CCState::getRemainingRegParmsForType(SmallVectorImpl<MCPhysReg> &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
index a6ff951b71c7d..93577dc4ff0d3 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -7224,8 +7224,8 @@ SDValue PPCTargetLowering::LowerFormalArguments_AIX(
   // 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<unsigned>(
+      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
@@ -7317,8 +7317,8 @@ SDValue PPCTargetLowering::LowerCall_AIX(
   // 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<unsigned>(
+      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
index 6e6041b782fb2..0aa3c875a14fa 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -1204,7 +1204,7 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
   // 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<unsigned>(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
index 0000000000000..405e1c6ef90d9
--- /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<CCValAssign, 8> 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
index a559e35f12198..a4d761bee5a4e 100644
--- a/llvm/unittests/CodeGen/CMakeLists.txt
+++ b/llvm/unittests/CodeGen/CMakeLists.txt
@@ -21,6 +21,7 @@ add_llvm_unittest(CodeGenTests
   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
index 8e6b40e6cd20d..de3810b2e2279 100644
--- a/llvm/utils/TableGen/CallingConvEmitter.cpp
+++ b/llvm/utils/TableGen/CallingConvEmitter.cpp
@@ -251,7 +251,7 @@ void CallingConvEmitter::EmitAction(Record *Action,
       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 @@ void CallingConvEmitter::EmitAction(Record *Action,
         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"


        


More information about the llvm-commits mailing list