mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
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. llvm-svn: 157650
This commit is contained in:
parent
cfa4538f05
commit
16603c4371
@ -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<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 @@ 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -162,10 +162,18 @@ namespace llvm {
|
||||
// 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 @@ 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]; }
|
||||
|
||||
|
@ -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<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 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
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 @@ 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<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 @@ 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)
|
||||
|
Loading…
Reference in New Issue
Block a user