forked from OSchip/llvm-project
Add a RegisterTuples class to Target.td and TableGen.
A RegisterTuples instance is used to synthesize super-registers by zipping together lists of sub-registers. This is useful for generating pseudo-registers representing register sequence constraints like 'two consecutive GPRs', or 'an even-odd pair of floating point registers'. The RegisterTuples def can be used in register set operations when building register classes. That is the only way of accessing the synthesized super-registers. For example, the ARM QQ register class of pseudo-registers could have been formed like this: // Form pairs Q0_Q1, Q2_Q3, ... def QQPairs : RegisterTuples<[qsub_0, qsub_1], [(decimate QPR, 2), (decimate (shl QPR, 1), 2)]>; def QQ : RegisterClass<..., (add QQPairs)>; Similarly, pseudo-registers representing '3 consecutive D-regs with wraparound' look like: // Form D0_D1_D2, D1_D2_D3, ..., D30_D31_D0, D31_D0_D1. def DSeqTriples : RegisterTuples<[dsub_0, dsub_1, dsub_2], [(rotl DPR, 0), (rotl DPR, 1), (rotl DPR, 2)]>; TableGen automatically computes aliasing information for the synthesized registers. Register tuples are still somewhat experimental. We still need to see how they interact with MC. llvm-svn: 133407
This commit is contained in:
parent
dceb0cf3f3
commit
3bd1b65ed3
|
@ -184,6 +184,43 @@ class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
|
|||
def sequence;
|
||||
def decimate;
|
||||
|
||||
// RegisterTuples - Automatically generate super-registers by forming tuples of
|
||||
// sub-registers. This is useful for modeling register sequence constraints
|
||||
// with pseudo-registers that are larger than the architectural registers.
|
||||
//
|
||||
// The sub-register lists are zipped together:
|
||||
//
|
||||
// def EvenOdd : RegisterTuples<[sube, subo], [(add R0, R2), (add R1, R3)]>;
|
||||
//
|
||||
// Generates the same registers as:
|
||||
//
|
||||
// let SubRegIndices = [sube, subo] in {
|
||||
// def R0_R1 : RegisterWithSubRegs<"", [R0, R1]>;
|
||||
// def R2_R3 : RegisterWithSubRegs<"", [R2, R3]>;
|
||||
// }
|
||||
//
|
||||
// The generated pseudo-registers inherit super-classes and fields from their
|
||||
// first sub-register. Most fields from the Register class are inferred, and
|
||||
// the AsmName and Dwarf numbers are cleared.
|
||||
//
|
||||
// RegisterTuples instances can be used in other set operations to form
|
||||
// register classes and so on. This is the only way of using the generated
|
||||
// registers.
|
||||
class RegisterTuples<list<SubRegIndex> Indices, list<dag> Regs> {
|
||||
// SubRegs - N lists of registers to be zipped up. Super-registers are
|
||||
// synthesized from the first element of each SubRegs list, the second
|
||||
// element and so on.
|
||||
list<dag> SubRegs = Regs;
|
||||
|
||||
// SubRegIndices - N SubRegIndex instances. This provides the names of the
|
||||
// sub-registers in the synthesized super-registers.
|
||||
list<SubRegIndex> SubRegIndices = Indices;
|
||||
|
||||
// Compose sub-register indices like in a normal Register.
|
||||
list<dag> CompositeIndices = [];
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DwarfRegNum - This class provides a mapping of the llvm register enumeration
|
||||
// to the register numbering used by gcc and gdb. These values are used by a
|
||||
|
|
|
@ -150,6 +150,104 @@ CodeGenRegister::addSubRegsPreOrder(SetVector<CodeGenRegister*> &OSet) const {
|
|||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// RegisterTuples
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// A RegisterTuples def is used to generate pseudo-registers from lists of
|
||||
// sub-registers. We provide a SetTheory expander class that returns the new
|
||||
// registers.
|
||||
namespace {
|
||||
struct TupleExpander : SetTheory::Expander {
|
||||
void expand(SetTheory &ST, Record *Def, SetTheory::RecSet &Elts) {
|
||||
std::vector<Record*> Indices = Def->getValueAsListOfDefs("SubRegIndices");
|
||||
unsigned Dim = Indices.size();
|
||||
ListInit *SubRegs = Def->getValueAsListInit("SubRegs");
|
||||
if (Dim != SubRegs->getSize())
|
||||
throw TGError(Def->getLoc(), "SubRegIndices and SubRegs size mismatch");
|
||||
if (Dim < 2)
|
||||
throw TGError(Def->getLoc(), "Tuples must have at least 2 sub-registers");
|
||||
|
||||
// Evaluate the sub-register lists to be zipped.
|
||||
unsigned Length = ~0u;
|
||||
SmallVector<SetTheory::RecSet, 4> Lists(Dim);
|
||||
for (unsigned i = 0; i != Dim; ++i) {
|
||||
ST.evaluate(SubRegs->getElement(i), Lists[i]);
|
||||
Length = std::min(Length, unsigned(Lists[i].size()));
|
||||
}
|
||||
|
||||
if (Length == 0)
|
||||
return;
|
||||
|
||||
// Precompute some types.
|
||||
Record *RegisterCl = Def->getRecords().getClass("Register");
|
||||
RecTy *RegisterRecTy = new RecordRecTy(RegisterCl);
|
||||
StringInit *BlankName = new StringInit("");
|
||||
|
||||
// Zip them up.
|
||||
for (unsigned n = 0; n != Length; ++n) {
|
||||
std::string Name;
|
||||
Record *Proto = Lists[0][n];
|
||||
std::vector<Init*> Tuple;
|
||||
unsigned CostPerUse = 0;
|
||||
for (unsigned i = 0; i != Dim; ++i) {
|
||||
Record *Reg = Lists[i][n];
|
||||
if (i) Name += '_';
|
||||
Name += Reg->getName();
|
||||
Tuple.push_back(new DefInit(Reg));
|
||||
CostPerUse = std::max(CostPerUse,
|
||||
unsigned(Reg->getValueAsInt("CostPerUse")));
|
||||
}
|
||||
|
||||
// Create a new Record representing the synthesized register. This record
|
||||
// is only for consumption by CodeGenRegister, it is not added to the
|
||||
// RecordKeeper.
|
||||
Record *NewReg = new Record(Name, Def->getLoc(), Def->getRecords());
|
||||
Elts.insert(NewReg);
|
||||
|
||||
// Copy Proto super-classes.
|
||||
for (unsigned i = 0, e = Proto->getSuperClasses().size(); i != e; ++i)
|
||||
NewReg->addSuperClass(Proto->getSuperClasses()[i]);
|
||||
|
||||
// Copy Proto fields.
|
||||
for (unsigned i = 0, e = Proto->getValues().size(); i != e; ++i) {
|
||||
RecordVal RV = Proto->getValues()[i];
|
||||
|
||||
// Replace the sub-register list with Tuple.
|
||||
if (RV.getName() == "SubRegs")
|
||||
RV.setValue(new ListInit(Tuple, RegisterRecTy));
|
||||
|
||||
// Provide a blank AsmName. MC hacks are required anyway.
|
||||
if (RV.getName() == "AsmName")
|
||||
RV.setValue(BlankName);
|
||||
|
||||
// CostPerUse is aggregated from all Tuple members.
|
||||
if (RV.getName() == "CostPerUse")
|
||||
RV.setValue(new IntInit(CostPerUse));
|
||||
|
||||
// Copy fields from the RegisterTuples def.
|
||||
if (RV.getName() == "SubRegIndices" ||
|
||||
RV.getName() == "CompositeIndices") {
|
||||
NewReg->addValue(*Def->getValue(RV.getName()));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Some fields get their default uninitialized value.
|
||||
if (RV.getName() == "DwarfNumbers" ||
|
||||
RV.getName() == "DwarfAlias" ||
|
||||
RV.getName() == "Aliases") {
|
||||
NewReg->addValue(*RegisterCl->getValue(RV.getName()));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Everything else is copied from Proto.
|
||||
NewReg->addValue(RV);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CodeGenRegisterClass
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -258,8 +356,9 @@ const std::string &CodeGenRegisterClass::getName() const {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) : Records(Records) {
|
||||
// Configure register Sets to understand register classes.
|
||||
// Configure register Sets to understand register classes and tuples.
|
||||
Sets.addFieldExpander("RegisterClass", "MemberList");
|
||||
Sets.addExpander("RegisterTuples", new TupleExpander());
|
||||
|
||||
// Read in the user-defined (named) sub-register indices.
|
||||
// More indices will be synthesized later.
|
||||
|
@ -275,6 +374,15 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) : Records(Records) {
|
|||
for (unsigned i = 0, e = Regs.size(); i != e; ++i)
|
||||
getReg(Regs[i]);
|
||||
|
||||
// Expand tuples and number the new registers.
|
||||
std::vector<Record*> Tups =
|
||||
Records.getAllDerivedDefinitions("RegisterTuples");
|
||||
for (unsigned i = 0, e = Tups.size(); i != e; ++i) {
|
||||
const std::vector<Record*> *TupRegs = Sets.expand(Tups[i]);
|
||||
for (unsigned j = 0, je = TupRegs->size(); j != je; ++j)
|
||||
getReg((*TupRegs)[j]);
|
||||
}
|
||||
|
||||
// Read in register class definitions.
|
||||
std::vector<Record*> RCs = Records.getAllDerivedDefinitions("RegisterClass");
|
||||
if (RCs.empty())
|
||||
|
|
Loading…
Reference in New Issue