[llvm] d393d0d - [TableGen] Emit table mapping physical registers to base classes

Carl Ritson via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 19 22:46:30 PST 2022


Author: Carl Ritson
Date: 2022-12-20T15:22:28+09:00
New Revision: d393d0d24239aedfd3c8166e7dc188f360104cac

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

LOG: [TableGen] Emit table mapping physical registers to base classes

Allow targets to define a mapping from registers to register
classes such that each register has exactly one base class.
As registers may be in multiple register classes the base class
is determined by the container class with the lowest BaseClassOrder.

Only register classes with BaseClassOrder set are considered
when determining the base classes.  By default BaseClassOrder is
unset in RegisterClass so no code is generated unless a target
explicit defines one or more base register classes.

Reviewed By: arsenm, foad

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

Added: 
    llvm/test/TableGen/RegisterInfoEmitter-BaseClassOrder.td

Modified: 
    llvm/include/llvm/CodeGen/TargetRegisterInfo.h
    llvm/include/llvm/Target/Target.td
    llvm/utils/TableGen/CodeGenRegisters.h
    llvm/utils/TableGen/RegisterInfoEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 0ab88b360213..77d5d0574f98 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -693,6 +693,14 @@ class TargetRegisterInfo : public MCRegisterInfo {
   static void dumpReg(Register Reg, unsigned SubRegIndex = 0,
                       const TargetRegisterInfo *TRI = nullptr);
 
+  /// Return target defined base register class for a physical register.
+  /// This is the register class with the lowest BaseClassOrder containing the
+  /// register.
+  /// Will be nullptr if the register is not in any base register class.
+  virtual const TargetRegisterClass *getPhysRegBaseClass(MCRegister Reg) const {
+    return nullptr;
+  }
+
 protected:
   /// Overridden by TableGen in targets that have sub-registers.
   virtual unsigned composeSubRegIndicesImpl(unsigned, unsigned) const {

diff  --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index dd74c89a6360..5e3311323eaf 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -318,6 +318,12 @@ class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
 
   // Target-specific flags. This becomes the TSFlags field in TargetRegisterClass.
   bits<8> TSFlags = 0;
+
+  // If set then consider this register class to be the base class for registers in
+  // its MemberList.  The base class for registers present in multiple base register
+  // classes will be resolved in the order defined by this value, with lower values
+  // taking precedence over higher ones.  Ties are resolved by enumeration order.
+  int BaseClassOrder = ?;
 }
 
 // The memberList in a RegisterClass is a dag of set operations. TableGen

diff  --git a/llvm/test/TableGen/RegisterInfoEmitter-BaseClassOrder.td b/llvm/test/TableGen/RegisterInfoEmitter-BaseClassOrder.td
new file mode 100644
index 000000000000..79c25e9e4aaa
--- /dev/null
+++ b/llvm/test/TableGen/RegisterInfoEmitter-BaseClassOrder.td
@@ -0,0 +1,38 @@
+// RUN: llvm-tblgen -gen-register-info -I %p/../../include -I %p/Common %s | FileCheck %s
+
+include "llvm/Target/Target.td"
+
+let Namespace = "MyTarget" in {
+  def R0 : Register<"r0">; // base class BaseA
+  def R1 : Register<"r1">; // base class BaseA
+  def R2 : Register<"r2">; // base class BaseC
+  def R3 : Register<"r3">; // base class BaseC
+  def R4 : Register<"r4">; // base class BaseB
+  def R5 : Register<"r5">; // base class BaseB
+  def R6 : Register<"r6">; // no base class
+} // Namespace = "MyTarget"
+
+
+// BaseA and BaseB are equal ordered so enumeration order determines base class for overlaps
+def BaseA : RegisterClass<"MyTarget", [i32], 32, (sequence "R%u", 0, 3)> {
+  let BaseClassOrder = 1;
+}
+def BaseB : RegisterClass<"MyTarget", [i32], 32, (sequence "R%u", 3, 5)> {
+  let BaseClassOrder = 1;
+}
+
+// BaseC defined order overrides BaseA and BaseB
+def BaseC : RegisterClass<"MyTarget", [i32], 32, (sequence "R%u", 2, 3)> {
+  let BaseClassOrder = 0;
+}
+
+def MyTarget : Target;
+
+// CHECK: static const TargetRegisterClass *BaseClasses[4] = {
+// CHECK-NEXT:   nullptr,
+// CHECK-NEXT:   &MyTarget::BaseCRegClass,
+// CHECK-NEXT:   &MyTarget::BaseARegClass,
+// CHECK-NEXT:   &MyTarget::BaseBRegClass,
+// CHECK-NEXT: }
+// CHECK-NEXT: static const uint8_t Mapping[8] = {
+// CHECK-NEXT:   0,2,2,1,1,3,3,0, };

diff  --git a/llvm/utils/TableGen/CodeGenRegisters.h b/llvm/utils/TableGen/CodeGenRegisters.h
index 2c3ac18c1159..a2adc0630680 100644
--- a/llvm/utils/TableGen/CodeGenRegisters.h
+++ b/llvm/utils/TableGen/CodeGenRegisters.h
@@ -472,6 +472,13 @@ namespace llvm {
 
     // Called by CodeGenRegBank::CodeGenRegBank().
     static void computeSubClasses(CodeGenRegBank&);
+
+    // Get ordering value among register base classes.
+    std::optional<int> getBaseClassOrder() const {
+      if (TheDef && !TheDef->isValueUnset("BaseClassOrder"))
+        return TheDef->getValueAsInt("BaseClassOrder");
+      return {};
+    }
   };
 
   // Register categories are used when we need to deterine the category a

diff  --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
index aa4536a5575c..05022d70a9a5 100644
--- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
@@ -1195,10 +1195,14 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
      << "  bool isConstantPhysReg(MCRegister PhysReg) const override final;\n"
      << "  /// Devirtualized TargetFrameLowering.\n"
      << "  static const " << TargetName << "FrameLowering *getFrameLowering(\n"
-     << "      const MachineFunction &MF);\n"
-     << "};\n\n";
+     << "      const MachineFunction &MF);\n";
 
   const auto &RegisterClasses = RegBank.getRegClasses();
+  if (llvm::any_of(RegisterClasses, [](const auto &RC) { return RC.getBaseClassOrder(); })) {
+    OS << "  const TargetRegisterClass *getPhysRegBaseClass(MCRegister Reg) const override;\n";
+  }
+
+  OS << "};\n\n";
 
   if (!RegisterClasses.empty()) {
     OS << "namespace " << RegisterClasses.front().Namespace
@@ -1595,6 +1599,54 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
 
   EmitRegUnitPressure(OS, RegBank, ClassName);
 
+  // Emit register base class mapper
+  if (!RegisterClasses.empty()) {
+    // Collect base classes
+    SmallVector<const CodeGenRegisterClass*> BaseClasses;
+    for (const auto &RC : RegisterClasses) {
+      if (RC.getBaseClassOrder())
+        BaseClasses.push_back(&RC);
+    }
+    if (!BaseClasses.empty()) {
+      // Represent class indexes with uint8_t and allocate one index for nullptr
+      assert(BaseClasses.size() <= UINT8_MAX && "Too many base register classes");
+
+      // Apply order
+      struct BaseClassOrdering {
+        bool operator()(const CodeGenRegisterClass *LHS, const CodeGenRegisterClass *RHS) const {
+          return std::pair(*LHS->getBaseClassOrder(), LHS->EnumValue)
+               < std::pair(*RHS->getBaseClassOrder(), RHS->EnumValue);
+        }
+      };
+      llvm::stable_sort(BaseClasses, BaseClassOrdering());
+
+      // Build mapping for Regs (+1 for NoRegister)
+      std::vector<uint8_t> Mapping(Regs.size() + 1, 0);
+      for (int RCIdx = BaseClasses.size() - 1; RCIdx >= 0; --RCIdx) {
+        for (const auto Reg : BaseClasses[RCIdx]->getMembers())
+          Mapping[Reg->EnumValue] = RCIdx + 1;
+      }
+
+      OS << "\n// Register to base register class mapping\n\n";
+      OS << "\n";
+      OS << "const TargetRegisterClass *" << ClassName
+         << "::getPhysRegBaseClass(MCRegister Reg)"
+         << " const {\n";
+      OS << "  static const TargetRegisterClass *BaseClasses[" << (BaseClasses.size() + 1) << "] = {\n";
+      OS << "    nullptr,\n";
+      for (const auto RC : BaseClasses)
+        OS << "    &" << RC->getQualifiedName() << "RegClass,\n";
+      OS << "  };\n";
+      OS << "  static const uint8_t Mapping[" << Mapping.size() << "] = {\n    ";
+      for (const uint8_t Value : Mapping)
+        OS << (unsigned)Value << ",";
+      OS << "  };\n\n";
+      OS << "  assert(Reg < sizeof(Mapping));\n";
+      OS << "  return BaseClasses[Mapping[Reg]];\n";
+      OS << "}\n";
+    }
+  }
+
   // Emit the constructor of the class...
   OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n";
   OS << "extern const MCPhysReg " << TargetName << "RegDiffLists[];\n";


        


More information about the llvm-commits mailing list