forked from OSchip/llvm-project
Add support for alternative register names, useful for instructions whose operands are logically equivalent to existing registers, but happen to be printed specially. For example, an instruciton that prints d0[0] instead of s0.
Patch by Jim Grosbach. llvm-svn: 133940
This commit is contained in:
parent
0ceb5473a3
commit
a84be6c96b
|
@ -26,11 +26,19 @@ class SubRegIndex {
|
||||||
string Namespace = "";
|
string Namespace = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegAltNameIndex - The alternate name set to use for register operands of
|
||||||
|
// this register class when printing.
|
||||||
|
class RegAltNameIndex {
|
||||||
|
string Namespace = "";
|
||||||
|
}
|
||||||
|
def NoRegAltName : RegAltNameIndex;
|
||||||
|
|
||||||
// Register - You should define one instance of this class for each register
|
// Register - You should define one instance of this class for each register
|
||||||
// in the target machine. String n will become the "name" of the register.
|
// in the target machine. String n will become the "name" of the register.
|
||||||
class Register<string n> {
|
class Register<string n, list<string> altNames = []> {
|
||||||
string Namespace = "";
|
string Namespace = "";
|
||||||
string AsmName = n;
|
string AsmName = n;
|
||||||
|
list<string> AltNames = altNames;
|
||||||
|
|
||||||
// Aliases - A list of registers that this register overlaps with. A read or
|
// Aliases - A list of registers that this register overlaps with. A read or
|
||||||
// modification of this register can potentially read or modify the aliased
|
// modification of this register can potentially read or modify the aliased
|
||||||
|
@ -48,6 +56,10 @@ class Register<string n> {
|
||||||
// SubRegs.
|
// SubRegs.
|
||||||
list<SubRegIndex> SubRegIndices = [];
|
list<SubRegIndex> SubRegIndices = [];
|
||||||
|
|
||||||
|
// RegAltNameIndices - The alternate name indices which are valid for this
|
||||||
|
// register.
|
||||||
|
list<RegAltNameIndex> RegAltNameIndices = [];
|
||||||
|
|
||||||
// CompositeIndices - Specify subreg indices that don't correspond directly to
|
// CompositeIndices - Specify subreg indices that don't correspond directly to
|
||||||
// a register in SubRegs and are not inherited. The following formats are
|
// a register in SubRegs and are not inherited. The following formats are
|
||||||
// supported:
|
// supported:
|
||||||
|
@ -92,7 +104,7 @@ class RegisterWithSubRegs<string n, list<Register> subregs> : Register<n> {
|
||||||
// registers by register allocators.
|
// registers by register allocators.
|
||||||
//
|
//
|
||||||
class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
|
class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
|
||||||
dag regList> {
|
dag regList, RegAltNameIndex idx = NoRegAltName> {
|
||||||
string Namespace = namespace;
|
string Namespace = namespace;
|
||||||
|
|
||||||
// RegType - Specify the list ValueType of the registers in this register
|
// RegType - Specify the list ValueType of the registers in this register
|
||||||
|
@ -124,6 +136,11 @@ class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
|
||||||
//
|
//
|
||||||
dag MemberList = regList;
|
dag MemberList = regList;
|
||||||
|
|
||||||
|
// AltNameIndex - The alternate register name to use when printing operands
|
||||||
|
// of this register class. Every register in the register class must have
|
||||||
|
// a valid alternate name for the given index.
|
||||||
|
RegAltNameIndex altNameIndex = idx;
|
||||||
|
|
||||||
// SubRegClasses - Specify the register class of subregisters as a list of
|
// SubRegClasses - Specify the register class of subregisters as a list of
|
||||||
// dags: (RegClass SubRegIndex, SubRegindex, ...)
|
// dags: (RegClass SubRegIndex, SubRegindex, ...)
|
||||||
list<dag> SubRegClasses = [];
|
list<dag> SubRegClasses = [];
|
||||||
|
@ -466,6 +483,24 @@ class Operand<ValueType ty> {
|
||||||
AsmOperandClass ParserMatchClass = ImmAsmOperand;
|
AsmOperandClass ParserMatchClass = ImmAsmOperand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RegisterOperand<RegisterClass regclass, string pm = "printOperand"> {
|
||||||
|
// RegClass - The register class of the operand.
|
||||||
|
RegisterClass RegClass = regclass;
|
||||||
|
// PrintMethod - The target method to call to print register operands of
|
||||||
|
// this type. The method normally will just use an alt-name index to look
|
||||||
|
// up the name to print. Default to the generic printOperand().
|
||||||
|
string PrintMethod = pm;
|
||||||
|
// ParserMatchClass - The "match class" that operands of this type fit
|
||||||
|
// in. Match classes are used to define the order in which instructions are
|
||||||
|
// match, to ensure that which instructions gets matched is deterministic.
|
||||||
|
//
|
||||||
|
// The target specific parser must be able to classify an parsed operand into
|
||||||
|
// a unique class, which does not partially overlap with any other classes. It
|
||||||
|
// can match a subset of some other class, in which case the AsmOperandClass
|
||||||
|
// should declare the other operand as one of its super classes.
|
||||||
|
AsmOperandClass ParserMatchClass;
|
||||||
|
}
|
||||||
|
|
||||||
def i1imm : Operand<i1>;
|
def i1imm : Operand<i1>;
|
||||||
def i8imm : Operand<i8>;
|
def i8imm : Operand<i8>;
|
||||||
def i16imm : Operand<i16>;
|
def i16imm : Operand<i16>;
|
||||||
|
|
|
@ -871,6 +871,31 @@ AsmMatcherInfo::getOperandClass(const CGIOperandList::OperandInfo &OI,
|
||||||
if (SubOpIdx != -1)
|
if (SubOpIdx != -1)
|
||||||
Rec = dynamic_cast<DefInit*>(OI.MIOperandInfo->getArg(SubOpIdx))->getDef();
|
Rec = dynamic_cast<DefInit*>(OI.MIOperandInfo->getArg(SubOpIdx))->getDef();
|
||||||
|
|
||||||
|
if (Rec->isSubClassOf("RegisterOperand")) {
|
||||||
|
// RegisterOperand may have an associated ParserMatchClass. If it does,
|
||||||
|
// use it, else just fall back to the underlying register class.
|
||||||
|
const RecordVal *R = Rec->getValue("ParserMatchClass");
|
||||||
|
if (R == 0 || R->getValue() == 0)
|
||||||
|
throw "Record `" + Rec->getName() +
|
||||||
|
"' does not have a ParserMatchClass!\n";
|
||||||
|
|
||||||
|
if (DefInit *DI= dynamic_cast<DefInit*>(R->getValue())) {
|
||||||
|
Record *MatchClass = DI->getDef();
|
||||||
|
if (ClassInfo *CI = AsmOperandClasses[MatchClass])
|
||||||
|
return CI;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No custom match class. Just use the register class.
|
||||||
|
Record *ClassRec = Rec->getValueAsDef("RegClass");
|
||||||
|
if (!ClassRec)
|
||||||
|
throw TGError(Rec->getLoc(), "RegisterOperand `" + Rec->getName() +
|
||||||
|
"' has no associated register class!\n");
|
||||||
|
if (ClassInfo *CI = RegisterClassClasses[ClassRec])
|
||||||
|
return CI;
|
||||||
|
throw TGError(Rec->getLoc(), "register class has no class info!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Rec->isSubClassOf("RegisterClass")) {
|
if (Rec->isSubClassOf("RegisterClass")) {
|
||||||
if (ClassInfo *CI = RegisterClassClasses[Rec])
|
if (ClassInfo *CI = RegisterClassClasses[Rec])
|
||||||
return CI;
|
return CI;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "CodeGenTarget.h"
|
#include "CodeGenTarget.h"
|
||||||
#include "Record.h"
|
#include "Record.h"
|
||||||
#include "StringToOffsetTable.h"
|
#include "StringToOffsetTable.h"
|
||||||
|
#include "llvm/ADT/Twine.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include "llvm/Support/MathExtras.h"
|
#include "llvm/Support/MathExtras.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -458,6 +459,58 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
|
||||||
O << "}\n";
|
O << "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
emitRegisterNameString(raw_ostream &O, StringRef AltName,
|
||||||
|
const std::vector<CodeGenRegister*> &Registers) {
|
||||||
|
StringToOffsetTable StringTable;
|
||||||
|
O << " static const unsigned RegAsmOffset" << AltName << "[] = {\n ";
|
||||||
|
for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
|
||||||
|
const CodeGenRegister &Reg = *Registers[i];
|
||||||
|
|
||||||
|
StringRef AsmName;
|
||||||
|
// "NoRegAltName" is special. We don't need to do a lookup for that,
|
||||||
|
// as it's just a reference to the default register name.
|
||||||
|
if (AltName == "" || AltName == "NoRegAltName") {
|
||||||
|
AsmName = Reg.TheDef->getValueAsString("AsmName");
|
||||||
|
if (AsmName.empty())
|
||||||
|
AsmName = Reg.getName();
|
||||||
|
} else {
|
||||||
|
// Make sure the register has an alternate name for this index.
|
||||||
|
std::vector<Record*> AltNameList =
|
||||||
|
Reg.TheDef->getValueAsListOfDefs("RegAltNameIndices");
|
||||||
|
unsigned Idx = 0, e;
|
||||||
|
for (e = AltNameList.size();
|
||||||
|
Idx < e && (AltNameList[Idx]->getName() != AltName);
|
||||||
|
++Idx)
|
||||||
|
;
|
||||||
|
// If the register has an alternate name for this index, use it.
|
||||||
|
// Otherwise, leave it empty as an error flag.
|
||||||
|
if (Idx < e) {
|
||||||
|
std::vector<std::string> AltNames =
|
||||||
|
Reg.TheDef->getValueAsListOfStrings("AltNames");
|
||||||
|
if (AltNames.size() <= Idx)
|
||||||
|
throw TGError(Reg.TheDef->getLoc(),
|
||||||
|
(Twine("Register definition missing alt name for '") +
|
||||||
|
AltName + "'.").str());
|
||||||
|
AsmName = AltNames[Idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
O << StringTable.GetOrAddStringOffset(AsmName);
|
||||||
|
if (((i + 1) % 14) == 0)
|
||||||
|
O << ",\n ";
|
||||||
|
else
|
||||||
|
O << ", ";
|
||||||
|
|
||||||
|
}
|
||||||
|
O << "0\n"
|
||||||
|
<< " };\n"
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
|
O << " const char *AsmStrs" << AltName << " =\n";
|
||||||
|
StringTable.EmitString(O);
|
||||||
|
O << ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
|
void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
|
||||||
CodeGenTarget Target(Records);
|
CodeGenTarget Target(Records);
|
||||||
|
@ -465,40 +518,48 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
|
||||||
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
|
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
|
||||||
const std::vector<CodeGenRegister*> &Registers =
|
const std::vector<CodeGenRegister*> &Registers =
|
||||||
Target.getRegBank().getRegisters();
|
Target.getRegBank().getRegisters();
|
||||||
|
std::vector<Record*> AltNameIndices = Target.getRegAltNameIndices();
|
||||||
|
bool hasAltNames = AltNameIndices.size() > 1;
|
||||||
|
|
||||||
StringToOffsetTable StringTable;
|
|
||||||
O <<
|
O <<
|
||||||
"\n\n/// getRegisterName - This method is automatically generated by tblgen\n"
|
"\n\n/// getRegisterName - This method is automatically generated by tblgen\n"
|
||||||
"/// from the register set description. This returns the assembler name\n"
|
"/// from the register set description. This returns the assembler name\n"
|
||||||
"/// for the specified register.\n"
|
"/// for the specified register.\n"
|
||||||
"const char *" << Target.getName() << ClassName
|
"const char *" << Target.getName() << ClassName << "::";
|
||||||
<< "::getRegisterName(unsigned RegNo) {\n"
|
if (hasAltNames)
|
||||||
<< " assert(RegNo && RegNo < " << (Registers.size()+1)
|
O << "\ngetRegisterName(unsigned RegNo, unsigned AltIdx) {\n";
|
||||||
<< " && \"Invalid register number!\");\n"
|
else
|
||||||
<< "\n"
|
O << "getRegisterName(unsigned RegNo) {\n";
|
||||||
<< " static const unsigned RegAsmOffset[] = {";
|
O << " assert(RegNo && RegNo < " << (Registers.size()+1)
|
||||||
for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
|
<< " && \"Invalid register number!\");\n"
|
||||||
const CodeGenRegister &Reg = *Registers[i];
|
|
||||||
|
|
||||||
std::string AsmName = Reg.TheDef->getValueAsString("AsmName");
|
|
||||||
if (AsmName.empty())
|
|
||||||
AsmName = Reg.getName();
|
|
||||||
|
|
||||||
|
|
||||||
if ((i % 14) == 0)
|
|
||||||
O << "\n ";
|
|
||||||
|
|
||||||
O << StringTable.GetOrAddStringOffset(AsmName) << ", ";
|
|
||||||
}
|
|
||||||
O << "0\n"
|
|
||||||
<< " };\n"
|
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
||||||
O << " const char *AsmStrs =\n";
|
if (hasAltNames) {
|
||||||
StringTable.EmitString(O);
|
for (unsigned i = 0, e = AltNameIndices.size(); i < e; ++i)
|
||||||
O << ";\n";
|
emitRegisterNameString(O, AltNameIndices[i]->getName(), Registers);
|
||||||
|
} else
|
||||||
|
emitRegisterNameString(O, "", Registers);
|
||||||
|
|
||||||
O << " return AsmStrs+RegAsmOffset[RegNo-1];\n"
|
if (hasAltNames) {
|
||||||
|
O << " const unsigned *RegAsmOffset;\n"
|
||||||
|
<< " const char *AsmStrs;\n"
|
||||||
|
<< " switch(AltIdx) {\n"
|
||||||
|
<< " default: assert(0 && \"Invalid register alt name index!\");\n";
|
||||||
|
for (unsigned i = 0, e = AltNameIndices.size(); i < e; ++i) {
|
||||||
|
StringRef Namespace = AltNameIndices[1]->getValueAsString("Namespace");
|
||||||
|
StringRef AltName(AltNameIndices[i]->getName());
|
||||||
|
O << " case " << Namespace << "::" << AltName
|
||||||
|
<< ":\n"
|
||||||
|
<< " AsmStrs = AsmStrs" << AltName << ";\n"
|
||||||
|
<< " RegAsmOffset = RegAsmOffset" << AltName << ";\n"
|
||||||
|
<< " break;\n";
|
||||||
|
}
|
||||||
|
O << "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
O << " assert (*(AsmStrs+RegAsmOffset[RegNo-1]) &&\n"
|
||||||
|
<< " \"Invalid alt name index for register!\");\n"
|
||||||
|
<< " return AsmStrs+RegAsmOffset[RegNo-1];\n"
|
||||||
<< "}\n";
|
<< "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -936,6 +997,9 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
|
||||||
const Record *Rec = RO.getRecord();
|
const Record *Rec = RO.getRecord();
|
||||||
StringRef ROName = RO.getName();
|
StringRef ROName = RO.getName();
|
||||||
|
|
||||||
|
|
||||||
|
if (Rec->isSubClassOf("RegisterOperand"))
|
||||||
|
Rec = Rec->getValueAsDef("RegClass");
|
||||||
if (Rec->isSubClassOf("RegisterClass")) {
|
if (Rec->isSubClassOf("RegisterClass")) {
|
||||||
Cond = std::string("MI->getOperand(")+llvm::utostr(i)+").isReg()";
|
Cond = std::string("MI->getOperand(")+llvm::utostr(i)+").isReg()";
|
||||||
IAP->addCond(Cond);
|
IAP->addCond(Cond);
|
||||||
|
|
|
@ -1242,6 +1242,16 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) {
|
||||||
///
|
///
|
||||||
static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo,
|
static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo,
|
||||||
bool NotRegisters, TreePattern &TP) {
|
bool NotRegisters, TreePattern &TP) {
|
||||||
|
// Check to see if this is a register operand.
|
||||||
|
if (R->isSubClassOf("RegisterOperand")) {
|
||||||
|
assert(ResNo == 0 && "Regoperand ref only has one result!");
|
||||||
|
if (NotRegisters)
|
||||||
|
return EEVT::TypeSet(); // Unknown.
|
||||||
|
Record *RegClass = R->getValueAsDef("RegClass");
|
||||||
|
const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo();
|
||||||
|
return EEVT::TypeSet(T.getRegisterClass(RegClass).getValueTypes());
|
||||||
|
}
|
||||||
|
|
||||||
// Check to see if this is a register or a register class.
|
// Check to see if this is a register or a register class.
|
||||||
if (R->isSubClassOf("RegisterClass")) {
|
if (R->isSubClassOf("RegisterClass")) {
|
||||||
assert(ResNo == 0 && "Regclass ref only has one result!");
|
assert(ResNo == 0 && "Regclass ref only has one result!");
|
||||||
|
@ -1524,6 +1534,11 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
|
||||||
|
|
||||||
if (ResultNode->isSubClassOf("PointerLikeRegClass")) {
|
if (ResultNode->isSubClassOf("PointerLikeRegClass")) {
|
||||||
MadeChange |= UpdateNodeType(ResNo, MVT::iPTR, TP);
|
MadeChange |= UpdateNodeType(ResNo, MVT::iPTR, TP);
|
||||||
|
} else if (ResultNode->isSubClassOf("RegisterOperand")) {
|
||||||
|
Record *RegClass = ResultNode->getValueAsDef("RegClass");
|
||||||
|
const CodeGenRegisterClass &RC =
|
||||||
|
CDP.getTargetInfo().getRegisterClass(RegClass);
|
||||||
|
MadeChange |= UpdateNodeType(ResNo, RC.getValueTypes(), TP);
|
||||||
} else if (ResultNode->getName() == "unknown") {
|
} else if (ResultNode->getName() == "unknown") {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
} else {
|
} else {
|
||||||
|
@ -1582,6 +1597,11 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
|
||||||
const CodeGenRegisterClass &RC =
|
const CodeGenRegisterClass &RC =
|
||||||
CDP.getTargetInfo().getRegisterClass(OperandNode);
|
CDP.getTargetInfo().getRegisterClass(OperandNode);
|
||||||
MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP);
|
MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP);
|
||||||
|
} else if (OperandNode->isSubClassOf("RegisterOperand")) {
|
||||||
|
Record *RegClass = OperandNode->getValueAsDef("RegClass");
|
||||||
|
const CodeGenRegisterClass &RC =
|
||||||
|
CDP.getTargetInfo().getRegisterClass(RegClass);
|
||||||
|
MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP);
|
||||||
} else if (OperandNode->isSubClassOf("Operand")) {
|
} else if (OperandNode->isSubClassOf("Operand")) {
|
||||||
VT = getValueType(OperandNode->getValueAsDef("Type"));
|
VT = getValueType(OperandNode->getValueAsDef("Type"));
|
||||||
MadeChange |= Child->UpdateNodeType(ChildResNo, VT, TP);
|
MadeChange |= Child->UpdateNodeType(ChildResNo, VT, TP);
|
||||||
|
@ -1928,7 +1948,8 @@ InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) {
|
||||||
// def : Pat<(v1i64 (bitconvert(v2i32 DPR:$src))), (v1i64 DPR:$src)>;
|
// def : Pat<(v1i64 (bitconvert(v2i32 DPR:$src))), (v1i64 DPR:$src)>;
|
||||||
if (Nodes[i] == Trees[0] && Nodes[i]->isLeaf()) {
|
if (Nodes[i] == Trees[0] && Nodes[i]->isLeaf()) {
|
||||||
DefInit *DI = dynamic_cast<DefInit*>(Nodes[i]->getLeafValue());
|
DefInit *DI = dynamic_cast<DefInit*>(Nodes[i]->getLeafValue());
|
||||||
if (DI && DI->getDef()->isSubClassOf("RegisterClass"))
|
if (DI && (DI->getDef()->isSubClassOf("RegisterClass") ||
|
||||||
|
DI->getDef()->isSubClassOf("RegisterOperand")))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2211,7 +2232,8 @@ static bool HandleUse(TreePattern *I, TreePatternNode *Pat,
|
||||||
if (Pat->getName().empty()) {
|
if (Pat->getName().empty()) {
|
||||||
if (Pat->isLeaf()) {
|
if (Pat->isLeaf()) {
|
||||||
DefInit *DI = dynamic_cast<DefInit*>(Pat->getLeafValue());
|
DefInit *DI = dynamic_cast<DefInit*>(Pat->getLeafValue());
|
||||||
if (DI && DI->getDef()->isSubClassOf("RegisterClass"))
|
if (DI && (DI->getDef()->isSubClassOf("RegisterClass") ||
|
||||||
|
DI->getDef()->isSubClassOf("RegisterOperand")))
|
||||||
I->error("Input " + DI->getDef()->getName() + " must be named!");
|
I->error("Input " + DI->getDef()->getName() + " must be named!");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -2318,6 +2340,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
|
||||||
I->error("set destination should be a register!");
|
I->error("set destination should be a register!");
|
||||||
|
|
||||||
if (Val->getDef()->isSubClassOf("RegisterClass") ||
|
if (Val->getDef()->isSubClassOf("RegisterClass") ||
|
||||||
|
Val->getDef()->isSubClassOf("RegisterOperand") ||
|
||||||
Val->getDef()->isSubClassOf("PointerLikeRegClass")) {
|
Val->getDef()->isSubClassOf("PointerLikeRegClass")) {
|
||||||
if (Dest->getName().empty())
|
if (Dest->getName().empty())
|
||||||
I->error("set destination must have a name!");
|
I->error("set destination must have a name!");
|
||||||
|
|
|
@ -69,7 +69,9 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
|
||||||
std::string EncoderMethod;
|
std::string EncoderMethod;
|
||||||
unsigned NumOps = 1;
|
unsigned NumOps = 1;
|
||||||
DagInit *MIOpInfo = 0;
|
DagInit *MIOpInfo = 0;
|
||||||
if (Rec->isSubClassOf("Operand")) {
|
if (Rec->isSubClassOf("RegisterOperand")) {
|
||||||
|
PrintMethod = Rec->getValueAsString("PrintMethod");
|
||||||
|
} else if (Rec->isSubClassOf("Operand")) {
|
||||||
PrintMethod = Rec->getValueAsString("PrintMethod");
|
PrintMethod = Rec->getValueAsString("PrintMethod");
|
||||||
// If there is an explicit encoder method, use it.
|
// If there is an explicit encoder method, use it.
|
||||||
EncoderMethod = Rec->getValueAsString("EncoderMethod");
|
EncoderMethod = Rec->getValueAsString("EncoderMethod");
|
||||||
|
@ -415,6 +417,9 @@ bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo,
|
||||||
|
|
||||||
// Handle explicit registers.
|
// Handle explicit registers.
|
||||||
if (ADI && ADI->getDef()->isSubClassOf("Register")) {
|
if (ADI && ADI->getDef()->isSubClassOf("Register")) {
|
||||||
|
if (InstOpRec->isSubClassOf("RegisterOperand"))
|
||||||
|
InstOpRec = InstOpRec->getValueAsDef("RegClass");
|
||||||
|
|
||||||
if (!InstOpRec->isSubClassOf("RegisterClass"))
|
if (!InstOpRec->isSubClassOf("RegisterClass"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -164,6 +164,11 @@ CodeGenRegBank &CodeGenTarget::getRegBank() const {
|
||||||
return *RegBank;
|
return *RegBank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeGenTarget::ReadRegAltNameIndices() const {
|
||||||
|
RegAltNameIndices = Records.getAllDerivedDefinitions("RegAltNameIndex");
|
||||||
|
std::sort(RegAltNameIndices.begin(), RegAltNameIndices.end(), LessRecord());
|
||||||
|
}
|
||||||
|
|
||||||
/// getRegisterByName - If there is a register with the specific AsmName,
|
/// getRegisterByName - If there is a register with the specific AsmName,
|
||||||
/// return it.
|
/// return it.
|
||||||
const CodeGenRegister *CodeGenTarget::getRegisterByName(StringRef Name) const {
|
const CodeGenRegister *CodeGenTarget::getRegisterByName(StringRef Name) const {
|
||||||
|
|
|
@ -66,7 +66,9 @@ class CodeGenTarget {
|
||||||
|
|
||||||
mutable DenseMap<const Record*, CodeGenInstruction*> Instructions;
|
mutable DenseMap<const Record*, CodeGenInstruction*> Instructions;
|
||||||
mutable CodeGenRegBank *RegBank;
|
mutable CodeGenRegBank *RegBank;
|
||||||
|
mutable std::vector<Record*> RegAltNameIndices;
|
||||||
mutable std::vector<MVT::SimpleValueType> LegalValueTypes;
|
mutable std::vector<MVT::SimpleValueType> LegalValueTypes;
|
||||||
|
void ReadRegAltNameIndices() const;
|
||||||
void ReadInstructions() const;
|
void ReadInstructions() const;
|
||||||
void ReadLegalValueTypes() const;
|
void ReadLegalValueTypes() const;
|
||||||
|
|
||||||
|
@ -100,6 +102,11 @@ public:
|
||||||
/// return it.
|
/// return it.
|
||||||
const CodeGenRegister *getRegisterByName(StringRef Name) const;
|
const CodeGenRegister *getRegisterByName(StringRef Name) const;
|
||||||
|
|
||||||
|
const std::vector<Record*> &getRegAltNameIndices() const {
|
||||||
|
if (RegAltNameIndices.empty()) ReadRegAltNameIndices();
|
||||||
|
return RegAltNameIndices;
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<CodeGenRegisterClass> &getRegisterClasses() const {
|
const std::vector<CodeGenRegisterClass> &getRegisterClasses() const {
|
||||||
return getRegBank().getRegClasses();
|
return getRegBank().getRegClasses();
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,6 +224,7 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
|
||||||
Record *LeafRec = DI->getDef();
|
Record *LeafRec = DI->getDef();
|
||||||
if (// Handle register references. Nothing to do here, they always match.
|
if (// Handle register references. Nothing to do here, they always match.
|
||||||
LeafRec->isSubClassOf("RegisterClass") ||
|
LeafRec->isSubClassOf("RegisterClass") ||
|
||||||
|
LeafRec->isSubClassOf("RegisterOperand") ||
|
||||||
LeafRec->isSubClassOf("PointerLikeRegClass") ||
|
LeafRec->isSubClassOf("PointerLikeRegClass") ||
|
||||||
LeafRec->isSubClassOf("SubRegIndex") ||
|
LeafRec->isSubClassOf("SubRegIndex") ||
|
||||||
// Place holder for SRCVALUE nodes. Nothing to do here.
|
// Place holder for SRCVALUE nodes. Nothing to do here.
|
||||||
|
@ -579,15 +580,16 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
|
||||||
|
|
||||||
// If this is an explicit register reference, handle it.
|
// If this is an explicit register reference, handle it.
|
||||||
if (DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue())) {
|
if (DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue())) {
|
||||||
if (DI->getDef()->isSubClassOf("Register")) {
|
Record *Def = DI->getDef();
|
||||||
|
if (Def->isSubClassOf("Register")) {
|
||||||
const CodeGenRegister *Reg =
|
const CodeGenRegister *Reg =
|
||||||
CGP.getTargetInfo().getRegBank().getReg(DI->getDef());
|
CGP.getTargetInfo().getRegBank().getReg(Def);
|
||||||
AddMatcher(new EmitRegisterMatcher(Reg, N->getType(0)));
|
AddMatcher(new EmitRegisterMatcher(Reg, N->getType(0)));
|
||||||
ResultOps.push_back(NextRecordedOperandNo++);
|
ResultOps.push_back(NextRecordedOperandNo++);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DI->getDef()->getName() == "zero_reg") {
|
if (Def->getName() == "zero_reg") {
|
||||||
AddMatcher(new EmitRegisterMatcher(0, N->getType(0)));
|
AddMatcher(new EmitRegisterMatcher(0, N->getType(0)));
|
||||||
ResultOps.push_back(NextRecordedOperandNo++);
|
ResultOps.push_back(NextRecordedOperandNo++);
|
||||||
return;
|
return;
|
||||||
|
@ -595,16 +597,18 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
|
||||||
|
|
||||||
// Handle a reference to a register class. This is used
|
// Handle a reference to a register class. This is used
|
||||||
// in COPY_TO_SUBREG instructions.
|
// in COPY_TO_SUBREG instructions.
|
||||||
if (DI->getDef()->isSubClassOf("RegisterClass")) {
|
if (Def->isSubClassOf("RegisterOperand"))
|
||||||
std::string Value = getQualifiedName(DI->getDef()) + "RegClassID";
|
Def = Def->getValueAsDef("RegClass");
|
||||||
|
if (Def->isSubClassOf("RegisterClass")) {
|
||||||
|
std::string Value = getQualifiedName(Def) + "RegClassID";
|
||||||
AddMatcher(new EmitStringIntegerMatcher(Value, MVT::i32));
|
AddMatcher(new EmitStringIntegerMatcher(Value, MVT::i32));
|
||||||
ResultOps.push_back(NextRecordedOperandNo++);
|
ResultOps.push_back(NextRecordedOperandNo++);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a subregister index. This is used for INSERT_SUBREG etc.
|
// Handle a subregister index. This is used for INSERT_SUBREG etc.
|
||||||
if (DI->getDef()->isSubClassOf("SubRegIndex")) {
|
if (Def->isSubClassOf("SubRegIndex")) {
|
||||||
std::string Value = getQualifiedName(DI->getDef());
|
std::string Value = getQualifiedName(Def);
|
||||||
AddMatcher(new EmitStringIntegerMatcher(Value, MVT::i32));
|
AddMatcher(new EmitStringIntegerMatcher(Value, MVT::i32));
|
||||||
ResultOps.push_back(NextRecordedOperandNo++);
|
ResultOps.push_back(NextRecordedOperandNo++);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -248,6 +248,8 @@ struct OperandsSignature {
|
||||||
|
|
||||||
// For now, the only other thing we accept is register operands.
|
// For now, the only other thing we accept is register operands.
|
||||||
const CodeGenRegisterClass *RC = 0;
|
const CodeGenRegisterClass *RC = 0;
|
||||||
|
if (OpLeafRec->isSubClassOf("RegisterOperand"))
|
||||||
|
OpLeafRec = OpLeafRec->getValueAsDef("RegClass");
|
||||||
if (OpLeafRec->isSubClassOf("RegisterClass"))
|
if (OpLeafRec->isSubClassOf("RegisterClass"))
|
||||||
RC = &Target.getRegisterClass(OpLeafRec);
|
RC = &Target.getRegisterClass(OpLeafRec);
|
||||||
else if (OpLeafRec->isSubClassOf("Register"))
|
else if (OpLeafRec->isSubClassOf("Register"))
|
||||||
|
@ -454,6 +456,8 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
|
||||||
std::string SubRegNo;
|
std::string SubRegNo;
|
||||||
if (Op->getName() != "EXTRACT_SUBREG") {
|
if (Op->getName() != "EXTRACT_SUBREG") {
|
||||||
Record *Op0Rec = II.Operands[0].Rec;
|
Record *Op0Rec = II.Operands[0].Rec;
|
||||||
|
if (Op0Rec->isSubClassOf("RegisterOperand"))
|
||||||
|
Op0Rec = Op0Rec->getValueAsDef("RegClass");
|
||||||
if (!Op0Rec->isSubClassOf("RegisterClass"))
|
if (!Op0Rec->isSubClassOf("RegisterClass"))
|
||||||
continue;
|
continue;
|
||||||
DstRC = &Target.getRegisterClass(Op0Rec);
|
DstRC = &Target.getRegisterClass(Op0Rec);
|
||||||
|
|
|
@ -1305,8 +1305,10 @@ bool FixedLenDecoderEmitter::populateInstruction(const CodeGenInstruction &CGI,
|
||||||
RecordRecTy *Type = dynamic_cast<RecordRecTy*>(TI->getType());
|
RecordRecTy *Type = dynamic_cast<RecordRecTy*>(TI->getType());
|
||||||
Record *TypeRecord = Type->getRecord();
|
Record *TypeRecord = Type->getRecord();
|
||||||
bool isReg = false;
|
bool isReg = false;
|
||||||
|
if (TypeRecord->isSubClassOf("RegisterOperand"))
|
||||||
|
TypeRecord = TypeRecord->getValueAsDef("RegClass");
|
||||||
if (TypeRecord->isSubClassOf("RegisterClass")) {
|
if (TypeRecord->isSubClassOf("RegisterClass")) {
|
||||||
Decoder = "Decode" + Type->getRecord()->getName() + "RegisterClass";
|
Decoder = "Decode" + TypeRecord->getName() + "RegisterClass";
|
||||||
isReg = true;
|
isReg = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,10 +43,10 @@ void InstrInfoEmitter::GatherItinClasses() {
|
||||||
std::vector<Record*> DefList =
|
std::vector<Record*> DefList =
|
||||||
Records.getAllDerivedDefinitions("InstrItinClass");
|
Records.getAllDerivedDefinitions("InstrItinClass");
|
||||||
std::sort(DefList.begin(), DefList.end(), LessRecord());
|
std::sort(DefList.begin(), DefList.end(), LessRecord());
|
||||||
|
|
||||||
for (unsigned i = 0, N = DefList.size(); i < N; i++)
|
for (unsigned i = 0, N = DefList.size(); i < N; i++)
|
||||||
ItinClassMap[DefList[i]->getName()] = i;
|
ItinClassMap[DefList[i]->getName()] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned InstrInfoEmitter::getItinClassNumber(const Record *InstRec) {
|
unsigned InstrInfoEmitter::getItinClassNumber(const Record *InstRec) {
|
||||||
return ItinClassMap[InstRec->getValueAsDef("Itinerary")->getName()];
|
return ItinClassMap[InstRec->getValueAsDef("Itinerary")->getName()];
|
||||||
|
@ -59,7 +59,7 @@ unsigned InstrInfoEmitter::getItinClassNumber(const Record *InstRec) {
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
||||||
std::vector<std::string> Result;
|
std::vector<std::string> Result;
|
||||||
|
|
||||||
for (unsigned i = 0, e = Inst.Operands.size(); i != e; ++i) {
|
for (unsigned i = 0, e = Inst.Operands.size(); i != e; ++i) {
|
||||||
// Handle aggregate operands and normal operands the same way by expanding
|
// Handle aggregate operands and normal operands the same way by expanding
|
||||||
// either case into a list of operands for this op.
|
// either case into a list of operands for this op.
|
||||||
|
@ -70,7 +70,7 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
||||||
// operand, which has a single operand, but no declared class for the
|
// operand, which has a single operand, but no declared class for the
|
||||||
// operand.
|
// operand.
|
||||||
DagInit *MIOI = Inst.Operands[i].MIOperandInfo;
|
DagInit *MIOI = Inst.Operands[i].MIOperandInfo;
|
||||||
|
|
||||||
if (!MIOI || MIOI->getNumArgs() == 0) {
|
if (!MIOI || MIOI->getNumArgs() == 0) {
|
||||||
// Single, anonymous, operand.
|
// Single, anonymous, operand.
|
||||||
OperandList.push_back(Inst.Operands[i]);
|
OperandList.push_back(Inst.Operands[i]);
|
||||||
|
@ -86,7 +86,9 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
||||||
for (unsigned j = 0, e = OperandList.size(); j != e; ++j) {
|
for (unsigned j = 0, e = OperandList.size(); j != e; ++j) {
|
||||||
Record *OpR = OperandList[j].Rec;
|
Record *OpR = OperandList[j].Rec;
|
||||||
std::string Res;
|
std::string Res;
|
||||||
|
|
||||||
|
if (OpR->isSubClassOf("RegisterOperand"))
|
||||||
|
OpR = OpR->getValueAsDef("RegClass");
|
||||||
if (OpR->isSubClassOf("RegisterClass"))
|
if (OpR->isSubClassOf("RegisterClass"))
|
||||||
Res += getQualifiedName(OpR) + "RegClassID, ";
|
Res += getQualifiedName(OpR) + "RegClassID, ";
|
||||||
else if (OpR->isSubClassOf("PointerLikeRegClass"))
|
else if (OpR->isSubClassOf("PointerLikeRegClass"))
|
||||||
|
@ -94,10 +96,10 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
||||||
else
|
else
|
||||||
// -1 means the operand does not have a fixed register class.
|
// -1 means the operand does not have a fixed register class.
|
||||||
Res += "-1, ";
|
Res += "-1, ";
|
||||||
|
|
||||||
// Fill in applicable flags.
|
// Fill in applicable flags.
|
||||||
Res += "0";
|
Res += "0";
|
||||||
|
|
||||||
// Ptr value whose register class is resolved via callback.
|
// Ptr value whose register class is resolved via callback.
|
||||||
if (OpR->isSubClassOf("PointerLikeRegClass"))
|
if (OpR->isSubClassOf("PointerLikeRegClass"))
|
||||||
Res += "|(1<<TOI::LookupPtrRegClass)";
|
Res += "|(1<<TOI::LookupPtrRegClass)";
|
||||||
|
@ -106,7 +108,7 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
||||||
// was of type PredicateOperand.
|
// was of type PredicateOperand.
|
||||||
if (Inst.Operands[i].Rec->isSubClassOf("PredicateOperand"))
|
if (Inst.Operands[i].Rec->isSubClassOf("PredicateOperand"))
|
||||||
Res += "|(1<<TOI::Predicate)";
|
Res += "|(1<<TOI::Predicate)";
|
||||||
|
|
||||||
// Optional def operands. Check to see if the original unexpanded operand
|
// Optional def operands. Check to see if the original unexpanded operand
|
||||||
// was of type OptionalDefOperand.
|
// was of type OptionalDefOperand.
|
||||||
if (Inst.Operands[i].Rec->isSubClassOf("OptionalDefOperand"))
|
if (Inst.Operands[i].Rec->isSubClassOf("OptionalDefOperand"))
|
||||||
|
@ -114,7 +116,7 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
||||||
|
|
||||||
// Fill in constraint info.
|
// Fill in constraint info.
|
||||||
Res += ", ";
|
Res += ", ";
|
||||||
|
|
||||||
const CGIOperandList::ConstraintInfo &Constraint =
|
const CGIOperandList::ConstraintInfo &Constraint =
|
||||||
Inst.Operands[i].Constraints[j];
|
Inst.Operands[i].Constraints[j];
|
||||||
if (Constraint.isNone())
|
if (Constraint.isNone())
|
||||||
|
@ -126,7 +128,7 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
||||||
Res += "((" + utostr(Constraint.getTiedOperand()) +
|
Res += "((" + utostr(Constraint.getTiedOperand()) +
|
||||||
" << 16) | (1 << TOI::TIED_TO))";
|
" << 16) | (1 << TOI::TIED_TO))";
|
||||||
}
|
}
|
||||||
|
|
||||||
Result.push_back(Res);
|
Result.push_back(Res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,12 +136,12 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
|
void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
|
||||||
OperandInfoMapTy &OperandInfoIDs) {
|
OperandInfoMapTy &OperandInfoIDs) {
|
||||||
// ID #0 is for no operand info.
|
// ID #0 is for no operand info.
|
||||||
unsigned OperandListNum = 0;
|
unsigned OperandListNum = 0;
|
||||||
OperandInfoIDs[std::vector<std::string>()] = ++OperandListNum;
|
OperandInfoIDs[std::vector<std::string>()] = ++OperandListNum;
|
||||||
|
|
||||||
OS << "\n";
|
OS << "\n";
|
||||||
const CodeGenTarget &Target = CDP.getTargetInfo();
|
const CodeGenTarget &Target = CDP.getTargetInfo();
|
||||||
for (CodeGenTarget::inst_iterator II = Target.inst_begin(),
|
for (CodeGenTarget::inst_iterator II = Target.inst_begin(),
|
||||||
|
@ -147,7 +149,7 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
|
||||||
std::vector<std::string> OperandInfo = GetOperandInfo(**II);
|
std::vector<std::string> OperandInfo = GetOperandInfo(**II);
|
||||||
unsigned &N = OperandInfoIDs[OperandInfo];
|
unsigned &N = OperandInfoIDs[OperandInfo];
|
||||||
if (N != 0) continue;
|
if (N != 0) continue;
|
||||||
|
|
||||||
N = ++OperandListNum;
|
N = ++OperandListNum;
|
||||||
OS << "static const TargetOperandInfo OperandInfo" << N << "[] = { ";
|
OS << "static const TargetOperandInfo OperandInfo" << N << "[] = { ";
|
||||||
for (unsigned i = 0, e = OperandInfo.size(); i != e; ++i)
|
for (unsigned i = 0, e = OperandInfo.size(); i != e; ++i)
|
||||||
|
@ -205,7 +207,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
|
||||||
std::map<std::vector<Record*>, unsigned> EmittedBarriers;
|
std::map<std::vector<Record*>, unsigned> EmittedBarriers;
|
||||||
unsigned BarrierNumber = 0;
|
unsigned BarrierNumber = 0;
|
||||||
std::map<Record*, unsigned> BarriersMap;
|
std::map<Record*, unsigned> BarriersMap;
|
||||||
|
|
||||||
// Emit all of the instruction's implicit uses and defs.
|
// Emit all of the instruction's implicit uses and defs.
|
||||||
for (CodeGenTarget::inst_iterator II = Target.inst_begin(),
|
for (CodeGenTarget::inst_iterator II = Target.inst_begin(),
|
||||||
E = Target.inst_end(); II != E; ++II) {
|
E = Target.inst_end(); II != E; ++II) {
|
||||||
|
@ -231,10 +233,10 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
OperandInfoMapTy OperandInfoIDs;
|
OperandInfoMapTy OperandInfoIDs;
|
||||||
|
|
||||||
// Emit all of the operand info records.
|
// Emit all of the operand info records.
|
||||||
EmitOperandInfo(OS, OperandInfoIDs);
|
EmitOperandInfo(OS, OperandInfoIDs);
|
||||||
|
|
||||||
// Emit all of the TargetInstrDesc records in their ENUM ordering.
|
// Emit all of the TargetInstrDesc records in their ENUM ordering.
|
||||||
//
|
//
|
||||||
OS << "\nstatic const TargetInstrDesc " << TargetName
|
OS << "\nstatic const TargetInstrDesc " << TargetName
|
||||||
|
|
|
@ -1443,6 +1443,25 @@ Record::getValueAsListOfInts(StringRef FieldName) const {
|
||||||
return Ints;
|
return Ints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// getValueAsListOfStrings - This method looks up the specified field and
|
||||||
|
/// returns its value as a vector of strings, throwing an exception if the
|
||||||
|
/// field does not exist or if the value is not the right type.
|
||||||
|
///
|
||||||
|
std::vector<std::string>
|
||||||
|
Record::getValueAsListOfStrings(StringRef FieldName) const {
|
||||||
|
ListInit *List = getValueAsListInit(FieldName);
|
||||||
|
std::vector<std::string> Strings;
|
||||||
|
for (unsigned i = 0; i < List->getSize(); i++) {
|
||||||
|
if (StringInit *II = dynamic_cast<StringInit*>(List->getElement(i))) {
|
||||||
|
Strings.push_back(II->getValue());
|
||||||
|
} else {
|
||||||
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
||||||
|
"' does not have a list of strings initializer!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Strings;
|
||||||
|
}
|
||||||
|
|
||||||
/// getValueAsDef - This method looks up the specified field and returns its
|
/// getValueAsDef - This method looks up the specified field and returns its
|
||||||
/// value as a Record, throwing an exception if the field does not exist or if
|
/// value as a Record, throwing an exception if the field does not exist or if
|
||||||
/// the value is not the right type.
|
/// the value is not the right type.
|
||||||
|
|
|
@ -1368,6 +1368,12 @@ public:
|
||||||
///
|
///
|
||||||
std::vector<int64_t> getValueAsListOfInts(StringRef FieldName) const;
|
std::vector<int64_t> getValueAsListOfInts(StringRef FieldName) const;
|
||||||
|
|
||||||
|
/// getValueAsListOfStrings - This method looks up the specified field and
|
||||||
|
/// returns its value as a vector of strings, throwing an exception if the
|
||||||
|
/// field does not exist or if the value is not the right type.
|
||||||
|
///
|
||||||
|
std::vector<std::string> getValueAsListOfStrings(StringRef FieldName) const;
|
||||||
|
|
||||||
/// getValueAsDef - This method looks up the specified field and returns its
|
/// getValueAsDef - This method looks up the specified field and returns its
|
||||||
/// value as a Record, throwing an exception if the field does not exist or if
|
/// value as a Record, throwing an exception if the field does not exist or if
|
||||||
/// the value is not the right type.
|
/// the value is not the right type.
|
||||||
|
|
|
@ -112,6 +112,18 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||||
OS << "0 };\n";
|
OS << "0 };\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<Record*> RegAltNameIndices = Target.getRegAltNameIndices();
|
||||||
|
// If the only definition is the default NoRegAltName, we don't need to
|
||||||
|
// emit anything.
|
||||||
|
if (RegAltNameIndices.size() > 1) {
|
||||||
|
OS << "\n// Register alternate name indices\n";
|
||||||
|
OS << "enum {\n";
|
||||||
|
for (unsigned i = 0, e = RegAltNameIndices.size(); i != e; ++i)
|
||||||
|
OS << " " << RegAltNameIndices[i]->getName() << ",\t// " << i << "\n";
|
||||||
|
OS << " NUM_TARGET_REG_ALT_NAMES = " << RegAltNameIndices.size() << "\n";
|
||||||
|
OS << "};\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Emit the empty sub-registers list
|
// Emit the empty sub-registers list
|
||||||
OS << " const unsigned Empty_SubRegsSet[] = { 0 };\n";
|
OS << " const unsigned Empty_SubRegsSet[] = { 0 };\n";
|
||||||
// Loop over all of the registers which have sub-registers, emitting the
|
// Loop over all of the registers which have sub-registers, emitting the
|
||||||
|
|
Loading…
Reference in New Issue