diff --git a/include/llvm/MC/MCRegisterInfo.h b/include/llvm/MC/MCRegisterInfo.h index db4164ad2ad..60c385db6a0 100644 --- a/include/llvm/MC/MCRegisterInfo.h +++ b/include/llvm/MC/MCRegisterInfo.h @@ -110,6 +110,10 @@ struct MCRegisterDesc { 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 @@ private: 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 @@ private: const DwarfLLVMRegPair *EHDwarf2LRegs; // Dwarf to LLVM regs mapping EH DenseMap 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 @@ public: RAReg = RA; Classes = C; RegLists = RL; + DiffLists = DL; RegStrings = Strings; NumClasses = NC; + NumRegUnits = NRU; SubRegIndices = SubIndices; NumSubRegIndices = NumIndices; RegEncodingTable = RET; @@ -313,6 +372,13 @@ public: 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 @@ public: }; +//===----------------------------------------------------------------------===// +// 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 diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp index 2b064aa3073..887f01bdfa9 100644 --- a/utils/TableGen/CodeGenRegisters.cpp +++ b/utils/TableGen/CodeGenRegisters.cpp @@ -83,6 +83,7 @@ CodeGenRegister::CodeGenRegister(Record *R, unsigned Enum) EnumValue(Enum), CostPerUse(R->getValueAsInt("CostPerUse")), CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")), + NumNativeRegUnits(0), SubRegsComplete(false), SuperRegsComplete(false), TopoSig(~0u) @@ -397,6 +398,10 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { 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; } diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h index 30461523ec2..0c348c367e5 100644 --- a/utils/TableGen/CodeGenRegisters.h +++ b/utils/TableGen/CodeGenRegisters.h @@ -162,10 +162,18 @@ namespace llvm { // List of register units in ascending order. typedef SmallVector 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 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 @@ namespace llvm { return RUID < NumNativeRegUnits; } + unsigned getNumNativeRegUnits() const { + return NumNativeRegUnits; + }; + RegUnit &getRegUnit(unsigned RUID) { return RegUnits[RUID]; } const RegUnit &getRegUnit(unsigned RUID) const { return RegUnits[RUID]; } diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index 3d50a82b696..0d0c3251fac 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -454,6 +454,35 @@ static void printSubRegIndex(raw_ostream &OS, const CodeGenSubRegIndex *Idx) { 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 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 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 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, SmallVector OverlapLists(Regs.size()); SequenceToOffsetTable RegSeqs; + // Differentially encoded lists. + SequenceToOffsetTable DiffSeqs; + SmallVector RegUnitLists(Regs.size()); + SmallVector RegUnitInitScale(Regs.size()); + SequenceToOffsetTable RegStrings; // Precompute register lists for the SequenceToOffsetTable. @@ -516,10 +550,36 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, // 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 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 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, 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 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, 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 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, 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 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, << "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 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, // 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 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, << " 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)