[llvm] 7d05f67 - [TableGen][CallingConv] Add CCAssignToRegTuple for synthetic registers. (#137826)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 30 16:32:40 PDT 2025


Author: Jason Eckhardt
Date: 2025-04-30T18:32:37-05:00
New Revision: 7d05f67a7377ad67e7eb15e0f8f7cf1f537b5afa

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

LOG: [TableGen][CallingConv] Add CCAssignToRegTuple for synthetic registers. (#137826)

Currently CCAssignToReg takes a list<Register>. There are tuple-heavy
back-ends where we would like to reference any register-- whether those
are singletons or those defined by RegisterTuples. However, the latter
are synthesized during tuple expansion and are not visible outside of
the register info emitter.

The problem is that the parser will see tuple registers as undefined
variables before the calling convention emitter is ever reached. To
defer evaluation of the symbol, we introduce CCAssignToRegTuple which
takes list<string> instead. This allows us to defer the actual
register name lookup until the emitter runs-- where we also validate
that the register actually exists.

This is currently used in a downstream back-end which will be upstreamed
very soon. In the meantime, a unit test is provided to exercise the
feature.

Added: 
    llvm/test/TableGen/cc-assign-to-reg-tuple.td

Modified: 
    llvm/include/llvm/Target/TargetCallingConv.td
    llvm/utils/TableGen/CallingConvEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Target/TargetCallingConv.td b/llvm/include/llvm/Target/TargetCallingConv.td
index 18b7ff4aec95f..d0533cad927a7 100644
--- a/llvm/include/llvm/Target/TargetCallingConv.td
+++ b/llvm/include/llvm/Target/TargetCallingConv.td
@@ -113,6 +113,13 @@ class CCAssignToReg<list<Register> regList> : CCAction {
   list<Register> RegList = regList;
 }
 
+/// CCAssignToRegTuple - Same as CCAssignToReg, but with a list of registers as
+/// strings. This is needed because records synthesized during tuple expansion
+/// are not visible outside of the register info emitter.
+class CCAssignToRegTuple<list<string> regList> : CCAction {
+  list<string> RegList = regList;
+}
+
 /// CCAssignToRegWithShadow - Same as CCAssignToReg, but with list of registers
 /// which became shadowed, when some register is used.
 class CCAssignToRegWithShadow<list<Register> regList,

diff  --git a/llvm/test/TableGen/cc-assign-to-reg-tuple.td b/llvm/test/TableGen/cc-assign-to-reg-tuple.td
new file mode 100644
index 0000000000000..624aa1d5f5f0b
--- /dev/null
+++ b/llvm/test/TableGen/cc-assign-to-reg-tuple.td
@@ -0,0 +1,78 @@
+// RUN: llvm-tblgen --gen-callingconv -I %p/../../include -I %p/Common %s 2>&1 | FileCheck %s
+// RUN: not llvm-tblgen -DERROR1 --gen-callingconv -I %p/../../include -I %p/Common %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR1 %s
+// RUN: not llvm-tblgen -DERROR2 --gen-callingconv -I %p/../../include -I %p/Common %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR2 %s
+
+include "reg-with-subregs-common.td"
+
+def CC_ABI1 : CallingConv<[
+  // Use singleton definitions directly.
+  CCIfType<[i32, f32],
+      CCAssignToReg<[R8, R9, R10, R11, R12, R13, R14, R15]>>,
+
+  // Use tuple definitions indirectly as strings.
+  CCIfType<[i64, f64],
+      CCAssignToRegTuple<["R8_R9", "R10_R11", "R12_R13", "R14_R15"]>>,
+
+  CCIfType<[i128],
+      CCAssignToRegTuple<["R8_R9_R10_R11", "R12_R13_R14_R15"]>>,
+
+  CCIfType<[v8i32],
+      CCAssignToRegTuple<["R8_R9_R10_R11_R12_R13_R14_R15"]>>,
+]>;
+
+// CHECK: if (LocVT == MVT::i32 ||
+// CHECK:      LocVT == MVT::f32) {
+// CHECK:    static const MCPhysReg RegList1[] = {
+// CHECK:      R8, R9, R10, R11, R12, R13, R14, R15
+// CHECK:    };
+// CHECK:    if (MCRegister Reg = State.AllocateReg(RegList1)) {
+// CHECK:      State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+// CHECK:      return false;
+// CHECK:    }
+// CHECK:  }
+
+// CHECK:  if (LocVT == MVT::i64 ||
+// CHECK:      LocVT == MVT::f64) {
+// CHECK:    static const MCPhysReg RegList2[] = {
+// CHECK:      R8_R9, R10_R11, R12_R13, R14_R15
+// CHECK:    };
+// CHECK:    if (MCRegister Reg = State.AllocateReg(RegList2)) {
+// CHECK:      State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+// CHECK:      return false;
+// CHECK:    }
+// CHECK:  }
+
+// CHECK:  if (LocVT == MVT::i128) {
+// CHECK:    static const MCPhysReg RegList3[] = {
+// CHECK:      R8_R9_R10_R11, R12_R13_R14_R15
+// CHECK:    };
+// CHECK:    if (MCRegister Reg = State.AllocateReg(RegList3)) {
+// CHECK:      State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+// CHECK:      return false;
+// CHECK:    }
+// CHECK:  }
+
+// CHECK:  if (LocVT == MVT::v8i32) {
+// CHECK:    if (MCRegister Reg = State.AllocateReg(R8_R9_R10_R11_R12_R13_R14_R15)) {
+// CHECK:      State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+// CHECK:      return false;
+// CHECK:    }
+// CHECK:  }
+
+#ifdef ERROR1
+def CC_ABI2 : CallingConv<[
+  // Test that referencing an undefined tuple is diagnosed as an error.
+  // CHECK-ERROR1: error: register not defined: "R89_R33"
+  CCIfType<[i64, f64],
+      CCAssignToRegTuple<["R89_R33", "R12_R13", "R14_R15"]>>,
+]>;
+#endif
+
+#ifdef ERROR2
+def CC_ABI3 : CallingConv<[
+  // Currently an error: Use tuple definitions directly.
+  // CHECK-ERROR2: error: Variable not defined: 'R8_R9_R10_R11'
+  CCIfType<[i128],
+      CCAssignToRegTuple<[R8_R9_R10_R11, R12_R13_R14_R15]>>,
+]>;
+#endif

diff  --git a/llvm/utils/TableGen/CallingConvEmitter.cpp b/llvm/utils/TableGen/CallingConvEmitter.cpp
index 57b1622752613..20dc1ff0ffd14 100644
--- a/llvm/utils/TableGen/CallingConvEmitter.cpp
+++ b/llvm/utils/TableGen/CallingConvEmitter.cpp
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "Common/CodeGenRegisters.h"
 #include "Common/CodeGenTarget.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/InterleavedRange.h"
@@ -26,6 +27,7 @@ using namespace llvm;
 namespace {
 class CallingConvEmitter {
   const RecordKeeper &Records;
+  const CodeGenTarget Target;
   unsigned Counter = 0u;
   std::string CurrentAction;
   bool SwiftAction = false;
@@ -35,7 +37,10 @@ class CallingConvEmitter {
   std::map<std::string, std::set<std::string>> DelegateToMap;
 
 public:
-  explicit CallingConvEmitter(const RecordKeeper &R) : Records(R) {}
+  explicit CallingConvEmitter(const RecordKeeper &R) : Records(R), Target(R) {
+    for (const CodeGenRegister &Reg : Target.getRegBank().getRegisters())
+      RegistersByDefName.try_emplace(Reg.getName(), &Reg);
+  }
 
   void run(raw_ostream &O);
 
@@ -43,6 +48,9 @@ class CallingConvEmitter {
   void emitCallingConv(const Record *CC, raw_ostream &O);
   void emitAction(const Record *Action, indent Indent, raw_ostream &O);
   void emitArgRegisterLists(raw_ostream &O);
+
+  StringMap<const CodeGenRegister *> RegistersByDefName;
+  std::string getQualifiedRegisterName(const Init *I);
 };
 } // End anonymous namespace
 
@@ -125,6 +133,20 @@ void CallingConvEmitter::emitCallingConv(const Record *CC, raw_ostream &O) {
   O << "}\n";
 }
 
+// Return the name of the specified Init (DefInit or StringInit), with a
+// namespace qualifier if the corresponding record contains one.
+std::string CallingConvEmitter::getQualifiedRegisterName(const Init *I) {
+  if (const auto *DI = dyn_cast<DefInit>(I))
+    return getQualifiedName(DI->getDef());
+
+  const auto *SI = cast<StringInit>(I);
+  if (const CodeGenRegister *CGR = RegistersByDefName.lookup(SI->getValue()))
+    return getQualifiedName(CGR->TheDef);
+
+  PrintFatalError("register not defined: " + SI->getAsString());
+  return "";
+}
+
 void CallingConvEmitter::emitAction(const Record *Action, indent Indent,
                                     raw_ostream &O) {
 
@@ -133,7 +155,7 @@ void CallingConvEmitter::emitAction(const Record *Action, indent Indent,
     O << Indent << "  ";
     ListSeparator LS;
     for (const Init *V : RL->getValues())
-      O << LS << getQualifiedName(cast<DefInit>(V)->getDef());
+      O << LS << getQualifiedRegisterName(V);
     O << "\n" << Indent << "};\n";
   };
 
@@ -142,7 +164,7 @@ void CallingConvEmitter::emitAction(const Record *Action, indent Indent,
     SmallVector<std::string> Parms;
     if (RegLists[0]->size() == 1) {
       for (const ListInit *LI : RegLists)
-        Parms.push_back(getQualifiedName(LI->getElementAsRecord(0)));
+        Parms.push_back(getQualifiedRegisterName(LI->getElement(0)));
     } else {
       for (const std::string &S : RLNames)
         Parms.push_back(S + utostr(++Counter));
@@ -207,10 +229,11 @@ void CallingConvEmitter::emitAction(const Record *Action, indent Indent,
         << Indent + 2 << "return false;\n";
       DelegateToMap[CurrentAction].insert(CC->getName().str());
     } else if (Action->isSubClassOf("CCAssignToReg") ||
+               Action->isSubClassOf("CCAssignToRegTuple") ||
                Action->isSubClassOf("CCAssignToRegAndStack")) {
       const ListInit *RegList = Action->getValueAsListInit("RegList");
       for (unsigned I = 0, E = RegList->size(); I != E; ++I) {
-        std::string Name = getQualifiedName(RegList->getElementAsRecord(I));
+        std::string Name = getQualifiedRegisterName(RegList->getElement(I));
         if (SwiftAction)
           AssignedSwiftRegsMap[CurrentAction].insert(std::move(Name));
         else


        


More information about the llvm-commits mailing list