[llvm-commits] [llvm] r157650 - in /llvm/trunk: include/llvm/MC/MCRegisterInfo.h utils/TableGen/CodeGenRegisters.cpp utils/TableGen/CodeGenRegisters.h utils/TableGen/RegisterInfoEmitter.cpp

Jakob Stoklund Olesen stoklund at 2pi.dk
Tue May 29 16:40:00 PDT 2012


Author: stoklund
Date: Tue May 29 18:40:00 2012
New Revision: 157650

URL: http://llvm.org/viewvc/llvm-project?rev=157650&view=rev
Log:
Emit register unit lists for each register.

Register units are already used internally in TableGen to compute
register pressure sets and overlapping registers. This patch makes them
available to the code generators.

The register unit lists are differentially encoded so they can be reused
for many related registers. This keeps the total size of the lists below
200 bytes for most targets. ARM has the largest table at 560 bytes.

Add an MCRegUnitIterator for traversing the register unit lists. It
provides an abstract interface so the representation can be changed in
the future without changing all clients.

Modified:
    llvm/trunk/include/llvm/MC/MCRegisterInfo.h
    llvm/trunk/utils/TableGen/CodeGenRegisters.cpp
    llvm/trunk/utils/TableGen/CodeGenRegisters.h
    llvm/trunk/utils/TableGen/RegisterInfoEmitter.cpp

Modified: llvm/trunk/include/llvm/MC/MCRegisterInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCRegisterInfo.h?rev=157650&r1=157649&r2=157650&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCRegisterInfo.h (original)
+++ llvm/trunk/include/llvm/MC/MCRegisterInfo.h Tue May 29 18:40:00 2012
@@ -110,6 +110,10 @@
   uint32_t Overlaps;  // Overlapping registers, described above
   uint32_t SubRegs;   // Sub-register set, described above
   uint32_t SuperRegs; // Super-register set, described above
+
+  // RegUnits - Points to the list of register units. The low 4 bits holds the
+  // Scale, the high bits hold an offset into DiffLists. See MCRegUnitIterator.
+  uint32_t RegUnits;
 };
 
 /// MCRegisterInfo base class - We assume that the target defines a static
@@ -142,7 +146,9 @@
   unsigned RAReg;                             // Return address register
   const MCRegisterClass *Classes;             // Pointer to the regclass array
   unsigned NumClasses;                        // Number of entries in the array
+  unsigned NumRegUnits;                       // Number of regunits.
   const uint16_t *RegLists;                   // Pointer to the reglists array
+  const uint16_t *DiffLists;                  // Pointer to the difflists array
   const char *RegStrings;                     // Pointer to the string table.
   const uint16_t *SubRegIndices;              // Pointer to the subreg lookup
                                               // array.
@@ -160,12 +166,63 @@
   const DwarfLLVMRegPair *EHDwarf2LRegs;      // Dwarf to LLVM regs mapping EH
   DenseMap<unsigned, int> L2SEHRegs;          // LLVM to SEH regs mapping
 
+  /// DiffListIterator - Base iterator class that can traverse the
+  /// differentially encoded register and regunit lists in DiffLists.
+  /// Don't use this class directly, use one of the specialized sub-classes
+  /// defined below.
+  class DiffListIterator {
+    uint16_t Val;
+    const uint16_t *List;
+
+  protected:
+    /// Create an invalid iterator. Call init() to point to something useful.
+    DiffListIterator() : Val(0), List(0) {}
+
+    /// init - Point the iterator to InitVal, decoding subsequent values from
+    /// DiffList. The iterator will initially point to InitVal, sub-classes are
+    /// responsible for skipping the seed value if it is not part of the list.
+    void init(uint16_t InitVal, const uint16_t *DiffList) {
+      Val = InitVal;
+      List = DiffList;
+    }
+
+    /// advance - Move to the next list position, return the applied
+    /// differential. This function does not detect the end of the list, that
+    /// is the caller's responsibility (by checking for a 0 return value).
+    unsigned advance() {
+      assert(isValid() && "Cannot move off the end of the list.");
+      uint16_t D = *List++;
+      Val += D;
+      return D;
+    }
+
+  public:
+
+    /// isValid - returns true if this iterator is not yet at the end.
+    bool isValid() const { return List; }
+
+    /// Dereference the iterator to get the value at the current position.
+    unsigned operator*() const { return Val; }
+
+    /// Pre-increment to move to the next position.
+    void operator++() {
+      // The end of the list is encoded as a 0 differential.
+      if (!advance())
+        List = 0;
+    }
+  };
+
+  // These iterators are allowed to sub-class DiffListIterator and access
+  // internal list pointers.
+  friend class MCRegUnitIterator;
+
 public:
   /// InitMCRegisterInfo - Initialize MCRegisterInfo, called by TableGen
   /// auto-generated routines. *DO NOT USE*.
   void InitMCRegisterInfo(const MCRegisterDesc *D, unsigned NR, unsigned RA,
-                          const MCRegisterClass *C, unsigned NC,
+                          const MCRegisterClass *C, unsigned NC, unsigned NRU,
                           const uint16_t *RL,
+                          const uint16_t *DL,
                           const char *Strings,
                           const uint16_t *SubIndices,
                           unsigned NumIndices,
@@ -175,8 +232,10 @@
     RAReg = RA;
     Classes = C;
     RegLists = RL;
+    DiffLists = DL;
     RegStrings = Strings;
     NumClasses = NC;
+    NumRegUnits = NRU;
     SubRegIndices = SubIndices;
     NumSubRegIndices = NumIndices;
     RegEncodingTable = RET;
@@ -313,6 +372,13 @@
     return NumRegs;
   }
 
+  /// getNumRegUnits - Return the number of (native) register units in the
+  /// target. Register units are numbered from 0 to getNumRegUnits() - 1. They
+  /// can be accessed through MCRegUnitIterator defined below.
+  unsigned getNumRegUnits() const {
+    return NumRegUnits;
+  }
+
   /// getDwarfRegNum - Map a target register to an equivalent dwarf register
   /// number.  Returns -1 if there is no equivalent value.  The second
   /// parameter allows targets to use different numberings for EH info and
@@ -371,6 +437,42 @@
 
 };
 
+//===----------------------------------------------------------------------===//
+//                               Register Units
+//===----------------------------------------------------------------------===//
+
+// Register units are used to compute register aliasing. Every register has at
+// least one register unit, but it can have more. Two registers overlap if and
+// only if they have a common register unit.
+//
+// A target with a complicated sub-register structure will typically have many
+// fewer register units than actual registers. MCRI::getNumRegUnits() returns
+// the number of register units in the target.
+
+// MCRegUnitIterator enumerates a list of register units for Reg. The list is
+// in ascending numerical order.
+class MCRegUnitIterator : public MCRegisterInfo::DiffListIterator {
+public:
+  /// MCRegUnitIterator - Create an iterator that traverses the register units
+  /// in Reg.
+  MCRegUnitIterator(unsigned Reg, const MCRegisterInfo *MCRI) {
+    // Decode the RegUnits MCRegisterDesc field.
+    unsigned RU = MCRI->get(Reg).RegUnits;
+    unsigned Scale = RU & 15;
+    unsigned Offset = RU >> 4;
+
+    // Initialize the iterator to Reg * Scale, and the List pointer to
+    // DiffLists + Offset.
+    init(Reg * Scale, MCRI->DiffLists + Offset);
+
+    // That may not be a valid unit, we need to advance by one to get the real
+    // unit number. The first differential can be 0 which would normally
+    // terminate the list, but since we know every register has at least one
+    // unit, we can allow a 0 differential here.
+    advance();
+  }
+};
+
 } // End llvm namespace
 
 #endif

Modified: llvm/trunk/utils/TableGen/CodeGenRegisters.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeGenRegisters.cpp?rev=157650&r1=157649&r2=157650&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/CodeGenRegisters.cpp (original)
+++ llvm/trunk/utils/TableGen/CodeGenRegisters.cpp Tue May 29 18:40:00 2012
@@ -83,6 +83,7 @@
     EnumValue(Enum),
     CostPerUse(R->getValueAsInt("CostPerUse")),
     CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")),
+    NumNativeRegUnits(0),
     SubRegsComplete(false),
     SuperRegsComplete(false),
     TopoSig(~0u)
@@ -397,6 +398,10 @@
   if (RegUnits.empty())
     RegUnits.push_back(RegBank.newRegUnit(this));
 
+  // We have now computed the native register units. More may be adopted later
+  // for balancing purposes.
+  NumNativeRegUnits = RegUnits.size();
+
   return SubRegs;
 }
 

Modified: llvm/trunk/utils/TableGen/CodeGenRegisters.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeGenRegisters.h?rev=157650&r1=157649&r2=157650&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/CodeGenRegisters.h (original)
+++ llvm/trunk/utils/TableGen/CodeGenRegisters.h Tue May 29 18:40:00 2012
@@ -162,10 +162,18 @@
     // List of register units in ascending order.
     typedef SmallVector<unsigned, 16> RegUnitList;
 
+    // How many entries in RegUnitList are native?
+    unsigned NumNativeRegUnits;
+
     // Get the list of register units.
-    // This is only valid after getSubRegs() completes.
+    // This is only valid after computeSubRegs() completes.
     const RegUnitList &getRegUnits() const { return RegUnits; }
 
+    // Get the native register units. This is a prefix of getRegUnits().
+    ArrayRef<unsigned> getNativeRegUnits() const {
+      return makeArrayRef(RegUnits).slice(0, NumNativeRegUnits);
+    }
+
     // Inherit register units from subregisters.
     // Return true if the RegUnits changed.
     bool inheritRegUnits(CodeGenRegBank &RegBank);
@@ -554,6 +562,10 @@
       return RUID < NumNativeRegUnits;
     }
 
+    unsigned getNumNativeRegUnits() const {
+      return NumNativeRegUnits;
+    };
+
     RegUnit &getRegUnit(unsigned RUID) { return RegUnits[RUID]; }
     const RegUnit &getRegUnit(unsigned RUID) const { return RegUnits[RUID]; }
 

Modified: llvm/trunk/utils/TableGen/RegisterInfoEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/RegisterInfoEmitter.cpp?rev=157650&r1=157649&r2=157650&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/RegisterInfoEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/RegisterInfoEmitter.cpp Tue May 29 18:40:00 2012
@@ -454,6 +454,35 @@
   OS << Idx->getQualifiedName();
 }
 
+// Differentially encoded register and regunit lists allow for better
+// compression on regular register banks. The sequence is computed from the
+// differential list as:
+//
+//   out[0] = InitVal;
+//   out[n+1] = out[n] + diff[n]; // n = 0, 1, ...
+//
+// The initial value depends on the specific list. The list is terminated by a
+// 0 differential which means we can't encode repeated elements.
+
+typedef SmallVector<uint16_t, 4> DiffVec;
+
+// Differentially encode a sequence of numbers into V. The starting value and
+// terminating 0 are not added to V, so it will have the same size as List.
+DiffVec &diffEncode(DiffVec &V, unsigned InitVal, ArrayRef<unsigned> List) {
+  assert(V.empty() && "Clear DiffVec before diffEncode.");
+  uint16_t Val = uint16_t(InitVal);
+  for (unsigned i = 0; i != List.size(); ++i) {
+    uint16_t Cur = List[i];
+    V.push_back(Cur - Val);
+    Val = Cur;
+  }
+  return V;
+}
+
+static void printDiff16(raw_ostream &OS, uint16_t Val) {
+  OS << SignExtend32<16>(Val);
+}
+
 //
 // runMCDesc - Print out MC register descriptions.
 //
@@ -474,6 +503,11 @@
   SmallVector<RegVec, 4> OverlapLists(Regs.size());
   SequenceToOffsetTable<RegVec, CodeGenRegister::Less> RegSeqs;
 
+  // Differentially encoded lists.
+  SequenceToOffsetTable<DiffVec> DiffSeqs;
+  SmallVector<DiffVec, 4> RegUnitLists(Regs.size());
+  SmallVector<unsigned, 4> RegUnitInitScale(Regs.size());
+
   SequenceToOffsetTable<std::string> RegStrings;
 
   // Precompute register lists for the SequenceToOffsetTable.
@@ -516,10 +550,36 @@
     // Finally, Suffix itself.
     OverlapList.insert(OverlapList.end(), Suffix.begin(), Suffix.end());
     RegSeqs.add(OverlapList);
+
+    // Differentially encode the register unit list, seeded by register number.
+    // First compute a scale factor that allows more diff-lists to be reused:
+    //
+    //   D0 -> (S0, S1)
+    //   D1 -> (S2, S3)
+    //
+    // A scale factor of 2 allows D0 and D1 to share a diff-list. The initial
+    // value for the differential decoder is the register number multiplied by
+    // the scale.
+    //
+    // Check the neighboring registers for arithmetic progressions.
+    unsigned ScaleA = ~0u, ScaleB = ~0u;
+    ArrayRef<unsigned> RUs = Reg->getNativeRegUnits();
+    if (i > 0 && Regs[i-1]->getNativeRegUnits().size() == RUs.size())
+      ScaleB = RUs.front() - Regs[i-1]->getNativeRegUnits().front();
+    if (i+1 != Regs.size() &&
+        Regs[i+1]->getNativeRegUnits().size() == RUs.size())
+      ScaleA = Regs[i+1]->getNativeRegUnits().front() - RUs.front();
+    unsigned Scale = std::min(ScaleB, ScaleA);
+    // Default the scale to 0 if it can't be encoded in 4 bits.
+    if (Scale >= 16)
+      Scale = 0;
+    RegUnitInitScale[i] = Scale;
+    DiffSeqs.add(diffEncode(RegUnitLists[i], Scale * Reg->EnumValue, RUs));
   }
 
   // Compute the final layout of the sequence table.
   RegSeqs.layout();
+  DiffSeqs.layout();
 
   OS << "namespace llvm {\n\n";
 
@@ -530,6 +590,11 @@
   RegSeqs.emit(OS, printRegister);
   OS << "};\n\n";
 
+  // Emit the shared table of differential lists.
+  OS << "extern const uint16_t " << TargetName << "RegDiffLists[] = {\n";
+  DiffSeqs.emit(OS, printDiff16);
+  OS << "};\n\n";
+
   // Emit the string table.
   RegStrings.layout();
   OS << "extern const char " << TargetName << "RegStrings[] = {\n";
@@ -538,7 +603,7 @@
 
   OS << "extern const MCRegisterDesc " << TargetName
      << "RegDesc[] = { // Descriptors\n";
-  OS << "  { " << RegStrings.get("") << ", 0, 0, 0 },\n";
+  OS << "  { " << RegStrings.get("") << ", 0, 0, 0, 0 },\n";
 
   // Emit the register descriptors now.
   for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
@@ -546,7 +611,8 @@
     OS << "  { " << RegStrings.get(Reg->getName()) << ", "
        << RegSeqs.get(OverlapLists[i]) << ", "
        << RegSeqs.get(SubRegLists[i]) << ", "
-       << RegSeqs.get(Reg->getSuperRegs()) << " },\n";
+       << RegSeqs.get(Reg->getSuperRegs()) << ", "
+       << (DiffSeqs.get(RegUnitLists[i])*16 + RegUnitInitScale[i]) << " },\n";
   }
   OS << "};\n\n";      // End of register descriptors...
 
@@ -668,7 +734,10 @@
      << "unsigned DwarfFlavour = 0, unsigned EHFlavour = 0) {\n";
   OS << "  RI->InitMCRegisterInfo(" << TargetName << "RegDesc, "
      << Regs.size()+1 << ", RA, " << TargetName << "MCRegisterClasses, "
-     << RegisterClasses.size() << ", " << TargetName << "RegLists, "
+     << RegisterClasses.size() << ", "
+     << RegBank.getNumNativeRegUnits() << ", "
+     << TargetName << "RegLists, "
+     << TargetName << "RegDiffLists, "
      << TargetName << "RegStrings, ";
   if (SubRegIndices.size() != 0)
     OS << "(uint16_t*)" << TargetName << "SubRegTable, "
@@ -1027,6 +1096,7 @@
   // Emit the constructor of the class...
   OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n";
   OS << "extern const uint16_t " << TargetName << "RegLists[];\n";
+  OS << "extern const uint16_t " << TargetName << "RegDiffLists[];\n";
   OS << "extern const char " << TargetName << "RegStrings[];\n";
   if (SubRegIndices.size() != 0)
     OS << "extern const uint16_t *get" << TargetName
@@ -1043,7 +1113,9 @@
      << "  InitMCRegisterInfo(" << TargetName << "RegDesc, "
      << Regs.size()+1 << ", RA,\n                     " << TargetName
      << "MCRegisterClasses, " << RegisterClasses.size() << ",\n"
+     << "                     " << RegBank.getNumNativeRegUnits() << ",\n"
      << "                     " << TargetName << "RegLists,\n"
+     << "                     " << TargetName << "RegDiffLists,\n"
      << "                     " << TargetName << "RegStrings,\n"
      << "                     ";
   if (SubRegIndices.size() != 0)





More information about the llvm-commits mailing list