diff --git a/include/llvm/Target/Target.td b/include/llvm/Target/Target.td index 616087cd14d..915879202ca 100644 --- a/include/llvm/Target/Target.td +++ b/include/llvm/Target/Target.td @@ -138,6 +138,22 @@ class RegisterClass regTypes, int alignment, // overload virtual methods. code MethodProtos = [{}]; code MethodBodies = [{}]; + + // AltOrders - List of alternative allocation orders. The default order is + // MemberList itself, and that is good enough for most targets since the + // register allocators automatically remove reserved registers and move + // callee-saved registers to the end. + list AltOrders = []; + + // AltOrderSelect - The body of a function that selects the allocation order + // to use in a given machine function. The code will be inserted in a + // function like this: + // + // static inline unsigned f(const MachineFunction &MF) { ... } + // + // The function should return 0 to select the default order defined by + // MemberList, 1 to select the first AltOrders entry and so on. + code AltOrderSelect = [{}]; } // The memberList in a RegisterClass is a dag of set operations. TableGen diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp index 37952fc36af..6b877826f46 100644 --- a/utils/TableGen/CodeGenRegisters.cpp +++ b/utils/TableGen/CodeGenRegisters.cpp @@ -172,10 +172,28 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) } assert(!VTs.empty() && "RegisterClass must contain at least one ValueType!"); + // Default allocation order always contains all registers. Elements = RegBank.getSets().expand(R); for (unsigned i = 0, e = Elements->size(); i != e; ++i) Members.insert(RegBank.getReg((*Elements)[i])); + // Alternative allocation orders may be subsets. + ListInit *Alts = R->getValueAsListInit("AltOrders"); + AltOrders.resize(Alts->size()); + SetTheory::RecSet Order; + for (unsigned i = 0, e = Alts->size(); i != e; ++i) { + RegBank.getSets().evaluate(Alts->getElement(i), Order); + AltOrders[i].append(Order.begin(), Order.end()); + // Verify that all altorder members are regclass members. + while (!Order.empty()) { + CodeGenRegister *Reg = RegBank.getReg(Order.back()); + Order.pop_back(); + if (!contains(Reg)) + throw TGError(R->getLoc(), " AltOrder register " + Reg->getName() + + " is not a class member"); + } + } + // SubRegClasses is a list containing (RC, subregindex, ...) dags. ListInit *SRC = R->getValueAsListInit("SubRegClasses"); for (ListInit::const_iterator i = SRC->begin(), e = SRC->end(); i != e; ++i) { @@ -209,6 +227,7 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) Allocatable = R->getValueAsBit("isAllocatable"); MethodBodies = R->getValueAsCode("MethodBodies"); MethodProtos = R->getValueAsCode("MethodProtos"); + AltOrderSelect = R->getValueAsCode("AltOrderSelect"); } bool CodeGenRegisterClass::contains(const CodeGenRegister *Reg) const { diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h index 55f0b9b3aa7..5e3d5e59c11 100644 --- a/utils/TableGen/CodeGenRegisters.h +++ b/utils/TableGen/CodeGenRegisters.h @@ -86,6 +86,7 @@ namespace llvm { class CodeGenRegisterClass { CodeGenRegister::Set Members; const std::vector *Elements; + std::vector > AltOrders; public: Record *TheDef; std::string Namespace; @@ -96,7 +97,7 @@ namespace llvm { bool Allocatable; // Map SubRegIndex -> RegisterClass DenseMap SubRegClasses; - std::string MethodProtos, MethodBodies; + std::string MethodProtos, MethodBodies, AltOrderSelect; const std::string &getName() const; const std::vector &getValueTypes() const {return VTs;} @@ -125,10 +126,17 @@ namespace llvm { // Returns an ordered list of class members. // The order of registers is the same as in the .td file. - ArrayRef getOrder() const { - return *Elements; + // No = 0 is the default allocation order, No = 1 is the first alternative. + ArrayRef getOrder(unsigned No = 0) const { + if (No == 0) + return *Elements; + else + return AltOrders[No - 1]; } + // Return the total number of allocation orders available. + unsigned getNumOrders() const { return 1 + AltOrders.size(); } + CodeGenRegisterClass(CodeGenRegBank&, Record *R); }; diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index 9ffb66a4522..bcdde342c02 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -108,12 +108,16 @@ void RegisterInfoEmitter::runHeader(raw_ostream &OS) { OS << "\n };\n\n"; for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) { - const std::string &Name = RegisterClasses[i].getName(); + const CodeGenRegisterClass &RC = RegisterClasses[i]; + const std::string &Name = RC.getName(); // Output the register class definition. OS << " struct " << Name << "Class : public TargetRegisterClass {\n" - << " " << Name << "Class();\n" - << RegisterClasses[i].MethodProtos << " };\n"; + << " " << Name << "Class();\n"; + if (!RC.AltOrderSelect.empty()) + OS << " ArrayRef " + "getRawAllocationOrder(const MachineFunction&) const;\n"; + OS << RC.MethodProtos << " };\n"; // Output the extern for the instance. OS << " extern " << Name << "Class\t" << Name << "RegClass;\n"; @@ -349,7 +353,7 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { OS << "\n };\n\n"; } - + // Emit methods. for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) { const CodeGenRegisterClass &RC = RegisterClasses[i]; OS << RC.MethodBodies << "\n"; @@ -371,6 +375,27 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { << RC.getName() << ", " << RC.getName() << " + " << RC.getOrder().size() << ") {}\n"; + if (!RC.AltOrderSelect.empty()) { + OS << "\nstatic inline unsigned " << RC.getName() + << "AltOrderSelect(const MachineFunction &MF) {" + << RC.AltOrderSelect << "}\n\nArrayRef " + << RC.getName() << "Class::" + << "getRawAllocationOrder(const MachineFunction &MF) const {\n"; + for (unsigned oi = 1 , oe = RC.getNumOrders(); oi != oe; ++oi) { + ArrayRef Elems = RC.getOrder(oi); + OS << " static const unsigned AltOrder" << oi << "[] = {"; + for (unsigned elem = 0; elem != Elems.size(); ++elem) + OS << (elem ? ", " : " ") << getQualifiedName(Elems[elem]); + OS << " };\n"; + } + OS << " static const ArrayRef Order[] = {\n" + << " ArrayRef(" << RC.getName(); + for (unsigned oi = 1, oe = RC.getNumOrders(); oi != oe; ++oi) + OS << "),\n ArrayRef(AltOrder" << oi; + OS << ")\n };\n const unsigned Select = " << RC.getName() + << "AltOrderSelect(MF);\n assert(Select < " << RC.getNumOrders() + << ");\n return Order[Select];\n}\n"; + } } OS << "}\n";