[NFC] clang-format utils/TableGen (#80973)
``` find llvm/utils/TableGen -iname "*.h" -o -iname "*.cpp" | xargs clang-format-16 -i ``` Split from #80847
This commit is contained in:
committed by
GitHub
parent
173e674ba5
commit
b9079baadd
File diff suppressed because it is too large
Load Diff
@@ -64,6 +64,7 @@ public:
|
||||
AsmWriterEmitter(RecordKeeper &R);
|
||||
|
||||
void run(raw_ostream &o);
|
||||
|
||||
private:
|
||||
void EmitGetMnemonic(
|
||||
raw_ostream &o,
|
||||
@@ -84,9 +85,9 @@ private:
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
static void PrintCases(std::vector<std::pair<std::string,
|
||||
AsmWriterOperand>> &OpsToPrint, raw_ostream &O,
|
||||
bool PassSubtarget) {
|
||||
static void
|
||||
PrintCases(std::vector<std::pair<std::string, AsmWriterOperand>> &OpsToPrint,
|
||||
raw_ostream &O, bool PassSubtarget) {
|
||||
O << " case " << OpsToPrint.back().first << ":";
|
||||
AsmWriterOperand TheOp = OpsToPrint.back().second;
|
||||
OpsToPrint.pop_back();
|
||||
@@ -94,9 +95,9 @@ static void PrintCases(std::vector<std::pair<std::string,
|
||||
// Check to see if any other operands are identical in this list, and if so,
|
||||
// emit a case label for them.
|
||||
for (unsigned i = OpsToPrint.size(); i != 0; --i)
|
||||
if (OpsToPrint[i-1].second == TheOp) {
|
||||
O << "\n case " << OpsToPrint[i-1].first << ":";
|
||||
OpsToPrint.erase(OpsToPrint.begin()+i-1);
|
||||
if (OpsToPrint[i - 1].second == TheOp) {
|
||||
O << "\n case " << OpsToPrint[i - 1].first << ":";
|
||||
OpsToPrint.erase(OpsToPrint.begin() + i - 1);
|
||||
}
|
||||
|
||||
// Finally, emit the code.
|
||||
@@ -106,33 +107,33 @@ static void PrintCases(std::vector<std::pair<std::string,
|
||||
|
||||
/// EmitInstructions - Emit the last instruction in the vector and any other
|
||||
/// instructions that are suitably similar to it.
|
||||
static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
|
||||
raw_ostream &O, bool PassSubtarget) {
|
||||
static void EmitInstructions(std::vector<AsmWriterInst> &Insts, raw_ostream &O,
|
||||
bool PassSubtarget) {
|
||||
AsmWriterInst FirstInst = Insts.back();
|
||||
Insts.pop_back();
|
||||
|
||||
std::vector<AsmWriterInst> SimilarInsts;
|
||||
unsigned DifferingOperand = ~0;
|
||||
for (unsigned i = Insts.size(); i != 0; --i) {
|
||||
unsigned DiffOp = Insts[i-1].MatchesAllButOneOp(FirstInst);
|
||||
unsigned DiffOp = Insts[i - 1].MatchesAllButOneOp(FirstInst);
|
||||
if (DiffOp != ~1U) {
|
||||
if (DifferingOperand == ~0U) // First match!
|
||||
if (DifferingOperand == ~0U) // First match!
|
||||
DifferingOperand = DiffOp;
|
||||
|
||||
// If this differs in the same operand as the rest of the instructions in
|
||||
// this class, move it to the SimilarInsts list.
|
||||
if (DifferingOperand == DiffOp || DiffOp == ~0U) {
|
||||
SimilarInsts.push_back(Insts[i-1]);
|
||||
Insts.erase(Insts.begin()+i-1);
|
||||
SimilarInsts.push_back(Insts[i - 1]);
|
||||
Insts.erase(Insts.begin() + i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
O << " case " << FirstInst.CGI->Namespace << "::"
|
||||
<< FirstInst.CGI->TheDef->getName() << ":\n";
|
||||
O << " case " << FirstInst.CGI->Namespace
|
||||
<< "::" << FirstInst.CGI->TheDef->getName() << ":\n";
|
||||
for (const AsmWriterInst &AWI : SimilarInsts)
|
||||
O << " case " << AWI.CGI->Namespace << "::"
|
||||
<< AWI.CGI->TheDef->getName() << ":\n";
|
||||
O << " case " << AWI.CGI->Namespace << "::" << AWI.CGI->TheDef->getName()
|
||||
<< ":\n";
|
||||
for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) {
|
||||
if (i != DifferingOperand) {
|
||||
// If the operand is the same for all instructions, just print it.
|
||||
@@ -143,14 +144,15 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
|
||||
O << " switch (MI->getOpcode()) {\n";
|
||||
O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";
|
||||
std::vector<std::pair<std::string, AsmWriterOperand>> OpsToPrint;
|
||||
OpsToPrint.push_back(std::make_pair(FirstInst.CGI->Namespace.str() + "::" +
|
||||
FirstInst.CGI->TheDef->getName().str(),
|
||||
FirstInst.Operands[i]));
|
||||
OpsToPrint.push_back(
|
||||
std::make_pair(FirstInst.CGI->Namespace.str() +
|
||||
"::" + FirstInst.CGI->TheDef->getName().str(),
|
||||
FirstInst.Operands[i]));
|
||||
|
||||
for (const AsmWriterInst &AWI : SimilarInsts) {
|
||||
OpsToPrint.push_back(std::make_pair(AWI.CGI->Namespace.str()+"::" +
|
||||
AWI.CGI->TheDef->getName().str(),
|
||||
AWI.Operands[i]));
|
||||
OpsToPrint.push_back(std::make_pair(
|
||||
AWI.CGI->Namespace.str() + "::" + AWI.CGI->TheDef->getName().str(),
|
||||
AWI.Operands[i]));
|
||||
}
|
||||
std::reverse(OpsToPrint.begin(), OpsToPrint.end());
|
||||
while (!OpsToPrint.empty())
|
||||
@@ -162,11 +164,10 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
|
||||
O << " break;\n";
|
||||
}
|
||||
|
||||
void AsmWriterEmitter::
|
||||
FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
|
||||
std::vector<std::vector<unsigned>> &InstIdxs,
|
||||
std::vector<unsigned> &InstOpsUsed,
|
||||
bool PassSubtarget) const {
|
||||
void AsmWriterEmitter::FindUniqueOperandCommands(
|
||||
std::vector<std::string> &UniqueOperandCommands,
|
||||
std::vector<std::vector<unsigned>> &InstIdxs,
|
||||
std::vector<unsigned> &InstOpsUsed, bool PassSubtarget) const {
|
||||
// This vector parallels UniqueOperandCommands, keeping track of which
|
||||
// instructions each case are used for. It is a comma separated string of
|
||||
// enums.
|
||||
@@ -177,9 +178,10 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
|
||||
for (size_t i = 0, e = Instructions.size(); i != e; ++i) {
|
||||
const AsmWriterInst &Inst = Instructions[i];
|
||||
if (Inst.Operands.empty())
|
||||
continue; // Instruction already done.
|
||||
continue; // Instruction already done.
|
||||
|
||||
std::string Command = " "+Inst.Operands[0].getCode(PassSubtarget)+"\n";
|
||||
std::string Command =
|
||||
" " + Inst.Operands[0].getCode(PassSubtarget) + "\n";
|
||||
|
||||
// Check to see if we already have 'Command' in UniqueOperandCommands.
|
||||
// If not, add it.
|
||||
@@ -203,12 +205,12 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
|
||||
// For each entry of UniqueOperandCommands, there is a set of instructions
|
||||
// that uses it. If the next command of all instructions in the set are
|
||||
// identical, fold it into the command.
|
||||
for (size_t CommandIdx = 0, e = UniqueOperandCommands.size();
|
||||
CommandIdx != e; ++CommandIdx) {
|
||||
for (size_t CommandIdx = 0, e = UniqueOperandCommands.size(); CommandIdx != e;
|
||||
++CommandIdx) {
|
||||
|
||||
const auto &Idxs = InstIdxs[CommandIdx];
|
||||
|
||||
for (unsigned Op = 1; ; ++Op) {
|
||||
for (unsigned Op = 1;; ++Op) {
|
||||
// Find the first instruction in the set.
|
||||
const AsmWriterInst &FirstInst = Instructions[Idxs.front()];
|
||||
// If this instruction has no more operands, we isn't anything to merge
|
||||
@@ -227,8 +229,8 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
|
||||
|
||||
// Okay, everything in this command set has the same next operand. Add it
|
||||
// to UniqueOperandCommands and remember that it was consumed.
|
||||
std::string Command = " " +
|
||||
FirstInst.Operands[Op].getCode(PassSubtarget) + "\n";
|
||||
std::string Command =
|
||||
" " + FirstInst.Operands[Op].getCode(PassSubtarget) + "\n";
|
||||
|
||||
UniqueOperandCommands[CommandIdx] += Command;
|
||||
InstOpsUsed[CommandIdx]++;
|
||||
@@ -239,35 +241,58 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
|
||||
for (unsigned i = 0, e = InstrsForCase.size(); i != e; ++i) {
|
||||
std::string Instrs = InstrsForCase[i];
|
||||
if (Instrs.size() > 70) {
|
||||
Instrs.erase(Instrs.begin()+70, Instrs.end());
|
||||
Instrs.erase(Instrs.begin() + 70, Instrs.end());
|
||||
Instrs += "...";
|
||||
}
|
||||
|
||||
if (!Instrs.empty())
|
||||
UniqueOperandCommands[i] = " // " + Instrs + "\n" +
|
||||
UniqueOperandCommands[i];
|
||||
UniqueOperandCommands[i] =
|
||||
" // " + Instrs + "\n" + UniqueOperandCommands[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void UnescapeString(std::string &Str) {
|
||||
for (unsigned i = 0; i != Str.size(); ++i) {
|
||||
if (Str[i] == '\\' && i != Str.size()-1) {
|
||||
switch (Str[i+1]) {
|
||||
default: continue; // Don't execute the code after the switch.
|
||||
case 'a': Str[i] = '\a'; break;
|
||||
case 'b': Str[i] = '\b'; break;
|
||||
case 'e': Str[i] = 27; break;
|
||||
case 'f': Str[i] = '\f'; break;
|
||||
case 'n': Str[i] = '\n'; break;
|
||||
case 'r': Str[i] = '\r'; break;
|
||||
case 't': Str[i] = '\t'; break;
|
||||
case 'v': Str[i] = '\v'; break;
|
||||
case '"': Str[i] = '\"'; break;
|
||||
case '\'': Str[i] = '\''; break;
|
||||
case '\\': Str[i] = '\\'; break;
|
||||
if (Str[i] == '\\' && i != Str.size() - 1) {
|
||||
switch (Str[i + 1]) {
|
||||
default:
|
||||
continue; // Don't execute the code after the switch.
|
||||
case 'a':
|
||||
Str[i] = '\a';
|
||||
break;
|
||||
case 'b':
|
||||
Str[i] = '\b';
|
||||
break;
|
||||
case 'e':
|
||||
Str[i] = 27;
|
||||
break;
|
||||
case 'f':
|
||||
Str[i] = '\f';
|
||||
break;
|
||||
case 'n':
|
||||
Str[i] = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
Str[i] = '\r';
|
||||
break;
|
||||
case 't':
|
||||
Str[i] = '\t';
|
||||
break;
|
||||
case 'v':
|
||||
Str[i] = '\v';
|
||||
break;
|
||||
case '"':
|
||||
Str[i] = '\"';
|
||||
break;
|
||||
case '\'':
|
||||
Str[i] = '\'';
|
||||
break;
|
||||
case '\\':
|
||||
Str[i] = '\\';
|
||||
break;
|
||||
}
|
||||
// Nuke the second character.
|
||||
Str.erase(Str.begin()+i+1);
|
||||
Str.erase(Str.begin() + i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,14 +306,19 @@ static void UnescapeString(std::string &Str) {
|
||||
/// causes non-standard escape character warnings.
|
||||
static void UnescapeAliasString(std::string &Str) {
|
||||
for (unsigned i = 0; i != Str.size(); ++i) {
|
||||
if (Str[i] == '\\' && i != Str.size()-1) {
|
||||
switch (Str[i+1]) {
|
||||
default: continue; // Don't execute the code after the switch.
|
||||
case '{': Str[i] = '{'; break;
|
||||
case '}': Str[i] = '}'; break;
|
||||
if (Str[i] == '\\' && i != Str.size() - 1) {
|
||||
switch (Str[i + 1]) {
|
||||
default:
|
||||
continue; // Don't execute the code after the switch.
|
||||
case '{':
|
||||
Str[i] = '{';
|
||||
break;
|
||||
case '}':
|
||||
Str[i] = '}';
|
||||
break;
|
||||
}
|
||||
// Nuke the second character.
|
||||
Str.erase(Str.begin()+i+1);
|
||||
Str.erase(Str.begin() + i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -318,8 +348,7 @@ void AsmWriterEmitter::EmitGetMnemonic(
|
||||
// Add all strings to the string table upfront so it can generate an optimized
|
||||
// representation.
|
||||
for (AsmWriterInst &AWI : Instructions) {
|
||||
if (AWI.Operands[0].OperandType ==
|
||||
AsmWriterOperand::isLiteralTextOperand &&
|
||||
if (AWI.Operands[0].OperandType == AsmWriterOperand::isLiteralTextOperand &&
|
||||
!AWI.Operands[0].Str.empty()) {
|
||||
std::string Str = AWI.Operands[0].Str;
|
||||
UnescapeString(Str);
|
||||
@@ -347,7 +376,7 @@ void AsmWriterEmitter::EmitGetMnemonic(
|
||||
}
|
||||
|
||||
// Bias offset by one since we want 0 as a sentinel.
|
||||
OpcodeInfo[AWI.CGIIndex] = Idx+1;
|
||||
OpcodeInfo[AWI.CGIIndex] = Idx + 1;
|
||||
}
|
||||
|
||||
// Figure out how many bits we used for the string index.
|
||||
@@ -365,7 +394,8 @@ void AsmWriterEmitter::EmitGetMnemonic(
|
||||
NumInstOpsHandled, PassSubtarget);
|
||||
|
||||
// If we ran out of operands to print, we're done.
|
||||
if (UniqueOperandCommands.empty()) break;
|
||||
if (UniqueOperandCommands.empty())
|
||||
break;
|
||||
|
||||
// Compute the number of bits we need to represent these cases, this is
|
||||
// ceil(log2(numentries)).
|
||||
@@ -383,14 +413,14 @@ void AsmWriterEmitter::EmitGetMnemonic(
|
||||
unsigned NumOps = NumInstOpsHandled[i];
|
||||
for (unsigned Idx : InstIdxs[i]) {
|
||||
OpcodeInfo[Instructions[Idx].CGIIndex] |=
|
||||
(uint64_t)i << (OpcodeInfoBits-BitsLeft);
|
||||
(uint64_t)i << (OpcodeInfoBits - BitsLeft);
|
||||
// Remove the info about this operand from the instruction.
|
||||
AsmWriterInst &Inst = Instructions[Idx];
|
||||
if (!Inst.Operands.empty()) {
|
||||
assert(NumOps <= Inst.Operands.size() &&
|
||||
"Can't remove this many ops!");
|
||||
Inst.Operands.erase(Inst.Operands.begin(),
|
||||
Inst.Operands.begin()+NumOps);
|
||||
Inst.Operands.begin() + NumOps);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -487,7 +517,7 @@ void AsmWriterEmitter::EmitPrintInstruction(
|
||||
<< " assert(Bits != 0 && \"Cannot print this instruction.\");\n";
|
||||
|
||||
// Output the table driven operand information.
|
||||
BitsLeft = OpcodeInfoBits-AsmStrBits;
|
||||
BitsLeft = OpcodeInfoBits - AsmStrBits;
|
||||
for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) {
|
||||
std::vector<std::string> &Commands = TableDrivenOperandPrinters[i];
|
||||
|
||||
@@ -497,25 +527,21 @@ void AsmWriterEmitter::EmitPrintInstruction(
|
||||
assert(NumBits <= BitsLeft && "consistency error");
|
||||
|
||||
// Emit code to extract this field from Bits.
|
||||
O << "\n // Fragment " << i << " encoded into " << NumBits
|
||||
<< " bits for " << Commands.size() << " unique commands.\n";
|
||||
O << "\n // Fragment " << i << " encoded into " << NumBits << " bits for "
|
||||
<< Commands.size() << " unique commands.\n";
|
||||
|
||||
if (Commands.size() == 2) {
|
||||
// Emit two possibilitys with if/else.
|
||||
O << " if ((Bits >> "
|
||||
<< (OpcodeInfoBits-BitsLeft) << ") & "
|
||||
<< ((1 << NumBits)-1) << ") {\n"
|
||||
<< Commands[1]
|
||||
<< " } else {\n"
|
||||
<< Commands[0]
|
||||
<< " }\n\n";
|
||||
O << " if ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & "
|
||||
<< ((1 << NumBits) - 1) << ") {\n"
|
||||
<< Commands[1] << " } else {\n"
|
||||
<< Commands[0] << " }\n\n";
|
||||
} else if (Commands.size() == 1) {
|
||||
// Emit a single possibility.
|
||||
O << Commands[0] << "\n\n";
|
||||
} else {
|
||||
O << " switch ((Bits >> "
|
||||
<< (OpcodeInfoBits-BitsLeft) << ") & "
|
||||
<< ((1 << NumBits)-1) << ") {\n"
|
||||
O << " switch ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & "
|
||||
<< ((1 << NumBits) - 1) << ") {\n"
|
||||
<< " default: llvm_unreachable(\"Invalid command number.\");\n";
|
||||
|
||||
// Print out all the cases.
|
||||
@@ -537,7 +563,6 @@ void AsmWriterEmitter::EmitPrintInstruction(
|
||||
// elements in the vector.
|
||||
std::reverse(Instructions.begin(), Instructions.end());
|
||||
|
||||
|
||||
// Now that we've emitted all of the operand info that fit into 64 bits, emit
|
||||
// information for those instructions that are left. This is a less dense
|
||||
// encoding, but we expect the main 64-bit table to handle the majority of
|
||||
@@ -572,22 +597,21 @@ emitRegisterNameString(raw_ostream &O, StringRef AltName,
|
||||
AsmName = std::string(Reg.getName());
|
||||
} else {
|
||||
// Make sure the register has an alternate name for this index.
|
||||
std::vector<Record*> AltNameList =
|
||||
Reg.TheDef->getValueAsListOfDefs("RegAltNameIndices");
|
||||
std::vector<Record *> AltNameList =
|
||||
Reg.TheDef->getValueAsListOfDefs("RegAltNameIndices");
|
||||
unsigned Idx = 0, e;
|
||||
for (e = AltNameList.size();
|
||||
Idx < e && (AltNameList[Idx]->getName() != AltName);
|
||||
++Idx)
|
||||
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<StringRef> AltNames =
|
||||
Reg.TheDef->getValueAsListOfStrings("AltNames");
|
||||
Reg.TheDef->getValueAsListOfStrings("AltNames");
|
||||
if (AltNames.size() <= Idx)
|
||||
PrintFatalError(Reg.TheDef->getLoc(),
|
||||
"Register definition missing alt name for '" +
|
||||
AltName + "'.");
|
||||
AltName + "'.");
|
||||
AsmName = std::string(AltNames[Idx]);
|
||||
}
|
||||
}
|
||||
@@ -613,15 +637,17 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
|
||||
Record *AsmWriter = Target.getAsmWriter();
|
||||
StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
|
||||
const auto &Registers = Target.getRegBank().getRegisters();
|
||||
const std::vector<Record*> &AltNameIndices = Target.getRegAltNameIndices();
|
||||
const std::vector<Record *> &AltNameIndices = Target.getRegAltNameIndices();
|
||||
bool hasAltNames = AltNameIndices.size() > 1;
|
||||
StringRef Namespace = Registers.front().TheDef->getValueAsString("Namespace");
|
||||
|
||||
O <<
|
||||
"\n\n/// getRegisterName - This method is automatically generated by tblgen\n"
|
||||
"/// from the register set description. This returns the assembler name\n"
|
||||
"/// for the specified register.\n"
|
||||
"const char *" << Target.getName() << ClassName << "::";
|
||||
O << "\n\n/// getRegisterName - This method is automatically generated by "
|
||||
"tblgen\n"
|
||||
"/// from the register set description. This returns the assembler "
|
||||
"name\n"
|
||||
"/// for the specified register.\n"
|
||||
"const char *"
|
||||
<< Target.getName() << ClassName << "::";
|
||||
if (hasAltNames)
|
||||
O << "\ngetRegisterName(MCRegister Reg, unsigned AltIdx) {\n";
|
||||
else
|
||||
@@ -695,8 +721,7 @@ public:
|
||||
|
||||
void addOperand(StringRef Op, int OpIdx, int PrintMethodIdx = -1) {
|
||||
assert(OpIdx >= 0 && OpIdx < 0xFE && "Idx out of range");
|
||||
assert(PrintMethodIdx >= -1 && PrintMethodIdx < 0xFF &&
|
||||
"Idx out of range");
|
||||
assert(PrintMethodIdx >= -1 && PrintMethodIdx < 0xFF && "Idx out of range");
|
||||
OpMap[Op] = std::make_pair(OpIdx, PrintMethodIdx);
|
||||
}
|
||||
|
||||
@@ -791,7 +816,7 @@ namespace {
|
||||
struct AliasPriorityComparator {
|
||||
typedef std::pair<CodeGenInstAlias, int> ValueType;
|
||||
bool operator()(const ValueType &LHS, const ValueType &RHS) const {
|
||||
if (LHS.second == RHS.second) {
|
||||
if (LHS.second == RHS.second) {
|
||||
// We don't actually care about the order, but for consistency it
|
||||
// shouldn't depend on pointer comparisons.
|
||||
return LessRecordByID()(LHS.first.TheDef, RHS.first.TheDef);
|
||||
@@ -819,8 +844,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
|
||||
unsigned Variant = AsmWriter->getValueAsInt("Variant");
|
||||
bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
|
||||
|
||||
std::vector<Record*> AllInstAliases =
|
||||
Records.getAllDerivedDefinitions("InstAlias");
|
||||
std::vector<Record *> AllInstAliases =
|
||||
Records.getAllDerivedDefinitions("InstAlias");
|
||||
|
||||
// Create a map from the qualified name to a list of potential matches.
|
||||
typedef std::set<std::pair<CodeGenInstAlias, int>, AliasPriorityComparator>
|
||||
@@ -843,8 +868,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
|
||||
std::vector<std::pair<std::string, bool>> PrintMethods;
|
||||
|
||||
// A list of MCOperandPredicates for all operands in use, and the reverse map
|
||||
std::vector<const Record*> MCOpPredicates;
|
||||
DenseMap<const Record*, unsigned> MCOpPredicateMap;
|
||||
std::vector<const Record *> MCOpPredicates;
|
||||
DenseMap<const Record *, unsigned> MCOpPredicateMap;
|
||||
|
||||
for (auto &Aliases : AliasMap) {
|
||||
// Collection of instruction alias rules. May contain ambiguous rules.
|
||||
@@ -854,8 +879,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
|
||||
const CodeGenInstAlias &CGA = Alias.first;
|
||||
unsigned LastOpNo = CGA.ResultInstOperandIndex.size();
|
||||
std::string FlatInstAsmString =
|
||||
CodeGenInstruction::FlattenAsmStringVariants(CGA.ResultInst->AsmString,
|
||||
Variant);
|
||||
CodeGenInstruction::FlattenAsmStringVariants(
|
||||
CGA.ResultInst->AsmString, Variant);
|
||||
unsigned NumResultOps = CountNumOperands(FlatInstAsmString, Variant);
|
||||
|
||||
std::string FlatAliasAsmString =
|
||||
@@ -881,8 +906,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
|
||||
unsigned OpNum = Operands.getSubOperandNumber(MIOpNum).first;
|
||||
if (Operands[OpNum].MINumOperands == 1 &&
|
||||
Operands[OpNum].getTiedRegister() != -1) {
|
||||
// Tied operands of different RegisterClass should be explicit within
|
||||
// an instruction's syntax and so cannot be skipped.
|
||||
// Tied operands of different RegisterClass should be explicit
|
||||
// within an instruction's syntax and so cannot be skipped.
|
||||
int TiedOpNum = Operands[OpNum].getTiedRegister();
|
||||
if (Operands[OpNum].Rec->getName() ==
|
||||
Operands[TiedOpNum].Rec->getName()) {
|
||||
@@ -1083,7 +1108,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
|
||||
if (It == IAPrinterMap.end())
|
||||
continue;
|
||||
std::vector<IAPrinter> &IAPs = It->second;
|
||||
std::vector<IAPrinter*> UniqueIAPs;
|
||||
std::vector<IAPrinter *> UniqueIAPs;
|
||||
|
||||
// Remove any ambiguous alias rules.
|
||||
for (auto &LHS : IAPs) {
|
||||
@@ -1099,7 +1124,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
|
||||
UniqueIAPs.push_back(&LHS);
|
||||
}
|
||||
|
||||
if (UniqueIAPs.empty()) continue;
|
||||
if (UniqueIAPs.empty())
|
||||
continue;
|
||||
|
||||
unsigned PatternStart = PatternCount;
|
||||
|
||||
@@ -1193,7 +1219,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
|
||||
if (MCOpPredicates.empty())
|
||||
O.indent(2) << " nullptr,\n";
|
||||
else
|
||||
O.indent(2) << " &" << Target.getName() << ClassName << "ValidateMCOperand,\n";
|
||||
O.indent(2) << " &" << Target.getName() << ClassName
|
||||
<< "ValidateMCOperand,\n";
|
||||
O.indent(2) << "};\n";
|
||||
|
||||
O.indent(2) << "const char *AsmString = matchAliasPatterns(MI, "
|
||||
@@ -1262,21 +1289,22 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
|
||||
<< " break;\n";
|
||||
}
|
||||
O << " }\n";
|
||||
}
|
||||
}
|
||||
O << "}\n\n";
|
||||
|
||||
if (!MCOpPredicates.empty()) {
|
||||
O << "static bool " << Target.getName() << ClassName
|
||||
<< "ValidateMCOperand(const MCOperand &MCOp,\n"
|
||||
<< " const MCSubtargetInfo &STI,\n"
|
||||
<< " unsigned PredicateIndex) {\n"
|
||||
<< " unsigned PredicateIndex) {\n"
|
||||
<< " switch (PredicateIndex) {\n"
|
||||
<< " default:\n"
|
||||
<< " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n"
|
||||
<< " break;\n";
|
||||
|
||||
for (unsigned i = 0; i < MCOpPredicates.size(); ++i) {
|
||||
StringRef MCOpPred = MCOpPredicates[i]->getValueAsString("MCOperandPredicate");
|
||||
StringRef MCOpPred =
|
||||
MCOpPredicates[i]->getValueAsString("MCOperandPredicate");
|
||||
O << " case " << i + 1 << ": {\n"
|
||||
<< MCOpPred.data() << "\n"
|
||||
<< " }\n";
|
||||
|
||||
@@ -57,54 +57,55 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex,
|
||||
std::string::size_type LastEmitted = 0;
|
||||
while (LastEmitted != AsmString.size()) {
|
||||
std::string::size_type DollarPos =
|
||||
AsmString.find_first_of("$\\", LastEmitted);
|
||||
if (DollarPos == std::string::npos) DollarPos = AsmString.size();
|
||||
AsmString.find_first_of("$\\", LastEmitted);
|
||||
if (DollarPos == std::string::npos)
|
||||
DollarPos = AsmString.size();
|
||||
|
||||
// Emit a constant string fragment.
|
||||
if (DollarPos != LastEmitted) {
|
||||
for (; LastEmitted != DollarPos; ++LastEmitted)
|
||||
switch (AsmString[LastEmitted]) {
|
||||
case '\n':
|
||||
AddLiteralString("\\n");
|
||||
break;
|
||||
case '\t':
|
||||
AddLiteralString("\\t");
|
||||
break;
|
||||
case '"':
|
||||
AddLiteralString("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
AddLiteralString("\\\\");
|
||||
break;
|
||||
default:
|
||||
AddLiteralString(std::string(1, AsmString[LastEmitted]));
|
||||
break;
|
||||
case '\n':
|
||||
AddLiteralString("\\n");
|
||||
break;
|
||||
case '\t':
|
||||
AddLiteralString("\\t");
|
||||
break;
|
||||
case '"':
|
||||
AddLiteralString("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
AddLiteralString("\\\\");
|
||||
break;
|
||||
default:
|
||||
AddLiteralString(std::string(1, AsmString[LastEmitted]));
|
||||
break;
|
||||
}
|
||||
} else if (AsmString[DollarPos] == '\\') {
|
||||
if (DollarPos+1 != AsmString.size()) {
|
||||
if (AsmString[DollarPos+1] == 'n') {
|
||||
if (DollarPos + 1 != AsmString.size()) {
|
||||
if (AsmString[DollarPos + 1] == 'n') {
|
||||
AddLiteralString("\\n");
|
||||
} else if (AsmString[DollarPos+1] == 't') {
|
||||
} else if (AsmString[DollarPos + 1] == 't') {
|
||||
AddLiteralString("\\t");
|
||||
} else if (std::string("${|}\\").find(AsmString[DollarPos+1])
|
||||
!= std::string::npos) {
|
||||
AddLiteralString(std::string(1, AsmString[DollarPos+1]));
|
||||
} else if (std::string("${|}\\").find(AsmString[DollarPos + 1]) !=
|
||||
std::string::npos) {
|
||||
AddLiteralString(std::string(1, AsmString[DollarPos + 1]));
|
||||
} else {
|
||||
PrintFatalError(
|
||||
CGI.TheDef->getLoc(),
|
||||
"Non-supported escaped character found in instruction '" +
|
||||
CGI.TheDef->getName() + "'!");
|
||||
}
|
||||
LastEmitted = DollarPos+2;
|
||||
LastEmitted = DollarPos + 2;
|
||||
continue;
|
||||
}
|
||||
} else if (DollarPos+1 != AsmString.size() &&
|
||||
AsmString[DollarPos+1] == '$') {
|
||||
AddLiteralString("$"); // "$$" -> $
|
||||
LastEmitted = DollarPos+2;
|
||||
} else if (DollarPos + 1 != AsmString.size() &&
|
||||
AsmString[DollarPos + 1] == '$') {
|
||||
AddLiteralString("$"); // "$$" -> $
|
||||
LastEmitted = DollarPos + 2;
|
||||
} else {
|
||||
// Get the name of the variable.
|
||||
std::string::size_type VarEnd = DollarPos+1;
|
||||
std::string::size_type VarEnd = DollarPos + 1;
|
||||
|
||||
// handle ${foo}bar as $foo by detecting whether the character following
|
||||
// the dollar sign is a curly brace. If so, advance VarEnd and DollarPos
|
||||
@@ -118,7 +119,8 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex,
|
||||
|
||||
while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
|
||||
++VarEnd;
|
||||
StringRef VarName(AsmString.data()+DollarPos+1, VarEnd-DollarPos-1);
|
||||
StringRef VarName(AsmString.data() + DollarPos + 1,
|
||||
VarEnd - DollarPos - 1);
|
||||
|
||||
// Modifier - Support ${foo:modifier} syntax, where "modifier" is passed
|
||||
// into printOperand. Also support ${:feature}, which is passed into
|
||||
@@ -190,13 +192,14 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex,
|
||||
/// specified instruction except for one differing operand, return the differing
|
||||
/// operand number. If more than one operand mismatches, return ~1, otherwise
|
||||
/// if the instructions are identical return ~0.
|
||||
unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{
|
||||
if (Operands.size() != Other.Operands.size()) return ~1;
|
||||
unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other) const {
|
||||
if (Operands.size() != Other.Operands.size())
|
||||
return ~1;
|
||||
|
||||
unsigned MismatchOperand = ~0U;
|
||||
for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
|
||||
if (Operands[i] != Other.Operands[i]) {
|
||||
if (MismatchOperand != ~0U) // Already have one mismatch?
|
||||
if (MismatchOperand != ~0U) // Already have one mismatch?
|
||||
return ~1U;
|
||||
MismatchOperand = i;
|
||||
}
|
||||
|
||||
@@ -20,88 +20,88 @@
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class CodeGenInstruction;
|
||||
class CodeGenInstruction;
|
||||
|
||||
struct AsmWriterOperand {
|
||||
enum OpType {
|
||||
// Output this text surrounded by quotes to the asm.
|
||||
isLiteralTextOperand,
|
||||
// This is the name of a routine to call to print the operand.
|
||||
isMachineInstrOperand,
|
||||
// Output this text verbatim to the asm writer. It is code that
|
||||
// will output some text to the asm.
|
||||
isLiteralStatementOperand
|
||||
} OperandType;
|
||||
struct AsmWriterOperand {
|
||||
enum OpType {
|
||||
// Output this text surrounded by quotes to the asm.
|
||||
isLiteralTextOperand,
|
||||
// This is the name of a routine to call to print the operand.
|
||||
isMachineInstrOperand,
|
||||
// Output this text verbatim to the asm writer. It is code that
|
||||
// will output some text to the asm.
|
||||
isLiteralStatementOperand
|
||||
} OperandType;
|
||||
|
||||
/// MiOpNo - For isMachineInstrOperand, this is the operand number of the
|
||||
/// machine instruction.
|
||||
unsigned MIOpNo = 0;
|
||||
/// MiOpNo - For isMachineInstrOperand, this is the operand number of the
|
||||
/// machine instruction.
|
||||
unsigned MIOpNo = 0;
|
||||
|
||||
/// Str - For isLiteralTextOperand, this IS the literal text. For
|
||||
/// isMachineInstrOperand, this is the PrinterMethodName for the operand..
|
||||
/// For isLiteralStatementOperand, this is the code to insert verbatim
|
||||
/// into the asm writer.
|
||||
std::string Str;
|
||||
/// Str - For isLiteralTextOperand, this IS the literal text. For
|
||||
/// isMachineInstrOperand, this is the PrinterMethodName for the operand..
|
||||
/// For isLiteralStatementOperand, this is the code to insert verbatim
|
||||
/// into the asm writer.
|
||||
std::string Str;
|
||||
|
||||
/// MiModifier - For isMachineInstrOperand, this is the modifier string for
|
||||
/// an operand, specified with syntax like ${opname:modifier}.
|
||||
std::string MiModifier;
|
||||
/// MiModifier - For isMachineInstrOperand, this is the modifier string for
|
||||
/// an operand, specified with syntax like ${opname:modifier}.
|
||||
std::string MiModifier;
|
||||
|
||||
bool PCRel = false;
|
||||
bool PCRel = false;
|
||||
|
||||
// To make VS STL happy
|
||||
AsmWriterOperand(OpType op = isLiteralTextOperand):OperandType(op) {}
|
||||
// To make VS STL happy
|
||||
AsmWriterOperand(OpType op = isLiteralTextOperand) : OperandType(op) {}
|
||||
|
||||
AsmWriterOperand(const std::string &LitStr,
|
||||
OpType op = isLiteralTextOperand)
|
||||
: OperandType(op), Str(LitStr) {}
|
||||
AsmWriterOperand(const std::string &LitStr, OpType op = isLiteralTextOperand)
|
||||
: OperandType(op), Str(LitStr) {}
|
||||
|
||||
AsmWriterOperand(const std::string &Printer, unsigned _MIOpNo,
|
||||
const std::string &Modifier,
|
||||
OpType op = isMachineInstrOperand, bool PCRel = false)
|
||||
: OperandType(op), MIOpNo(_MIOpNo), Str(Printer), MiModifier(Modifier),
|
||||
PCRel(PCRel) {}
|
||||
AsmWriterOperand(const std::string &Printer, unsigned _MIOpNo,
|
||||
const std::string &Modifier,
|
||||
OpType op = isMachineInstrOperand, bool PCRel = false)
|
||||
: OperandType(op), MIOpNo(_MIOpNo), Str(Printer), MiModifier(Modifier),
|
||||
PCRel(PCRel) {}
|
||||
|
||||
bool operator!=(const AsmWriterOperand &Other) const {
|
||||
if (OperandType != Other.OperandType || Str != Other.Str) return true;
|
||||
if (OperandType == isMachineInstrOperand)
|
||||
return MIOpNo != Other.MIOpNo || MiModifier != Other.MiModifier ||
|
||||
PCRel != Other.PCRel;
|
||||
return false;
|
||||
}
|
||||
bool operator==(const AsmWriterOperand &Other) const {
|
||||
return !operator!=(Other);
|
||||
}
|
||||
bool operator!=(const AsmWriterOperand &Other) const {
|
||||
if (OperandType != Other.OperandType || Str != Other.Str)
|
||||
return true;
|
||||
if (OperandType == isMachineInstrOperand)
|
||||
return MIOpNo != Other.MIOpNo || MiModifier != Other.MiModifier ||
|
||||
PCRel != Other.PCRel;
|
||||
return false;
|
||||
}
|
||||
bool operator==(const AsmWriterOperand &Other) const {
|
||||
return !operator!=(Other);
|
||||
}
|
||||
|
||||
/// getCode - Return the code that prints this operand.
|
||||
std::string getCode(bool PassSubtarget) const;
|
||||
};
|
||||
/// getCode - Return the code that prints this operand.
|
||||
std::string getCode(bool PassSubtarget) const;
|
||||
};
|
||||
|
||||
class AsmWriterInst {
|
||||
public:
|
||||
std::vector<AsmWriterOperand> Operands;
|
||||
const CodeGenInstruction *CGI;
|
||||
unsigned CGIIndex;
|
||||
class AsmWriterInst {
|
||||
public:
|
||||
std::vector<AsmWriterOperand> Operands;
|
||||
const CodeGenInstruction *CGI;
|
||||
unsigned CGIIndex;
|
||||
|
||||
AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex,
|
||||
unsigned Variant);
|
||||
AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex,
|
||||
unsigned Variant);
|
||||
|
||||
/// MatchesAllButOneOp - If this instruction is exactly identical to the
|
||||
/// specified instruction except for one differing operand, return the
|
||||
/// differing operand number. Otherwise return ~0.
|
||||
unsigned MatchesAllButOneOp(const AsmWriterInst &Other) const;
|
||||
/// MatchesAllButOneOp - If this instruction is exactly identical to the
|
||||
/// specified instruction except for one differing operand, return the
|
||||
/// differing operand number. Otherwise return ~0.
|
||||
unsigned MatchesAllButOneOp(const AsmWriterInst &Other) const;
|
||||
|
||||
private:
|
||||
void AddLiteralString(const std::string &Str) {
|
||||
// If the last operand was already a literal text string, append this to
|
||||
// it, otherwise add a new operand.
|
||||
if (!Operands.empty() &&
|
||||
Operands.back().OperandType == AsmWriterOperand::isLiteralTextOperand)
|
||||
Operands.back().Str.append(Str);
|
||||
else
|
||||
Operands.push_back(AsmWriterOperand(Str));
|
||||
}
|
||||
};
|
||||
}
|
||||
private:
|
||||
void AddLiteralString(const std::string &Str) {
|
||||
// If the last operand was already a literal text string, append this to
|
||||
// it, otherwise add a new operand.
|
||||
if (!Operands.empty() &&
|
||||
Operands.back().OperandType == AsmWriterOperand::isLiteralTextOperand)
|
||||
Operands.back().Str.append(Str);
|
||||
else
|
||||
Operands.push_back(AsmWriterOperand(Str));
|
||||
}
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===- CTagsEmitter.cpp - Generate ctags-compatible index ------------------===//
|
||||
//===- CTagsEmitter.cpp - Generate ctags-compatible index -----------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@@ -30,6 +30,7 @@ private:
|
||||
StringRef Id;
|
||||
StringRef BufferIdentifier;
|
||||
unsigned Line;
|
||||
|
||||
public:
|
||||
Tag(StringRef Name, const SMLoc Location) : Id(Name) {
|
||||
const MemoryBuffer *CurMB =
|
||||
@@ -39,7 +40,8 @@ public:
|
||||
Line = LineAndColumn.first;
|
||||
}
|
||||
int operator<(const Tag &B) const {
|
||||
return std::make_tuple(Id, BufferIdentifier, Line) < std::make_tuple(B.Id, B.BufferIdentifier, B.Line);
|
||||
return std::make_tuple(Id, BufferIdentifier, Line) <
|
||||
std::make_tuple(B.Id, B.BufferIdentifier, B.Line);
|
||||
}
|
||||
void emit(raw_ostream &OS) const {
|
||||
OS << Id << "\t" << BufferIdentifier << "\t" << Line << "\n";
|
||||
@@ -49,6 +51,7 @@ public:
|
||||
class CTagsEmitter {
|
||||
private:
|
||||
RecordKeeper &Records;
|
||||
|
||||
public:
|
||||
CTagsEmitter(RecordKeeper &R) : Records(R) {}
|
||||
|
||||
|
||||
@@ -117,23 +117,24 @@ void CallingConvEmitter::EmitCallingConv(Record *CC, raw_ostream &O) {
|
||||
O << "\n";
|
||||
EmitAction(Action, 2, O);
|
||||
}
|
||||
|
||||
|
||||
O << "\n return true; // CC didn't match.\n";
|
||||
O << "}\n";
|
||||
}
|
||||
|
||||
void CallingConvEmitter::EmitAction(Record *Action,
|
||||
unsigned Indent, raw_ostream &O) {
|
||||
void CallingConvEmitter::EmitAction(Record *Action, unsigned Indent,
|
||||
raw_ostream &O) {
|
||||
std::string IndentStr = std::string(Indent, ' ');
|
||||
|
||||
if (Action->isSubClassOf("CCPredicateAction")) {
|
||||
O << IndentStr << "if (";
|
||||
|
||||
|
||||
if (Action->isSubClassOf("CCIfType")) {
|
||||
ListInit *VTs = Action->getValueAsListInit("VTs");
|
||||
for (unsigned i = 0, e = VTs->size(); i != e; ++i) {
|
||||
Record *VT = VTs->getElementAsRecord(i);
|
||||
if (i != 0) O << " ||\n " << IndentStr;
|
||||
if (i != 0)
|
||||
O << " ||\n " << IndentStr;
|
||||
O << "LocVT == " << getEnumName(getValueType(VT));
|
||||
}
|
||||
|
||||
@@ -143,9 +144,9 @@ void CallingConvEmitter::EmitAction(Record *Action,
|
||||
errs() << *Action;
|
||||
PrintFatalError(Action->getLoc(), "Unknown CCPredicateAction!");
|
||||
}
|
||||
|
||||
|
||||
O << ") {\n";
|
||||
EmitAction(Action->getValueAsDef("SubAction"), Indent+2, O);
|
||||
EmitAction(Action->getValueAsDef("SubAction"), Indent + 2, O);
|
||||
O << IndentStr << "}\n";
|
||||
} else {
|
||||
if (Action->isSubClassOf("CCDelegateTo")) {
|
||||
@@ -241,8 +242,8 @@ void CallingConvEmitter::EmitAction(Record *Action,
|
||||
O << "\n" << IndentStr << "};\n";
|
||||
|
||||
O << IndentStr << "if (unsigned Reg = State.AllocateReg(RegList"
|
||||
<< RegListNumber << ", " << "RegList" << ShadowRegListNumber
|
||||
<< ")) {\n";
|
||||
<< RegListNumber << ", "
|
||||
<< "RegList" << ShadowRegListNumber << ")) {\n";
|
||||
}
|
||||
O << IndentStr << " State.addLoc(CCValAssign::getReg(ValNo, ValVT, "
|
||||
<< "Reg, LocVT, LocInfo));\n";
|
||||
@@ -257,7 +258,8 @@ void CallingConvEmitter::EmitAction(Record *Action,
|
||||
if (Size)
|
||||
O << Size << ", ";
|
||||
else
|
||||
O << "\n" << IndentStr
|
||||
O << "\n"
|
||||
<< IndentStr
|
||||
<< " State.getMachineFunction().getDataLayout()."
|
||||
"getTypeAllocSize(EVT(LocVT).getTypeForEVT(State.getContext())),"
|
||||
" ";
|
||||
@@ -269,8 +271,8 @@ void CallingConvEmitter::EmitAction(Record *Action,
|
||||
<< " State.getMachineFunction().getDataLayout()."
|
||||
"getABITypeAlign(EVT(LocVT).getTypeForEVT(State.getContext()"
|
||||
"))";
|
||||
O << ");\n" << IndentStr
|
||||
<< "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset"
|
||||
O << ");\n"
|
||||
<< IndentStr << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset"
|
||||
<< Counter << ", LocVT, LocInfo));\n";
|
||||
O << IndentStr << "return false;\n";
|
||||
} else if (Action->isSubClassOf("CCAssignToStackWithShadow")) {
|
||||
@@ -281,7 +283,7 @@ void CallingConvEmitter::EmitAction(Record *Action,
|
||||
unsigned ShadowRegListNumber = ++Counter;
|
||||
|
||||
O << IndentStr << "static const MCPhysReg ShadowRegList"
|
||||
<< ShadowRegListNumber << "[] = {\n";
|
||||
<< ShadowRegListNumber << "[] = {\n";
|
||||
O << IndentStr << " ";
|
||||
ListSeparator LS;
|
||||
for (unsigned i = 0, e = ShadowRegList->size(); i != e; ++i)
|
||||
@@ -297,7 +299,7 @@ void CallingConvEmitter::EmitAction(Record *Action,
|
||||
} else if (Action->isSubClassOf("CCPromoteToType")) {
|
||||
Record *DestTy = Action->getValueAsDef("DestTy");
|
||||
MVT::SimpleValueType DestVT = getValueType(DestTy);
|
||||
O << IndentStr << "LocVT = " << getEnumName(DestVT) <<";\n";
|
||||
O << IndentStr << "LocVT = " << getEnumName(DestVT) << ";\n";
|
||||
if (MVT(DestVT).isFloatingPoint()) {
|
||||
O << IndentStr << "LocInfo = CCValAssign::FPExt;\n";
|
||||
} else {
|
||||
@@ -326,15 +328,18 @@ void CallingConvEmitter::EmitAction(Record *Action,
|
||||
}
|
||||
} else if (Action->isSubClassOf("CCBitConvertToType")) {
|
||||
Record *DestTy = Action->getValueAsDef("DestTy");
|
||||
O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n";
|
||||
O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy))
|
||||
<< ";\n";
|
||||
O << IndentStr << "LocInfo = CCValAssign::BCvt;\n";
|
||||
} else if (Action->isSubClassOf("CCTruncToType")) {
|
||||
Record *DestTy = Action->getValueAsDef("DestTy");
|
||||
O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n";
|
||||
O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy))
|
||||
<< ";\n";
|
||||
O << IndentStr << "LocInfo = CCValAssign::Trunc;\n";
|
||||
} else if (Action->isSubClassOf("CCPassIndirect")) {
|
||||
Record *DestTy = Action->getValueAsDef("DestTy");
|
||||
O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n";
|
||||
O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy))
|
||||
<< ";\n";
|
||||
O << IndentStr << "LocInfo = CCValAssign::Indirect;\n";
|
||||
} else if (Action->isSubClassOf("CCPassByVal")) {
|
||||
int Size = Action->getValueAsInt("Size");
|
||||
@@ -343,8 +348,8 @@ void CallingConvEmitter::EmitAction(Record *Action,
|
||||
<< Size << ", Align(" << Align << "), ArgFlags);\n";
|
||||
O << IndentStr << "return false;\n";
|
||||
} else if (Action->isSubClassOf("CCCustom")) {
|
||||
O << IndentStr
|
||||
<< "if (" << Action->getValueAsString("FuncName") << "(ValNo, ValVT, "
|
||||
O << IndentStr << "if (" << Action->getValueAsString("FuncName")
|
||||
<< "(ValNo, ValVT, "
|
||||
<< "LocVT, LocInfo, ArgFlags, State))\n";
|
||||
O << IndentStr << " return false;\n";
|
||||
} else {
|
||||
@@ -376,9 +381,8 @@ void CallingConvEmitter::EmitArgRegisterLists(raw_ostream &O) {
|
||||
std::set<std::string> &InnerRegisters = InnerEntry.second;
|
||||
|
||||
if (InnerRegisters.find(CCName) != InnerRegisters.end()) {
|
||||
AssignedRegsMap[InnerCCName].insert(
|
||||
AssignedRegsMap[CCName].begin(),
|
||||
AssignedRegsMap[CCName].end());
|
||||
AssignedRegsMap[InnerCCName].insert(AssignedRegsMap[CCName].begin(),
|
||||
AssignedRegsMap[CCName].end());
|
||||
InnerRegisters.erase(CCName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,8 +78,8 @@ private:
|
||||
|
||||
// If the VarBitInit at position 'bit' matches the specified variable then
|
||||
// return the variable bit position. Otherwise return -1.
|
||||
int CodeEmitterGen::getVariableBit(const std::string &VarName,
|
||||
BitsInit *BI, int bit) {
|
||||
int CodeEmitterGen::getVariableBit(const std::string &VarName, BitsInit *BI,
|
||||
int bit) {
|
||||
if (VarBitInit *VBI = dyn_cast<VarBitInit>(BI->getBit(bit))) {
|
||||
if (VarInit *VI = dyn_cast<VarInit>(VBI->getBitVar()))
|
||||
if (VI->getName() == VarName)
|
||||
@@ -101,16 +101,16 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
|
||||
CodeGenInstruction &CGI = Target.getInstruction(R);
|
||||
|
||||
// Determine if VarName actually contributes to the Inst encoding.
|
||||
int bit = BI->getNumBits()-1;
|
||||
int bit = BI->getNumBits() - 1;
|
||||
|
||||
// Scan for a bit that this contributed to.
|
||||
for (; bit >= 0; ) {
|
||||
for (; bit >= 0;) {
|
||||
if (getVariableBit(VarName, BI, bit) != -1)
|
||||
break;
|
||||
|
||||
|
||||
--bit;
|
||||
}
|
||||
|
||||
|
||||
// If we found no bits, ignore this value, otherwise emit the call to get the
|
||||
// operand encoding.
|
||||
if (bit < 0)
|
||||
@@ -127,12 +127,14 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
|
||||
// Get the machine operand number for the indicated operand.
|
||||
OpIdx = CGI.Operands[OpIdx].MIOperandNo;
|
||||
} else {
|
||||
PrintError(R, Twine("No operand named ") + VarName + " in record " + R->getName());
|
||||
PrintError(R, Twine("No operand named ") + VarName + " in record " +
|
||||
R->getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CGI.Operands.isFlatOperandNotEmitted(OpIdx)) {
|
||||
PrintError(R, "Operand " + VarName + " used but also marked as not emitted!");
|
||||
PrintError(R,
|
||||
"Operand " + VarName + " used but also marked as not emitted!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -156,10 +158,12 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
|
||||
Case += ", Fixups, STI);\n";
|
||||
} else {
|
||||
if (UseAPInt) {
|
||||
Case += " getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
|
||||
Case +=
|
||||
" getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
|
||||
Case += ", op, Fixups, STI";
|
||||
} else {
|
||||
Case += " op = getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
|
||||
Case += " op = getMachineOpValue(MI, MI.getOperand(" +
|
||||
utostr(OpIdx) + ")";
|
||||
Case += ", Fixups, STI";
|
||||
}
|
||||
Case += ");\n";
|
||||
@@ -193,9 +197,9 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
|
||||
}
|
||||
|
||||
unsigned BitOffset = -1;
|
||||
for (; bit >= 0; ) {
|
||||
for (; bit >= 0;) {
|
||||
int varBit = getVariableBit(VarName, BI, bit);
|
||||
|
||||
|
||||
// If this bit isn't from a variable, skip it.
|
||||
if (varBit == -1) {
|
||||
--bit;
|
||||
@@ -209,7 +213,8 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
|
||||
int N = 1;
|
||||
for (--bit; bit >= 0;) {
|
||||
varBit = getVariableBit(VarName, BI, bit);
|
||||
if (varBit == -1 || varBit != (beginVarBit - N)) break;
|
||||
if (varBit == -1 || varBit != (beginVarBit - N))
|
||||
break;
|
||||
++N;
|
||||
--bit;
|
||||
}
|
||||
@@ -368,7 +373,9 @@ void CodeEmitterGen::emitInstructionBaseValues(
|
||||
|
||||
if (R->getValueAsString("Namespace") == "TargetOpcode" ||
|
||||
R->getValueAsBit("isPseudo")) {
|
||||
o << " "; emitInstBits(o, APInt(BitWidth, 0)); o << ",\n";
|
||||
o << " ";
|
||||
emitInstBits(o, APInt(BitWidth, 0));
|
||||
o << ",\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -419,13 +426,13 @@ void CodeEmitterGen::run(raw_ostream &o) {
|
||||
emitSourceFileHeader("Machine Code Emitter", o);
|
||||
|
||||
CodeGenTarget Target(Records);
|
||||
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
|
||||
std::vector<Record *> Insts = Records.getAllDerivedDefinitions("Instruction");
|
||||
|
||||
// For little-endian instruction bit encodings, reverse the bit order
|
||||
Target.reverseBitsForLittleEndianEncoding();
|
||||
|
||||
ArrayRef<const CodeGenInstruction*> NumberedInstructions =
|
||||
Target.getInstructionsByEnumValue();
|
||||
ArrayRef<const CodeGenInstruction *> NumberedInstructions =
|
||||
Target.getInstructionsByEnumValue();
|
||||
|
||||
if (any_of(NumberedInstructions, [](const CodeGenInstruction *CGI) {
|
||||
Record *R = CGI->TheDef;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -56,17 +56,15 @@ struct MachineValueTypeSet {
|
||||
static_assert(std::is_same<std::underlying_type_t<MVT::SimpleValueType>,
|
||||
uint8_t>::value,
|
||||
"Change uint8_t here to the SimpleValueType's type");
|
||||
static unsigned constexpr Capacity = std::numeric_limits<uint8_t>::max()+1;
|
||||
static unsigned constexpr Capacity = std::numeric_limits<uint8_t>::max() + 1;
|
||||
using WordType = uint64_t;
|
||||
static unsigned constexpr WordWidth = CHAR_BIT*sizeof(WordType);
|
||||
static unsigned constexpr NumWords = Capacity/WordWidth;
|
||||
static_assert(NumWords*WordWidth == Capacity,
|
||||
static unsigned constexpr WordWidth = CHAR_BIT * sizeof(WordType);
|
||||
static unsigned constexpr NumWords = Capacity / WordWidth;
|
||||
static_assert(NumWords * WordWidth == Capacity,
|
||||
"Capacity should be a multiple of WordWidth");
|
||||
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
MachineValueTypeSet() {
|
||||
clear();
|
||||
}
|
||||
MachineValueTypeSet() { clear(); }
|
||||
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
unsigned size() const {
|
||||
@@ -76,9 +74,7 @@ struct MachineValueTypeSet {
|
||||
return Count;
|
||||
}
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
void clear() {
|
||||
std::memset(Words.data(), 0, NumWords*sizeof(WordType));
|
||||
}
|
||||
void clear() { std::memset(Words.data(), 0, NumWords * sizeof(WordType)); }
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool empty() const {
|
||||
for (WordType W : Words)
|
||||
@@ -90,7 +86,7 @@ struct MachineValueTypeSet {
|
||||
unsigned count(MVT T) const {
|
||||
return (Words[T.SimpleTy / WordWidth] >> (T.SimpleTy % WordWidth)) & 1;
|
||||
}
|
||||
std::pair<MachineValueTypeSet&,bool> insert(MVT T) {
|
||||
std::pair<MachineValueTypeSet &, bool> insert(MVT T) {
|
||||
bool V = count(T.SimpleTy);
|
||||
Words[T.SimpleTy / WordWidth] |= WordType(1) << (T.SimpleTy % WordWidth);
|
||||
return {*this, V};
|
||||
@@ -113,8 +109,8 @@ struct MachineValueTypeSet {
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = MVT;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = const MVT*;
|
||||
using reference = const MVT&;
|
||||
using pointer = const MVT *;
|
||||
using reference = const MVT &;
|
||||
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
MVT operator*() const {
|
||||
@@ -128,7 +124,7 @@ struct MachineValueTypeSet {
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
const_iterator &operator++() {
|
||||
assert(Pos != Capacity);
|
||||
Pos = find_from_pos(Pos+1);
|
||||
Pos = find_from_pos(Pos + 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -137,9 +133,7 @@ struct MachineValueTypeSet {
|
||||
return Set == It.Set && Pos == It.Pos;
|
||||
}
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool operator!=(const const_iterator &It) const {
|
||||
return !operator==(It);
|
||||
}
|
||||
bool operator!=(const const_iterator &It) const { return !operator==(It); }
|
||||
|
||||
private:
|
||||
unsigned find_from_pos(unsigned P) const {
|
||||
@@ -151,7 +145,7 @@ struct MachineValueTypeSet {
|
||||
// the trailing bits need to be masked off to use findFirstSet.
|
||||
if (SkipBits != 0) {
|
||||
WordType W = Set->Words[SkipWords];
|
||||
W &= maskLeadingOnes<WordType>(WordWidth-SkipBits);
|
||||
W &= maskLeadingOnes<WordType>(WordWidth - SkipBits);
|
||||
if (W != 0)
|
||||
return Count + llvm::countr_zero(W);
|
||||
Count += WordWidth;
|
||||
@@ -174,20 +168,18 @@ struct MachineValueTypeSet {
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
const_iterator begin() const { return const_iterator(this, false); }
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
const_iterator end() const { return const_iterator(this, true); }
|
||||
const_iterator end() const { return const_iterator(this, true); }
|
||||
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool operator==(const MachineValueTypeSet &S) const {
|
||||
return Words == S.Words;
|
||||
}
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool operator!=(const MachineValueTypeSet &S) const {
|
||||
return !operator==(S);
|
||||
}
|
||||
bool operator!=(const MachineValueTypeSet &S) const { return !operator==(S); }
|
||||
|
||||
private:
|
||||
friend struct const_iterator;
|
||||
std::array<WordType,NumWords> Words;
|
||||
std::array<WordType, NumWords> Words;
|
||||
};
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const MachineValueTypeSet &T);
|
||||
@@ -200,14 +192,12 @@ struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> {
|
||||
TypeSetByHwMode(const TypeSetByHwMode &VTS) = default;
|
||||
TypeSetByHwMode &operator=(const TypeSetByHwMode &) = default;
|
||||
TypeSetByHwMode(MVT::SimpleValueType VT)
|
||||
: TypeSetByHwMode(ValueTypeByHwMode(VT)) {}
|
||||
: TypeSetByHwMode(ValueTypeByHwMode(VT)) {}
|
||||
TypeSetByHwMode(ValueTypeByHwMode VT)
|
||||
: TypeSetByHwMode(ArrayRef<ValueTypeByHwMode>(&VT, 1)) {}
|
||||
: TypeSetByHwMode(ArrayRef<ValueTypeByHwMode>(&VT, 1)) {}
|
||||
TypeSetByHwMode(ArrayRef<ValueTypeByHwMode> VTList);
|
||||
|
||||
SetType &getOrCreate(unsigned Mode) {
|
||||
return Map[Mode];
|
||||
}
|
||||
SetType &getOrCreate(unsigned Mode) { return Map[Mode]; }
|
||||
|
||||
bool isValueTypeByHwMode(bool AllowEmpty) const;
|
||||
ValueTypeByHwMode getValueTypeByHwMode() const;
|
||||
@@ -225,9 +215,7 @@ struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> {
|
||||
|
||||
bool isPossible() const;
|
||||
|
||||
bool isPointer() const {
|
||||
return getValueTypeByHwMode().isPointer();
|
||||
}
|
||||
bool isPointer() const { return getValueTypeByHwMode().isPointer(); }
|
||||
|
||||
unsigned getPtrAddrSpace() const {
|
||||
assert(isPointer());
|
||||
@@ -313,8 +301,7 @@ struct TypeInfer {
|
||||
/// Ensure that for each type T in \p Sub, T is a vector type, and there
|
||||
/// exists a type U in \p Vec such that U is a vector type with the same
|
||||
/// element type as T and at least as many elements as T.
|
||||
bool EnforceVectorSubVectorTypeIs(TypeSetByHwMode &Vec,
|
||||
TypeSetByHwMode &Sub);
|
||||
bool EnforceVectorSubVectorTypeIs(TypeSetByHwMode &Vec, TypeSetByHwMode &Sub);
|
||||
/// 1. Ensure that \p V has a scalar type iff \p W has a scalar type.
|
||||
/// 2. Ensure that for each vector type T in \p V, there exists a vector
|
||||
/// type U in \p W, such that T and U have the same number of elements.
|
||||
@@ -346,15 +333,13 @@ struct TypeInfer {
|
||||
SuppressValidation(TypeInfer &TI) : Infer(TI), SavedValidate(TI.Validate) {
|
||||
Infer.Validate = false;
|
||||
}
|
||||
~SuppressValidation() {
|
||||
Infer.Validate = SavedValidate;
|
||||
}
|
||||
~SuppressValidation() { Infer.Validate = SavedValidate; }
|
||||
TypeInfer &Infer;
|
||||
bool SavedValidate;
|
||||
};
|
||||
|
||||
TreePattern &TP;
|
||||
bool Validate = true; // Indicate whether to validate types.
|
||||
bool Validate = true; // Indicate whether to validate types.
|
||||
|
||||
private:
|
||||
const TypeSetByHwMode &getLegalTypes() const;
|
||||
@@ -372,14 +357,24 @@ typedef StringSet<> MultipleUseVarSet;
|
||||
struct SDTypeConstraint {
|
||||
SDTypeConstraint(Record *R, const CodeGenHwModes &CGH);
|
||||
|
||||
unsigned OperandNo; // The operand # this constraint applies to.
|
||||
unsigned OperandNo; // The operand # this constraint applies to.
|
||||
enum {
|
||||
SDTCisVT, SDTCisPtrTy, SDTCisInt, SDTCisFP, SDTCisVec, SDTCisSameAs,
|
||||
SDTCisVTSmallerThanOp, SDTCisOpSmallerThanOp, SDTCisEltOfVec,
|
||||
SDTCisSubVecOfVec, SDTCVecEltisVT, SDTCisSameNumEltsAs, SDTCisSameSizeAs
|
||||
SDTCisVT,
|
||||
SDTCisPtrTy,
|
||||
SDTCisInt,
|
||||
SDTCisFP,
|
||||
SDTCisVec,
|
||||
SDTCisSameAs,
|
||||
SDTCisVTSmallerThanOp,
|
||||
SDTCisOpSmallerThanOp,
|
||||
SDTCisEltOfVec,
|
||||
SDTCisSubVecOfVec,
|
||||
SDTCVecEltisVT,
|
||||
SDTCisSameNumEltsAs,
|
||||
SDTCisSameSizeAs
|
||||
} ConstraintType;
|
||||
|
||||
union { // The discriminated union.
|
||||
union { // The discriminated union.
|
||||
struct {
|
||||
unsigned OtherOperandNum;
|
||||
} SDTCisSameAs_Info;
|
||||
@@ -422,6 +417,7 @@ struct SDTypeConstraint {
|
||||
class ScopedName {
|
||||
unsigned Scope;
|
||||
std::string Identifier;
|
||||
|
||||
public:
|
||||
ScopedName(unsigned Scope, StringRef Identifier)
|
||||
: Scope(Scope), Identifier(std::string(Identifier)) {
|
||||
@@ -447,6 +443,7 @@ class SDNodeInfo {
|
||||
unsigned NumResults;
|
||||
int NumOperands;
|
||||
std::vector<SDTypeConstraint> TypeConstraints;
|
||||
|
||||
public:
|
||||
// Parse the specified record.
|
||||
SDNodeInfo(Record *R, const CodeGenHwModes &CGH);
|
||||
@@ -487,11 +484,11 @@ class TreePredicateFn {
|
||||
/// PatFragRec - This is the TreePattern for the PatFrag that we
|
||||
/// originally came from.
|
||||
TreePattern *PatFragRec;
|
||||
|
||||
public:
|
||||
/// TreePredicateFn constructor. Here 'N' is a subclass of PatFrag.
|
||||
TreePredicateFn(TreePattern *N);
|
||||
|
||||
|
||||
TreePattern *getOrigPatFragRecord() const { return PatFragRec; }
|
||||
|
||||
/// isAlwaysTrue - Return true if this is a noop predicate.
|
||||
@@ -582,7 +579,8 @@ public:
|
||||
bool isAtomicOrderingWeakerThanRelease() const;
|
||||
|
||||
/// If non-null, indicates that this predicate is a predefined memory VT
|
||||
/// predicate for a load/store and returns the ValueType record for the memory VT.
|
||||
/// predicate for a load/store and returns the ValueType record for the memory
|
||||
/// VT.
|
||||
Record *getMemoryVT() const;
|
||||
/// If non-null, indicates that this predicate is a predefined memory VT
|
||||
/// predicate (checking only the scalar type) for load/store and returns the
|
||||
@@ -615,14 +613,12 @@ struct TreePredicateCall {
|
||||
unsigned Scope;
|
||||
|
||||
TreePredicateCall(const TreePredicateFn &Fn, unsigned Scope)
|
||||
: Fn(Fn), Scope(Scope) {}
|
||||
: Fn(Fn), Scope(Scope) {}
|
||||
|
||||
bool operator==(const TreePredicateCall &o) const {
|
||||
return Fn == o.Fn && Scope == o.Scope;
|
||||
}
|
||||
bool operator!=(const TreePredicateCall &o) const {
|
||||
return !(*this == o);
|
||||
}
|
||||
bool operator!=(const TreePredicateCall &o) const { return !(*this == o); }
|
||||
};
|
||||
|
||||
class TreePatternNode : public RefCountedBase<TreePatternNode> {
|
||||
@@ -681,7 +677,7 @@ public:
|
||||
const std::vector<ScopedName> &getNamesAsPredicateArg() const {
|
||||
return NamesAsPredicateArg;
|
||||
}
|
||||
void setNamesAsPredicateArg(const std::vector<ScopedName>& Names) {
|
||||
void setNamesAsPredicateArg(const std::vector<ScopedName> &Names) {
|
||||
NamesAsPredicateArg = Names;
|
||||
}
|
||||
void addNameAsPredicateArg(const ScopedName &N) {
|
||||
@@ -733,9 +729,7 @@ public:
|
||||
const TreePatternNodePtr &getChildShared(unsigned N) const {
|
||||
return Children[N];
|
||||
}
|
||||
TreePatternNodePtr &getChildSharedPtr(unsigned N) {
|
||||
return Children[N];
|
||||
}
|
||||
TreePatternNodePtr &getChildSharedPtr(unsigned N) { return Children[N]; }
|
||||
void setChild(unsigned i, TreePatternNodePtr N) { Children[i] = N; }
|
||||
|
||||
/// hasChild - Return true if N is any of our children.
|
||||
@@ -762,7 +756,8 @@ public:
|
||||
}
|
||||
void addPredicateCall(const TreePredicateCall &Call) {
|
||||
assert(!Call.Fn.isAlwaysTrue() && "Empty predicate string!");
|
||||
assert(!is_contained(PredicateCalls, Call) && "predicate applied recursively");
|
||||
assert(!is_contained(PredicateCalls, Call) &&
|
||||
"predicate applied recursively");
|
||||
PredicateCalls.push_back(Call);
|
||||
}
|
||||
void addPredicateCall(const TreePredicateFn &Fn, unsigned Scope) {
|
||||
@@ -805,8 +800,7 @@ public:
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
public: // Higher level manipulation routines.
|
||||
|
||||
public: // Higher level manipulation routines.
|
||||
/// clone - Return a new copy of this tree.
|
||||
///
|
||||
TreePatternNodePtr clone() const;
|
||||
@@ -845,8 +839,7 @@ public: // Higher level manipulation routines.
|
||||
TreePattern &TP);
|
||||
bool UpdateNodeType(unsigned ResNo, MVT::SimpleValueType InTy,
|
||||
TreePattern &TP);
|
||||
bool UpdateNodeType(unsigned ResNo, ValueTypeByHwMode InTy,
|
||||
TreePattern &TP);
|
||||
bool UpdateNodeType(unsigned ResNo, ValueTypeByHwMode InTy, TreePattern &TP);
|
||||
|
||||
// Update node type with types inferred from an instruction operand or result
|
||||
// def from the ins/outs lists.
|
||||
@@ -910,7 +903,6 @@ class TreePattern {
|
||||
TypeInfer Infer;
|
||||
|
||||
public:
|
||||
|
||||
/// TreePattern constructor - Parse the specified DagInits into the
|
||||
/// current record.
|
||||
TreePattern(Record *TheRec, ListInit *RawPat, bool isInput,
|
||||
@@ -971,12 +963,8 @@ public:
|
||||
/// error - If this is the first error in the current resolution step,
|
||||
/// print it and set the error flag. Otherwise, continue silently.
|
||||
void error(const Twine &Msg);
|
||||
bool hasError() const {
|
||||
return HasError;
|
||||
}
|
||||
void resetError() {
|
||||
HasError = false;
|
||||
}
|
||||
bool hasError() const { return HasError; }
|
||||
void resetError() { HasError = false; }
|
||||
|
||||
TypeInfer &getInfer() { return Infer; }
|
||||
|
||||
@@ -989,7 +977,6 @@ private:
|
||||
void ComputeNamedNodes(TreePatternNode *N);
|
||||
};
|
||||
|
||||
|
||||
inline bool TreePatternNode::UpdateNodeType(unsigned ResNo,
|
||||
const TypeSetByHwMode &InTy,
|
||||
TreePattern &TP) {
|
||||
@@ -1014,7 +1001,6 @@ inline bool TreePatternNode::UpdateNodeType(unsigned ResNo,
|
||||
return TP.getInfer().MergeInTypeInfo(Types[ResNo], VTS);
|
||||
}
|
||||
|
||||
|
||||
/// DAGDefaultOperand - One of these is created for each OperandWithDefaultOps
|
||||
/// that has a set ExecuteAlways / DefaultOps field.
|
||||
struct DAGDefaultOperand {
|
||||
@@ -1022,9 +1008,9 @@ struct DAGDefaultOperand {
|
||||
};
|
||||
|
||||
class DAGInstruction {
|
||||
std::vector<Record*> Results;
|
||||
std::vector<Record*> Operands;
|
||||
std::vector<Record*> ImpResults;
|
||||
std::vector<Record *> Results;
|
||||
std::vector<Record *> Operands;
|
||||
std::vector<Record *> ImpResults;
|
||||
TreePatternNodePtr SrcPattern;
|
||||
TreePatternNodePtr ResultPattern;
|
||||
|
||||
@@ -1041,7 +1027,7 @@ public:
|
||||
unsigned getNumResults() const { return Results.size(); }
|
||||
unsigned getNumOperands() const { return Operands.size(); }
|
||||
unsigned getNumImpResults() const { return ImpResults.size(); }
|
||||
const std::vector<Record*>& getImpResults() const { return ImpResults; }
|
||||
const std::vector<Record *> &getImpResults() const { return ImpResults; }
|
||||
|
||||
Record *getResult(unsigned RN) const {
|
||||
assert(RN < Results.size());
|
||||
@@ -1065,34 +1051,33 @@ public:
|
||||
/// PatternToMatch - Used by CodeGenDAGPatterns to keep tab of patterns
|
||||
/// processed to produce isel.
|
||||
class PatternToMatch {
|
||||
Record *SrcRecord; // Originating Record for the pattern.
|
||||
ListInit *Predicates; // Top level predicate conditions to match.
|
||||
TreePatternNodePtr SrcPattern; // Source pattern to match.
|
||||
TreePatternNodePtr DstPattern; // Resulting pattern.
|
||||
std::vector<Record*> Dstregs; // Physical register defs being matched.
|
||||
std::string HwModeFeatures;
|
||||
int AddedComplexity; // Add to matching pattern complexity.
|
||||
unsigned ID; // Unique ID for the record.
|
||||
Record *SrcRecord; // Originating Record for the pattern.
|
||||
ListInit *Predicates; // Top level predicate conditions to match.
|
||||
TreePatternNodePtr SrcPattern; // Source pattern to match.
|
||||
TreePatternNodePtr DstPattern; // Resulting pattern.
|
||||
std::vector<Record *> Dstregs; // Physical register defs being matched.
|
||||
std::string HwModeFeatures;
|
||||
int AddedComplexity; // Add to matching pattern complexity.
|
||||
unsigned ID; // Unique ID for the record.
|
||||
|
||||
public:
|
||||
PatternToMatch(Record *srcrecord, ListInit *preds, TreePatternNodePtr src,
|
||||
TreePatternNodePtr dst, std::vector<Record *> dstregs,
|
||||
int complexity, unsigned uid,
|
||||
const Twine &hwmodefeatures = "")
|
||||
int complexity, unsigned uid, const Twine &hwmodefeatures = "")
|
||||
: SrcRecord(srcrecord), Predicates(preds), SrcPattern(src),
|
||||
DstPattern(dst), Dstregs(std::move(dstregs)),
|
||||
HwModeFeatures(hwmodefeatures.str()), AddedComplexity(complexity),
|
||||
ID(uid) {}
|
||||
|
||||
Record *getSrcRecord() const { return SrcRecord; }
|
||||
ListInit *getPredicates() const { return Predicates; }
|
||||
Record *getSrcRecord() const { return SrcRecord; }
|
||||
ListInit *getPredicates() const { return Predicates; }
|
||||
TreePatternNode *getSrcPattern() const { return SrcPattern.get(); }
|
||||
TreePatternNodePtr getSrcPatternShared() const { return SrcPattern; }
|
||||
TreePatternNode *getDstPattern() const { return DstPattern.get(); }
|
||||
TreePatternNodePtr getDstPatternShared() const { return DstPattern; }
|
||||
const std::vector<Record*> &getDstRegs() const { return Dstregs; }
|
||||
StringRef getHwModeFeatures() const { return HwModeFeatures; }
|
||||
int getAddedComplexity() const { return AddedComplexity; }
|
||||
const std::vector<Record *> &getDstRegs() const { return Dstregs; }
|
||||
StringRef getHwModeFeatures() const { return HwModeFeatures; }
|
||||
int getAddedComplexity() const { return AddedComplexity; }
|
||||
unsigned getID() const { return ID; }
|
||||
|
||||
std::string getPredicateCheck() const;
|
||||
@@ -1108,14 +1093,14 @@ class CodeGenDAGPatterns {
|
||||
CodeGenTarget Target;
|
||||
CodeGenIntrinsicTable Intrinsics;
|
||||
|
||||
std::map<Record*, SDNodeInfo, LessRecordByID> SDNodes;
|
||||
std::map<Record*, std::pair<Record*, std::string>, LessRecordByID>
|
||||
std::map<Record *, SDNodeInfo, LessRecordByID> SDNodes;
|
||||
std::map<Record *, std::pair<Record *, std::string>, LessRecordByID>
|
||||
SDNodeXForms;
|
||||
std::map<Record*, ComplexPattern, LessRecordByID> ComplexPatterns;
|
||||
std::map<Record *, ComplexPattern, LessRecordByID> ComplexPatterns;
|
||||
std::map<Record *, std::unique_ptr<TreePattern>, LessRecordByID>
|
||||
PatternFragments;
|
||||
std::map<Record*, DAGDefaultOperand, LessRecordByID> DefaultOperands;
|
||||
std::map<Record*, DAGInstruction, LessRecordByID> Instructions;
|
||||
std::map<Record *, DAGDefaultOperand, LessRecordByID> DefaultOperands;
|
||||
std::map<Record *, DAGInstruction, LessRecordByID> Instructions;
|
||||
|
||||
// Specific SDNode definitions:
|
||||
Record *intrinsic_void_sdnode;
|
||||
@@ -1128,7 +1113,7 @@ class CodeGenDAGPatterns {
|
||||
|
||||
TypeSetByHwMode LegalVTS;
|
||||
|
||||
using PatternRewriterFn = std::function<void (TreePattern *)>;
|
||||
using PatternRewriterFn = std::function<void(TreePattern *)>;
|
||||
PatternRewriterFn PatternRewriter;
|
||||
|
||||
unsigned NumScopes = 0;
|
||||
@@ -1150,7 +1135,7 @@ public:
|
||||
}
|
||||
|
||||
// Node transformation lookups.
|
||||
typedef std::pair<Record*, std::string> NodeXForm;
|
||||
typedef std::pair<Record *, std::string> NodeXForm;
|
||||
const NodeXForm &getSDNodeTransform(Record *R) const {
|
||||
auto F = SDNodeXForms.find(R);
|
||||
assert(F != SDNodeXForms.end() && "Invalid transform!");
|
||||
@@ -1165,25 +1150,27 @@ public:
|
||||
|
||||
const CodeGenIntrinsic &getIntrinsic(Record *R) const {
|
||||
for (unsigned i = 0, e = Intrinsics.size(); i != e; ++i)
|
||||
if (Intrinsics[i].TheDef == R) return Intrinsics[i];
|
||||
if (Intrinsics[i].TheDef == R)
|
||||
return Intrinsics[i];
|
||||
llvm_unreachable("Unknown intrinsic!");
|
||||
}
|
||||
|
||||
const CodeGenIntrinsic &getIntrinsicInfo(unsigned IID) const {
|
||||
if (IID-1 < Intrinsics.size())
|
||||
return Intrinsics[IID-1];
|
||||
if (IID - 1 < Intrinsics.size())
|
||||
return Intrinsics[IID - 1];
|
||||
llvm_unreachable("Bad intrinsic ID!");
|
||||
}
|
||||
|
||||
unsigned getIntrinsicID(Record *R) const {
|
||||
for (unsigned i = 0, e = Intrinsics.size(); i != e; ++i)
|
||||
if (Intrinsics[i].TheDef == R) return i;
|
||||
if (Intrinsics[i].TheDef == R)
|
||||
return i;
|
||||
llvm_unreachable("Unknown intrinsic!");
|
||||
}
|
||||
|
||||
const DAGDefaultOperand &getDefaultOperand(Record *R) const {
|
||||
auto F = DefaultOperands.find(R);
|
||||
assert(F != DefaultOperands.end() &&"Isn't an analyzed default operand!");
|
||||
assert(F != DefaultOperands.end() && "Isn't an analyzed default operand!");
|
||||
return F->second;
|
||||
}
|
||||
|
||||
@@ -1213,10 +1200,9 @@ public:
|
||||
iterator_range<ptm_iterator> ptms() const { return PatternsToMatch; }
|
||||
|
||||
/// Parse the Pattern for an instruction, and insert the result in DAGInsts.
|
||||
typedef std::map<Record*, DAGInstruction, LessRecordByID> DAGInstMap;
|
||||
void parseInstructionPattern(
|
||||
CodeGenInstruction &CGI, ListInit *Pattern,
|
||||
DAGInstMap &DAGInsts);
|
||||
typedef std::map<Record *, DAGInstruction, LessRecordByID> DAGInstMap;
|
||||
void parseInstructionPattern(CodeGenInstruction &CGI, ListInit *Pattern,
|
||||
DAGInstMap &DAGInsts);
|
||||
|
||||
const DAGInstruction &getInstruction(Record *R) const {
|
||||
auto F = Instructions.find(R);
|
||||
@@ -1224,9 +1210,7 @@ public:
|
||||
return F->second;
|
||||
}
|
||||
|
||||
Record *get_intrinsic_void_sdnode() const {
|
||||
return intrinsic_void_sdnode;
|
||||
}
|
||||
Record *get_intrinsic_void_sdnode() const { return intrinsic_void_sdnode; }
|
||||
Record *get_intrinsic_w_chain_sdnode() const {
|
||||
return intrinsic_w_chain_sdnode;
|
||||
}
|
||||
@@ -1238,7 +1222,7 @@ public:
|
||||
|
||||
bool operandHasDefault(Record *Op) const {
|
||||
return Op->isSubClassOf("OperandWithDefaultOps") &&
|
||||
!getDefaultOperand(Op).DefaultOps.empty();
|
||||
!getDefaultOperand(Op).DefaultOps.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1254,8 +1238,8 @@ private:
|
||||
void GenerateVariants();
|
||||
void VerifyInstructionFlags();
|
||||
|
||||
void ParseOnePattern(Record *TheDef,
|
||||
TreePattern &Pattern, TreePattern &Result,
|
||||
void ParseOnePattern(Record *TheDef, TreePattern &Pattern,
|
||||
TreePattern &Result,
|
||||
const std::vector<Record *> &InstImpResults);
|
||||
void AddPatternToMatch(TreePattern *Pattern, PatternToMatch &&PTM);
|
||||
void FindPatternInputsAndOutputs(
|
||||
@@ -1266,14 +1250,13 @@ private:
|
||||
std::vector<Record *> &InstImpResults);
|
||||
};
|
||||
|
||||
|
||||
inline bool SDNodeInfo::ApplyTypeConstraints(TreePatternNode *N,
|
||||
TreePattern &TP) const {
|
||||
bool MadeChange = false;
|
||||
for (unsigned i = 0, e = TypeConstraints.size(); i != e; ++i)
|
||||
MadeChange |= TypeConstraints[i].ApplyTypeConstraint(N, *this, TP);
|
||||
return MadeChange;
|
||||
}
|
||||
bool MadeChange = false;
|
||||
for (unsigned i = 0, e = TypeConstraints.size(); i != e; ++i)
|
||||
MadeChange |= TypeConstraints[i].ApplyTypeConstraint(N, *this, TP);
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
|
||||
@@ -37,17 +37,17 @@ HwMode::HwMode(Record *R) {
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD
|
||||
void HwMode::dump() const {
|
||||
dbgs() << Name << ": " << Features << '\n';
|
||||
}
|
||||
void HwMode::dump() const { dbgs() << Name << ": " << Features << '\n'; }
|
||||
|
||||
HwModeSelect::HwModeSelect(Record *R, CodeGenHwModes &CGH) {
|
||||
std::vector<Record*> Modes = R->getValueAsListOfDefs("Modes");
|
||||
std::vector<Record*> Objects = R->getValueAsListOfDefs("Objects");
|
||||
std::vector<Record *> Modes = R->getValueAsListOfDefs("Modes");
|
||||
std::vector<Record *> Objects = R->getValueAsListOfDefs("Objects");
|
||||
if (Modes.size() != Objects.size()) {
|
||||
PrintError(R->getLoc(), "in record " + R->getName() +
|
||||
" derived from HwModeSelect: the lists Modes and Objects should "
|
||||
"have the same size");
|
||||
PrintError(
|
||||
R->getLoc(),
|
||||
"in record " + R->getName() +
|
||||
" derived from HwModeSelect: the lists Modes and Objects should "
|
||||
"have the same size");
|
||||
report_fatal_error("error in target description.");
|
||||
}
|
||||
for (unsigned i = 0, e = Modes.size(); i != e; ++i) {
|
||||
|
||||
@@ -22,46 +22,46 @@
|
||||
// HwModeId -> list of predicates (definition)
|
||||
|
||||
namespace llvm {
|
||||
class Record;
|
||||
class RecordKeeper;
|
||||
class Record;
|
||||
class RecordKeeper;
|
||||
|
||||
struct CodeGenHwModes;
|
||||
struct CodeGenHwModes;
|
||||
|
||||
struct HwMode {
|
||||
HwMode(Record *R);
|
||||
StringRef Name;
|
||||
std::string Features;
|
||||
std::string Predicates;
|
||||
void dump() const;
|
||||
};
|
||||
struct HwMode {
|
||||
HwMode(Record *R);
|
||||
StringRef Name;
|
||||
std::string Features;
|
||||
std::string Predicates;
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
struct HwModeSelect {
|
||||
HwModeSelect(Record *R, CodeGenHwModes &CGH);
|
||||
typedef std::pair<unsigned, Record*> PairType;
|
||||
std::vector<PairType> Items;
|
||||
void dump() const;
|
||||
};
|
||||
struct HwModeSelect {
|
||||
HwModeSelect(Record *R, CodeGenHwModes &CGH);
|
||||
typedef std::pair<unsigned, Record *> PairType;
|
||||
std::vector<PairType> Items;
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
struct CodeGenHwModes {
|
||||
enum : unsigned { DefaultMode = 0 };
|
||||
static StringRef DefaultModeName;
|
||||
struct CodeGenHwModes {
|
||||
enum : unsigned { DefaultMode = 0 };
|
||||
static StringRef DefaultModeName;
|
||||
|
||||
CodeGenHwModes(RecordKeeper &R);
|
||||
unsigned getHwModeId(Record *R) const;
|
||||
const HwMode &getMode(unsigned Id) const {
|
||||
assert(Id != 0 && "Mode id of 0 is reserved for the default mode");
|
||||
return Modes[Id-1];
|
||||
}
|
||||
const HwModeSelect &getHwModeSelect(Record *R) const;
|
||||
unsigned getNumModeIds() const { return Modes.size()+1; }
|
||||
void dump() const;
|
||||
CodeGenHwModes(RecordKeeper &R);
|
||||
unsigned getHwModeId(Record *R) const;
|
||||
const HwMode &getMode(unsigned Id) const {
|
||||
assert(Id != 0 && "Mode id of 0 is reserved for the default mode");
|
||||
return Modes[Id - 1];
|
||||
}
|
||||
const HwModeSelect &getHwModeSelect(Record *R) const;
|
||||
unsigned getNumModeIds() const { return Modes.size() + 1; }
|
||||
void dump() const;
|
||||
|
||||
private:
|
||||
RecordKeeper &Records;
|
||||
DenseMap<Record *, unsigned> ModeIds; // HwMode Record -> HwModeId
|
||||
std::vector<HwMode> Modes;
|
||||
std::map<Record*,HwModeSelect> ModeSelects;
|
||||
};
|
||||
}
|
||||
private:
|
||||
RecordKeeper &Records;
|
||||
DenseMap<Record *, unsigned> ModeIds; // HwMode Record -> HwModeId
|
||||
std::vector<HwMode> Modes;
|
||||
std::map<Record *, HwModeSelect> ModeSelects;
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_UTILS_TABLEGEN_CODEGENHWMODES_H
|
||||
|
||||
@@ -55,15 +55,15 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
|
||||
unsigned e = InDI->getNumArgs() + OutDI->getNumArgs();
|
||||
OperandList.reserve(e);
|
||||
bool VariadicOuts = false;
|
||||
for (unsigned i = 0; i != e; ++i){
|
||||
for (unsigned i = 0; i != e; ++i) {
|
||||
Init *ArgInit;
|
||||
StringRef ArgName;
|
||||
if (i < NumDefs) {
|
||||
ArgInit = OutDI->getArg(i);
|
||||
ArgName = OutDI->getArgNameStr(i);
|
||||
} else {
|
||||
ArgInit = InDI->getArg(i-NumDefs);
|
||||
ArgName = InDI->getArgNameStr(i-NumDefs);
|
||||
ArgInit = InDI->getArg(i - NumDefs);
|
||||
ArgName = InDI->getArgNameStr(i - NumDefs);
|
||||
}
|
||||
|
||||
DagInit *SubArgDag = dyn_cast<DagInit>(ArgInit);
|
||||
@@ -192,7 +192,6 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
|
||||
--NumDefs;
|
||||
}
|
||||
|
||||
|
||||
/// getOperandNamed - Return the index of the operand with the specified
|
||||
/// non-empty name. If the instruction does not have an operand with the
|
||||
/// specified name, abort.
|
||||
@@ -230,7 +229,7 @@ bool CGIOperandList::hasSubOperandAlias(
|
||||
return false;
|
||||
}
|
||||
|
||||
std::pair<unsigned,unsigned>
|
||||
std::pair<unsigned, unsigned>
|
||||
CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
|
||||
if (!Op.starts_with("$"))
|
||||
PrintFatalError(TheDef->getLoc(),
|
||||
@@ -242,7 +241,7 @@ CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
|
||||
// Check to see if this is $foo.bar.
|
||||
StringRef::size_type DotIdx = OpName.find_first_of('.');
|
||||
if (DotIdx != StringRef::npos) {
|
||||
SubOpName = OpName.substr(DotIdx+1);
|
||||
SubOpName = OpName.substr(DotIdx + 1);
|
||||
if (SubOpName.empty())
|
||||
PrintFatalError(TheDef->getLoc(),
|
||||
TheDef->getName() +
|
||||
@@ -266,7 +265,7 @@ CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
|
||||
|
||||
OpIdx = getOperandNamed(OpName);
|
||||
|
||||
if (SubOpName.empty()) { // If no suboperand name was specified:
|
||||
if (SubOpName.empty()) { // If no suboperand name was specified:
|
||||
// If one was needed, throw.
|
||||
if (OperandList[OpIdx].MINumOperands > 1 && !AllowWholeOp &&
|
||||
SubOpName.empty())
|
||||
@@ -299,82 +298,80 @@ CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
|
||||
return std::make_pair(0U, 0U);
|
||||
}
|
||||
|
||||
static void ParseConstraint(StringRef CStr, CGIOperandList &Ops,
|
||||
Record *Rec) {
|
||||
static void ParseConstraint(StringRef CStr, CGIOperandList &Ops, Record *Rec) {
|
||||
// EARLY_CLOBBER: @early $reg
|
||||
StringRef::size_type wpos = CStr.find_first_of(" \t");
|
||||
StringRef::size_type start = CStr.find_first_not_of(" \t");
|
||||
StringRef Tok = CStr.substr(start, wpos - start);
|
||||
if (Tok == "@earlyclobber") {
|
||||
StringRef Name = CStr.substr(wpos+1);
|
||||
StringRef Name = CStr.substr(wpos + 1);
|
||||
wpos = Name.find_first_not_of(" \t");
|
||||
if (wpos == StringRef::npos)
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Illegal format for @earlyclobber constraint in '" +
|
||||
Rec->getName() + "': '" + CStr + "'");
|
||||
PrintFatalError(Rec->getLoc(),
|
||||
"Illegal format for @earlyclobber constraint in '" +
|
||||
Rec->getName() + "': '" + CStr + "'");
|
||||
Name = Name.substr(wpos);
|
||||
std::pair<unsigned,unsigned> Op = Ops.ParseOperandName(Name, false);
|
||||
std::pair<unsigned, unsigned> Op = Ops.ParseOperandName(Name, false);
|
||||
|
||||
// Build the string for the operand
|
||||
if (!Ops[Op.first].Constraints[Op.second].isNone())
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Operand '" + Name + "' of '" + Rec->getName() +
|
||||
"' cannot have multiple constraints!");
|
||||
PrintFatalError(Rec->getLoc(), "Operand '" + Name + "' of '" +
|
||||
Rec->getName() +
|
||||
"' cannot have multiple constraints!");
|
||||
Ops[Op.first].Constraints[Op.second] =
|
||||
CGIOperandList::ConstraintInfo::getEarlyClobber();
|
||||
CGIOperandList::ConstraintInfo::getEarlyClobber();
|
||||
return;
|
||||
}
|
||||
|
||||
// Only other constraint is "TIED_TO" for now.
|
||||
StringRef::size_type pos = CStr.find_first_of('=');
|
||||
if (pos == StringRef::npos)
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Unrecognized constraint '" + CStr +
|
||||
"' in '" + Rec->getName() + "'");
|
||||
PrintFatalError(Rec->getLoc(), "Unrecognized constraint '" + CStr +
|
||||
"' in '" + Rec->getName() + "'");
|
||||
start = CStr.find_first_not_of(" \t");
|
||||
|
||||
// TIED_TO: $src1 = $dst
|
||||
wpos = CStr.find_first_of(" \t", start);
|
||||
if (wpos == StringRef::npos || wpos > pos)
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Illegal format for tied-to constraint in '" +
|
||||
Rec->getName() + "': '" + CStr + "'");
|
||||
PrintFatalError(Rec->getLoc(),
|
||||
"Illegal format for tied-to constraint in '" +
|
||||
Rec->getName() + "': '" + CStr + "'");
|
||||
StringRef LHSOpName = CStr.substr(start, wpos - start);
|
||||
std::pair<unsigned,unsigned> LHSOp = Ops.ParseOperandName(LHSOpName, false);
|
||||
std::pair<unsigned, unsigned> LHSOp = Ops.ParseOperandName(LHSOpName, false);
|
||||
|
||||
wpos = CStr.find_first_not_of(" \t", pos + 1);
|
||||
if (wpos == StringRef::npos)
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Illegal format for tied-to constraint: '" + CStr + "'");
|
||||
PrintFatalError(Rec->getLoc(),
|
||||
"Illegal format for tied-to constraint: '" + CStr + "'");
|
||||
|
||||
StringRef RHSOpName = CStr.substr(wpos);
|
||||
std::pair<unsigned,unsigned> RHSOp = Ops.ParseOperandName(RHSOpName, false);
|
||||
std::pair<unsigned, unsigned> RHSOp = Ops.ParseOperandName(RHSOpName, false);
|
||||
|
||||
// Sort the operands into order, which should put the output one
|
||||
// first. But keep the original order, for use in diagnostics.
|
||||
bool FirstIsDest = (LHSOp < RHSOp);
|
||||
std::pair<unsigned,unsigned> DestOp = (FirstIsDest ? LHSOp : RHSOp);
|
||||
std::pair<unsigned, unsigned> DestOp = (FirstIsDest ? LHSOp : RHSOp);
|
||||
StringRef DestOpName = (FirstIsDest ? LHSOpName : RHSOpName);
|
||||
std::pair<unsigned,unsigned> SrcOp = (FirstIsDest ? RHSOp : LHSOp);
|
||||
std::pair<unsigned, unsigned> SrcOp = (FirstIsDest ? RHSOp : LHSOp);
|
||||
StringRef SrcOpName = (FirstIsDest ? RHSOpName : LHSOpName);
|
||||
|
||||
// Ensure one operand is a def and the other is a use.
|
||||
if (DestOp.first >= Ops.NumDefs)
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Input operands '" + LHSOpName + "' and '" + RHSOpName +
|
||||
"' of '" + Rec->getName() + "' cannot be tied!");
|
||||
PrintFatalError(Rec->getLoc(), "Input operands '" + LHSOpName + "' and '" +
|
||||
RHSOpName + "' of '" + Rec->getName() +
|
||||
"' cannot be tied!");
|
||||
if (SrcOp.first < Ops.NumDefs)
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Output operands '" + LHSOpName + "' and '" + RHSOpName +
|
||||
"' of '" + Rec->getName() + "' cannot be tied!");
|
||||
PrintFatalError(Rec->getLoc(), "Output operands '" + LHSOpName + "' and '" +
|
||||
RHSOpName + "' of '" + Rec->getName() +
|
||||
"' cannot be tied!");
|
||||
|
||||
// The constraint has to go on the operand with higher index, i.e.
|
||||
// the source one. Check there isn't another constraint there
|
||||
// already.
|
||||
if (!Ops[SrcOp.first].Constraints[SrcOp.second].isNone())
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Operand '" + SrcOpName + "' of '" + Rec->getName() +
|
||||
"' cannot have multiple constraints!");
|
||||
PrintFatalError(Rec->getLoc(), "Operand '" + SrcOpName + "' of '" +
|
||||
Rec->getName() +
|
||||
"' cannot have multiple constraints!");
|
||||
|
||||
unsigned DestFlatOpNo = Ops.getFlattenedOperandNumber(DestOp);
|
||||
auto NewConstraint = CGIOperandList::ConstraintInfo::getTied(DestFlatOpNo);
|
||||
@@ -384,16 +381,17 @@ static void ParseConstraint(StringRef CStr, CGIOperandList &Ops,
|
||||
for (const CGIOperandList::OperandInfo &Op : Ops) {
|
||||
for (unsigned i = 0; i < Op.MINumOperands; i++)
|
||||
if (Op.Constraints[i] == NewConstraint)
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Operand '" + DestOpName + "' of '" + Rec->getName() +
|
||||
"' cannot have multiple operands tied to it!");
|
||||
PrintFatalError(Rec->getLoc(),
|
||||
"Operand '" + DestOpName + "' of '" + Rec->getName() +
|
||||
"' cannot have multiple operands tied to it!");
|
||||
}
|
||||
|
||||
Ops[SrcOp.first].Constraints[SrcOp.second] = NewConstraint;
|
||||
}
|
||||
|
||||
static void ParseConstraints(StringRef CStr, CGIOperandList &Ops, Record *Rec) {
|
||||
if (CStr.empty()) return;
|
||||
if (CStr.empty())
|
||||
return;
|
||||
|
||||
StringRef delims(",");
|
||||
StringRef::size_type bidx, eidx;
|
||||
@@ -413,15 +411,15 @@ void CGIOperandList::ProcessDisableEncoding(StringRef DisableEncoding) {
|
||||
while (true) {
|
||||
StringRef OpName;
|
||||
std::tie(OpName, DisableEncoding) = getToken(DisableEncoding, " ,\t");
|
||||
if (OpName.empty()) break;
|
||||
if (OpName.empty())
|
||||
break;
|
||||
|
||||
// Figure out which operand this is.
|
||||
std::pair<unsigned,unsigned> Op = ParseOperandName(OpName, false);
|
||||
std::pair<unsigned, unsigned> Op = ParseOperandName(OpName, false);
|
||||
|
||||
// Mark the operand as not-to-be encoded.
|
||||
OperandList[Op.first].DoNotEncode[Op.second] = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -429,27 +427,27 @@ void CGIOperandList::ProcessDisableEncoding(StringRef DisableEncoding) {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CodeGenInstruction::CodeGenInstruction(Record *R)
|
||||
: TheDef(R), Operands(R), InferredFrom(nullptr) {
|
||||
: TheDef(R), Operands(R), InferredFrom(nullptr) {
|
||||
Namespace = R->getValueAsString("Namespace");
|
||||
AsmString = std::string(R->getValueAsString("AsmString"));
|
||||
|
||||
isPreISelOpcode = R->getValueAsBit("isPreISelOpcode");
|
||||
isReturn = R->getValueAsBit("isReturn");
|
||||
isReturn = R->getValueAsBit("isReturn");
|
||||
isEHScopeReturn = R->getValueAsBit("isEHScopeReturn");
|
||||
isBranch = R->getValueAsBit("isBranch");
|
||||
isBranch = R->getValueAsBit("isBranch");
|
||||
isIndirectBranch = R->getValueAsBit("isIndirectBranch");
|
||||
isCompare = R->getValueAsBit("isCompare");
|
||||
isMoveImm = R->getValueAsBit("isMoveImm");
|
||||
isMoveReg = R->getValueAsBit("isMoveReg");
|
||||
isBitcast = R->getValueAsBit("isBitcast");
|
||||
isSelect = R->getValueAsBit("isSelect");
|
||||
isBarrier = R->getValueAsBit("isBarrier");
|
||||
isCall = R->getValueAsBit("isCall");
|
||||
isAdd = R->getValueAsBit("isAdd");
|
||||
isTrap = R->getValueAsBit("isTrap");
|
||||
isCompare = R->getValueAsBit("isCompare");
|
||||
isMoveImm = R->getValueAsBit("isMoveImm");
|
||||
isMoveReg = R->getValueAsBit("isMoveReg");
|
||||
isBitcast = R->getValueAsBit("isBitcast");
|
||||
isSelect = R->getValueAsBit("isSelect");
|
||||
isBarrier = R->getValueAsBit("isBarrier");
|
||||
isCall = R->getValueAsBit("isCall");
|
||||
isAdd = R->getValueAsBit("isAdd");
|
||||
isTrap = R->getValueAsBit("isTrap");
|
||||
canFoldAsLoad = R->getValueAsBit("canFoldAsLoad");
|
||||
isPredicable = !R->getValueAsBit("isUnpredicable") && (
|
||||
Operands.isPredicable || R->getValueAsBit("isPredicable"));
|
||||
isPredicable = !R->getValueAsBit("isUnpredicable") &&
|
||||
(Operands.isPredicable || R->getValueAsBit("isPredicable"));
|
||||
isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress");
|
||||
isCommutable = R->getValueAsBit("isCommutable");
|
||||
isTerminator = R->getValueAsBit("isTerminator");
|
||||
@@ -457,7 +455,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R)
|
||||
hasDelaySlot = R->getValueAsBit("hasDelaySlot");
|
||||
usesCustomInserter = R->getValueAsBit("usesCustomInserter");
|
||||
hasPostISelHook = R->getValueAsBit("hasPostISelHook");
|
||||
hasCtrlDep = R->getValueAsBit("hasCtrlDep");
|
||||
hasCtrlDep = R->getValueAsBit("hasCtrlDep");
|
||||
isNotDuplicable = R->getValueAsBit("isNotDuplicable");
|
||||
isRegSequence = R->getValueAsBit("isRegSequence");
|
||||
isExtractSubreg = R->getValueAsBit("isExtractSubreg");
|
||||
@@ -469,9 +467,9 @@ CodeGenInstruction::CodeGenInstruction(Record *R)
|
||||
isAuthenticated = R->getValueAsBit("isAuthenticated");
|
||||
|
||||
bool Unset;
|
||||
mayLoad = R->getValueAsBitOrUnset("mayLoad", Unset);
|
||||
mayLoad = R->getValueAsBitOrUnset("mayLoad", Unset);
|
||||
mayLoad_Unset = Unset;
|
||||
mayStore = R->getValueAsBitOrUnset("mayStore", Unset);
|
||||
mayStore = R->getValueAsBitOrUnset("mayStore", Unset);
|
||||
mayStore_Unset = Unset;
|
||||
mayRaiseFPException = R->getValueAsBit("mayRaiseFPException");
|
||||
hasSideEffects = R->getValueAsBitOrUnset("hasSideEffects", Unset);
|
||||
@@ -494,8 +492,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R)
|
||||
ParseConstraints(R->getValueAsString("Constraints"), Operands, R);
|
||||
|
||||
// Parse the DisableEncoding field.
|
||||
Operands.ProcessDisableEncoding(
|
||||
R->getValueAsString("DisableEncoding"));
|
||||
Operands.ProcessDisableEncoding(R->getValueAsString("DisableEncoding"));
|
||||
|
||||
// First check for a ComplexDeprecationPredicate.
|
||||
if (R->getValue("ComplexDeprecationPredicate")) {
|
||||
@@ -516,25 +513,25 @@ CodeGenInstruction::CodeGenInstruction(Record *R)
|
||||
/// HasOneImplicitDefWithKnownVT - If the instruction has at least one
|
||||
/// implicit def and it has a known VT, return the VT, otherwise return
|
||||
/// MVT::Other.
|
||||
MVT::SimpleValueType CodeGenInstruction::
|
||||
HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const {
|
||||
if (ImplicitDefs.empty()) return MVT::Other;
|
||||
MVT::SimpleValueType CodeGenInstruction::HasOneImplicitDefWithKnownVT(
|
||||
const CodeGenTarget &TargetInfo) const {
|
||||
if (ImplicitDefs.empty())
|
||||
return MVT::Other;
|
||||
|
||||
// Check to see if the first implicit def has a resolvable type.
|
||||
Record *FirstImplicitDef = ImplicitDefs[0];
|
||||
assert(FirstImplicitDef->isSubClassOf("Register"));
|
||||
const std::vector<ValueTypeByHwMode> &RegVTs =
|
||||
TargetInfo.getRegisterVTs(FirstImplicitDef);
|
||||
TargetInfo.getRegisterVTs(FirstImplicitDef);
|
||||
if (RegVTs.size() == 1 && RegVTs[0].isSimple())
|
||||
return RegVTs[0].getSimple().SimpleTy;
|
||||
return MVT::Other;
|
||||
}
|
||||
|
||||
|
||||
/// FlattenAsmStringVariants - Flatten the specified AsmString to only
|
||||
/// include text from the specified variant, returning the new string.
|
||||
std::string CodeGenInstruction::
|
||||
FlattenAsmStringVariants(StringRef Cur, unsigned Variant) {
|
||||
std::string CodeGenInstruction::FlattenAsmStringVariants(StringRef Cur,
|
||||
unsigned Variant) {
|
||||
std::string Res;
|
||||
|
||||
for (;;) {
|
||||
@@ -542,8 +539,8 @@ FlattenAsmStringVariants(StringRef Cur, unsigned Variant) {
|
||||
size_t VariantsStart = 0;
|
||||
for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart)
|
||||
if (Cur[VariantsStart] == '{' &&
|
||||
(VariantsStart == 0 || (Cur[VariantsStart-1] != '$' &&
|
||||
Cur[VariantsStart-1] != '\\')))
|
||||
(VariantsStart == 0 ||
|
||||
(Cur[VariantsStart - 1] != '$' && Cur[VariantsStart - 1] != '\\')))
|
||||
break;
|
||||
|
||||
// Add the prefix to the result.
|
||||
@@ -557,7 +554,7 @@ FlattenAsmStringVariants(StringRef Cur, unsigned Variant) {
|
||||
size_t VariantsEnd = VariantsStart;
|
||||
unsigned NestedBraces = 1;
|
||||
for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) {
|
||||
if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd-1] != '\\') {
|
||||
if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd - 1] != '\\') {
|
||||
if (--NestedBraces == 0)
|
||||
break;
|
||||
} else if (Cur[VariantsEnd] == '{')
|
||||
|
||||
@@ -23,324 +23,320 @@
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class Record;
|
||||
class DagInit;
|
||||
class CodeGenTarget;
|
||||
class Record;
|
||||
class DagInit;
|
||||
class CodeGenTarget;
|
||||
|
||||
class CGIOperandList {
|
||||
public:
|
||||
class ConstraintInfo {
|
||||
enum { None, EarlyClobber, Tied } Kind = None;
|
||||
unsigned OtherTiedOperand = 0;
|
||||
|
||||
class CGIOperandList {
|
||||
public:
|
||||
class ConstraintInfo {
|
||||
enum { None, EarlyClobber, Tied } Kind = None;
|
||||
unsigned OtherTiedOperand = 0;
|
||||
ConstraintInfo() = default;
|
||||
|
||||
public:
|
||||
ConstraintInfo() = default;
|
||||
static ConstraintInfo getEarlyClobber() {
|
||||
ConstraintInfo I;
|
||||
I.Kind = EarlyClobber;
|
||||
I.OtherTiedOperand = 0;
|
||||
return I;
|
||||
}
|
||||
|
||||
static ConstraintInfo getEarlyClobber() {
|
||||
ConstraintInfo I;
|
||||
I.Kind = EarlyClobber;
|
||||
I.OtherTiedOperand = 0;
|
||||
return I;
|
||||
}
|
||||
static ConstraintInfo getTied(unsigned Op) {
|
||||
ConstraintInfo I;
|
||||
I.Kind = Tied;
|
||||
I.OtherTiedOperand = Op;
|
||||
return I;
|
||||
}
|
||||
|
||||
static ConstraintInfo getTied(unsigned Op) {
|
||||
ConstraintInfo I;
|
||||
I.Kind = Tied;
|
||||
I.OtherTiedOperand = Op;
|
||||
return I;
|
||||
}
|
||||
bool isNone() const { return Kind == None; }
|
||||
bool isEarlyClobber() const { return Kind == EarlyClobber; }
|
||||
bool isTied() const { return Kind == Tied; }
|
||||
|
||||
bool isNone() const { return Kind == None; }
|
||||
bool isEarlyClobber() const { return Kind == EarlyClobber; }
|
||||
bool isTied() const { return Kind == Tied; }
|
||||
unsigned getTiedOperand() const {
|
||||
assert(isTied());
|
||||
return OtherTiedOperand;
|
||||
}
|
||||
|
||||
unsigned getTiedOperand() const {
|
||||
assert(isTied());
|
||||
return OtherTiedOperand;
|
||||
}
|
||||
bool operator==(const ConstraintInfo &RHS) const {
|
||||
if (Kind != RHS.Kind)
|
||||
return false;
|
||||
if (Kind == Tied && OtherTiedOperand != RHS.OtherTiedOperand)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const ConstraintInfo &RHS) const { return !(*this == RHS); }
|
||||
};
|
||||
|
||||
bool operator==(const ConstraintInfo &RHS) const {
|
||||
if (Kind != RHS.Kind)
|
||||
return false;
|
||||
if (Kind == Tied && OtherTiedOperand != RHS.OtherTiedOperand)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const ConstraintInfo &RHS) const {
|
||||
return !(*this == RHS);
|
||||
}
|
||||
};
|
||||
|
||||
/// OperandInfo - The information we keep track of for each operand in the
|
||||
/// operand list for a tablegen instruction.
|
||||
struct OperandInfo {
|
||||
/// Rec - The definition this operand is declared as.
|
||||
///
|
||||
Record *Rec;
|
||||
|
||||
/// Name - If this operand was assigned a symbolic name, this is it,
|
||||
/// otherwise, it's empty.
|
||||
std::string Name;
|
||||
|
||||
/// The names of sub-operands, if given, otherwise empty.
|
||||
std::vector<std::string> SubOpNames;
|
||||
|
||||
/// PrinterMethodName - The method used to print operands of this type in
|
||||
/// the asmprinter.
|
||||
std::string PrinterMethodName;
|
||||
|
||||
/// The method used to get the machine operand value for binary
|
||||
/// encoding, per sub-operand. If empty, uses "getMachineOpValue".
|
||||
std::vector<std::string> EncoderMethodNames;
|
||||
|
||||
/// OperandType - A value from MCOI::OperandType representing the type of
|
||||
/// the operand.
|
||||
std::string OperandType;
|
||||
|
||||
/// MIOperandNo - Currently (this is meant to be phased out), some logical
|
||||
/// operands correspond to multiple MachineInstr operands. In the X86
|
||||
/// target for example, one address operand is represented as 4
|
||||
/// MachineOperands. Because of this, the operand number in the
|
||||
/// OperandList may not match the MachineInstr operand num. Until it
|
||||
/// does, this contains the MI operand index of this operand.
|
||||
unsigned MIOperandNo;
|
||||
unsigned MINumOperands; // The number of operands.
|
||||
|
||||
/// DoNotEncode - Bools are set to true in this vector for each operand in
|
||||
/// the DisableEncoding list. These should not be emitted by the code
|
||||
/// emitter.
|
||||
BitVector DoNotEncode;
|
||||
|
||||
/// MIOperandInfo - Default MI operand type. Note an operand may be made
|
||||
/// up of multiple MI operands.
|
||||
DagInit *MIOperandInfo;
|
||||
|
||||
/// Constraint info for this operand. This operand can have pieces, so we
|
||||
/// track constraint info for each.
|
||||
std::vector<ConstraintInfo> Constraints;
|
||||
|
||||
OperandInfo(Record *R, const std::string &N, const std::string &PMN,
|
||||
const std::string &OT, unsigned MION, unsigned MINO,
|
||||
DagInit *MIOI)
|
||||
: Rec(R), Name(N), SubOpNames(MINO), PrinterMethodName(PMN),
|
||||
EncoderMethodNames(MINO), OperandType(OT), MIOperandNo(MION),
|
||||
MINumOperands(MINO), DoNotEncode(MINO), MIOperandInfo(MIOI),
|
||||
Constraints(MINO) {}
|
||||
|
||||
/// getTiedOperand - If this operand is tied to another one, return the
|
||||
/// other operand number. Otherwise, return -1.
|
||||
int getTiedRegister() const {
|
||||
for (unsigned j = 0, e = Constraints.size(); j != e; ++j) {
|
||||
const CGIOperandList::ConstraintInfo &CI = Constraints[j];
|
||||
if (CI.isTied()) return CI.getTiedOperand();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
CGIOperandList(Record *D);
|
||||
|
||||
Record *TheDef; // The actual record containing this OperandList.
|
||||
|
||||
/// NumDefs - Number of def operands declared, this is the number of
|
||||
/// elements in the instruction's (outs) list.
|
||||
/// OperandInfo - The information we keep track of for each operand in the
|
||||
/// operand list for a tablegen instruction.
|
||||
struct OperandInfo {
|
||||
/// Rec - The definition this operand is declared as.
|
||||
///
|
||||
unsigned NumDefs;
|
||||
Record *Rec;
|
||||
|
||||
/// OperandList - The list of declared operands, along with their declared
|
||||
/// type (which is a record).
|
||||
std::vector<OperandInfo> OperandList;
|
||||
/// Name - If this operand was assigned a symbolic name, this is it,
|
||||
/// otherwise, it's empty.
|
||||
std::string Name;
|
||||
|
||||
/// SubOpAliases - List of alias names for suboperands.
|
||||
StringMap<std::pair<unsigned, unsigned>> SubOpAliases;
|
||||
/// The names of sub-operands, if given, otherwise empty.
|
||||
std::vector<std::string> SubOpNames;
|
||||
|
||||
// Information gleaned from the operand list.
|
||||
bool isPredicable;
|
||||
bool hasOptionalDef;
|
||||
bool isVariadic;
|
||||
/// PrinterMethodName - The method used to print operands of this type in
|
||||
/// the asmprinter.
|
||||
std::string PrinterMethodName;
|
||||
|
||||
// Provide transparent accessors to the operand list.
|
||||
bool empty() const { return OperandList.empty(); }
|
||||
unsigned size() const { return OperandList.size(); }
|
||||
const OperandInfo &operator[](unsigned i) const { return OperandList[i]; }
|
||||
OperandInfo &operator[](unsigned i) { return OperandList[i]; }
|
||||
OperandInfo &back() { return OperandList.back(); }
|
||||
const OperandInfo &back() const { return OperandList.back(); }
|
||||
/// The method used to get the machine operand value for binary
|
||||
/// encoding, per sub-operand. If empty, uses "getMachineOpValue".
|
||||
std::vector<std::string> EncoderMethodNames;
|
||||
|
||||
typedef std::vector<OperandInfo>::iterator iterator;
|
||||
typedef std::vector<OperandInfo>::const_iterator const_iterator;
|
||||
iterator begin() { return OperandList.begin(); }
|
||||
const_iterator begin() const { return OperandList.begin(); }
|
||||
iterator end() { return OperandList.end(); }
|
||||
const_iterator end() const { return OperandList.end(); }
|
||||
/// OperandType - A value from MCOI::OperandType representing the type of
|
||||
/// the operand.
|
||||
std::string OperandType;
|
||||
|
||||
/// getOperandNamed - Return the index of the operand with the specified
|
||||
/// non-empty name. If the instruction does not have an operand with the
|
||||
/// specified name, abort.
|
||||
unsigned getOperandNamed(StringRef Name) const;
|
||||
/// MIOperandNo - Currently (this is meant to be phased out), some logical
|
||||
/// operands correspond to multiple MachineInstr operands. In the X86
|
||||
/// target for example, one address operand is represented as 4
|
||||
/// MachineOperands. Because of this, the operand number in the
|
||||
/// OperandList may not match the MachineInstr operand num. Until it
|
||||
/// does, this contains the MI operand index of this operand.
|
||||
unsigned MIOperandNo;
|
||||
unsigned MINumOperands; // The number of operands.
|
||||
|
||||
/// hasOperandNamed - Query whether the instruction has an operand of the
|
||||
/// given name. If so, return true and set OpIdx to the index of the
|
||||
/// operand. Otherwise, return false.
|
||||
bool hasOperandNamed(StringRef Name, unsigned &OpIdx) const;
|
||||
/// DoNotEncode - Bools are set to true in this vector for each operand in
|
||||
/// the DisableEncoding list. These should not be emitted by the code
|
||||
/// emitter.
|
||||
BitVector DoNotEncode;
|
||||
|
||||
bool hasSubOperandAlias(StringRef Name,
|
||||
std::pair<unsigned, unsigned> &SubOp) const;
|
||||
/// MIOperandInfo - Default MI operand type. Note an operand may be made
|
||||
/// up of multiple MI operands.
|
||||
DagInit *MIOperandInfo;
|
||||
|
||||
/// ParseOperandName - Parse an operand name like "$foo" or "$foo.bar",
|
||||
/// where $foo is a whole operand and $foo.bar refers to a suboperand.
|
||||
/// This aborts if the name is invalid. If AllowWholeOp is true, references
|
||||
/// to operands with suboperands are allowed, otherwise not.
|
||||
std::pair<unsigned,unsigned> ParseOperandName(StringRef Op,
|
||||
bool AllowWholeOp = true);
|
||||
/// Constraint info for this operand. This operand can have pieces, so we
|
||||
/// track constraint info for each.
|
||||
std::vector<ConstraintInfo> Constraints;
|
||||
|
||||
/// getFlattenedOperandNumber - Flatten a operand/suboperand pair into a
|
||||
/// flat machineinstr operand #.
|
||||
unsigned getFlattenedOperandNumber(std::pair<unsigned,unsigned> Op) const {
|
||||
return OperandList[Op.first].MIOperandNo + Op.second;
|
||||
}
|
||||
OperandInfo(Record *R, const std::string &N, const std::string &PMN,
|
||||
const std::string &OT, unsigned MION, unsigned MINO,
|
||||
DagInit *MIOI)
|
||||
: Rec(R), Name(N), SubOpNames(MINO), PrinterMethodName(PMN),
|
||||
EncoderMethodNames(MINO), OperandType(OT), MIOperandNo(MION),
|
||||
MINumOperands(MINO), DoNotEncode(MINO), MIOperandInfo(MIOI),
|
||||
Constraints(MINO) {}
|
||||
|
||||
/// getSubOperandNumber - Unflatten a operand number into an
|
||||
/// operand/suboperand pair.
|
||||
std::pair<unsigned,unsigned> getSubOperandNumber(unsigned Op) const {
|
||||
for (unsigned i = 0; ; ++i) {
|
||||
assert(i < OperandList.size() && "Invalid flat operand #");
|
||||
if (OperandList[i].MIOperandNo+OperandList[i].MINumOperands > Op)
|
||||
return std::make_pair(i, Op-OperandList[i].MIOperandNo);
|
||||
/// getTiedOperand - If this operand is tied to another one, return the
|
||||
/// other operand number. Otherwise, return -1.
|
||||
int getTiedRegister() const {
|
||||
for (unsigned j = 0, e = Constraints.size(); j != e; ++j) {
|
||||
const CGIOperandList::ConstraintInfo &CI = Constraints[j];
|
||||
if (CI.isTied())
|
||||
return CI.getTiedOperand();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/// isFlatOperandNotEmitted - Return true if the specified flat operand #
|
||||
/// should not be emitted with the code emitter.
|
||||
bool isFlatOperandNotEmitted(unsigned FlatOpNo) const {
|
||||
std::pair<unsigned,unsigned> Op = getSubOperandNumber(FlatOpNo);
|
||||
if (OperandList[Op.first].DoNotEncode.size() > Op.second)
|
||||
return OperandList[Op.first].DoNotEncode[Op.second];
|
||||
return false;
|
||||
}
|
||||
|
||||
void ProcessDisableEncoding(StringRef Value);
|
||||
};
|
||||
|
||||
CGIOperandList(Record *D);
|
||||
|
||||
class CodeGenInstruction {
|
||||
public:
|
||||
Record *TheDef; // The actual record defining this instruction.
|
||||
StringRef Namespace; // The namespace the instruction is in.
|
||||
Record *TheDef; // The actual record containing this OperandList.
|
||||
|
||||
/// AsmString - The format string used to emit a .s file for the
|
||||
/// instruction.
|
||||
std::string AsmString;
|
||||
/// NumDefs - Number of def operands declared, this is the number of
|
||||
/// elements in the instruction's (outs) list.
|
||||
///
|
||||
unsigned NumDefs;
|
||||
|
||||
/// Operands - This is information about the (ins) and (outs) list specified
|
||||
/// to the instruction.
|
||||
CGIOperandList Operands;
|
||||
/// OperandList - The list of declared operands, along with their declared
|
||||
/// type (which is a record).
|
||||
std::vector<OperandInfo> OperandList;
|
||||
|
||||
/// ImplicitDefs/ImplicitUses - These are lists of registers that are
|
||||
/// implicitly defined and used by the instruction.
|
||||
std::vector<Record*> ImplicitDefs, ImplicitUses;
|
||||
/// SubOpAliases - List of alias names for suboperands.
|
||||
StringMap<std::pair<unsigned, unsigned>> SubOpAliases;
|
||||
|
||||
// Various boolean values we track for the instruction.
|
||||
bool isPreISelOpcode : 1;
|
||||
bool isReturn : 1;
|
||||
bool isEHScopeReturn : 1;
|
||||
bool isBranch : 1;
|
||||
bool isIndirectBranch : 1;
|
||||
bool isCompare : 1;
|
||||
bool isMoveImm : 1;
|
||||
bool isMoveReg : 1;
|
||||
bool isBitcast : 1;
|
||||
bool isSelect : 1;
|
||||
bool isBarrier : 1;
|
||||
bool isCall : 1;
|
||||
bool isAdd : 1;
|
||||
bool isTrap : 1;
|
||||
bool canFoldAsLoad : 1;
|
||||
bool mayLoad : 1;
|
||||
bool mayLoad_Unset : 1;
|
||||
bool mayStore : 1;
|
||||
bool mayStore_Unset : 1;
|
||||
bool mayRaiseFPException : 1;
|
||||
bool isPredicable : 1;
|
||||
bool isConvertibleToThreeAddress : 1;
|
||||
bool isCommutable : 1;
|
||||
bool isTerminator : 1;
|
||||
bool isReMaterializable : 1;
|
||||
bool hasDelaySlot : 1;
|
||||
bool usesCustomInserter : 1;
|
||||
bool hasPostISelHook : 1;
|
||||
bool hasCtrlDep : 1;
|
||||
bool isNotDuplicable : 1;
|
||||
bool hasSideEffects : 1;
|
||||
bool hasSideEffects_Unset : 1;
|
||||
bool isAsCheapAsAMove : 1;
|
||||
bool hasExtraSrcRegAllocReq : 1;
|
||||
bool hasExtraDefRegAllocReq : 1;
|
||||
bool isCodeGenOnly : 1;
|
||||
bool isPseudo : 1;
|
||||
bool isMeta : 1;
|
||||
bool isRegSequence : 1;
|
||||
bool isExtractSubreg : 1;
|
||||
bool isInsertSubreg : 1;
|
||||
bool isConvergent : 1;
|
||||
bool hasNoSchedulingInfo : 1;
|
||||
bool FastISelShouldIgnore : 1;
|
||||
bool hasChain : 1;
|
||||
bool hasChain_Inferred : 1;
|
||||
bool variadicOpsAreDefs : 1;
|
||||
bool isAuthenticated : 1;
|
||||
// Information gleaned from the operand list.
|
||||
bool isPredicable;
|
||||
bool hasOptionalDef;
|
||||
bool isVariadic;
|
||||
|
||||
std::string DeprecatedReason;
|
||||
bool HasComplexDeprecationPredicate;
|
||||
// Provide transparent accessors to the operand list.
|
||||
bool empty() const { return OperandList.empty(); }
|
||||
unsigned size() const { return OperandList.size(); }
|
||||
const OperandInfo &operator[](unsigned i) const { return OperandList[i]; }
|
||||
OperandInfo &operator[](unsigned i) { return OperandList[i]; }
|
||||
OperandInfo &back() { return OperandList.back(); }
|
||||
const OperandInfo &back() const { return OperandList.back(); }
|
||||
|
||||
/// Are there any undefined flags?
|
||||
bool hasUndefFlags() const {
|
||||
return mayLoad_Unset || mayStore_Unset || hasSideEffects_Unset;
|
||||
typedef std::vector<OperandInfo>::iterator iterator;
|
||||
typedef std::vector<OperandInfo>::const_iterator const_iterator;
|
||||
iterator begin() { return OperandList.begin(); }
|
||||
const_iterator begin() const { return OperandList.begin(); }
|
||||
iterator end() { return OperandList.end(); }
|
||||
const_iterator end() const { return OperandList.end(); }
|
||||
|
||||
/// getOperandNamed - Return the index of the operand with the specified
|
||||
/// non-empty name. If the instruction does not have an operand with the
|
||||
/// specified name, abort.
|
||||
unsigned getOperandNamed(StringRef Name) const;
|
||||
|
||||
/// hasOperandNamed - Query whether the instruction has an operand of the
|
||||
/// given name. If so, return true and set OpIdx to the index of the
|
||||
/// operand. Otherwise, return false.
|
||||
bool hasOperandNamed(StringRef Name, unsigned &OpIdx) const;
|
||||
|
||||
bool hasSubOperandAlias(StringRef Name,
|
||||
std::pair<unsigned, unsigned> &SubOp) const;
|
||||
|
||||
/// ParseOperandName - Parse an operand name like "$foo" or "$foo.bar",
|
||||
/// where $foo is a whole operand and $foo.bar refers to a suboperand.
|
||||
/// This aborts if the name is invalid. If AllowWholeOp is true, references
|
||||
/// to operands with suboperands are allowed, otherwise not.
|
||||
std::pair<unsigned, unsigned> ParseOperandName(StringRef Op,
|
||||
bool AllowWholeOp = true);
|
||||
|
||||
/// getFlattenedOperandNumber - Flatten a operand/suboperand pair into a
|
||||
/// flat machineinstr operand #.
|
||||
unsigned getFlattenedOperandNumber(std::pair<unsigned, unsigned> Op) const {
|
||||
return OperandList[Op.first].MIOperandNo + Op.second;
|
||||
}
|
||||
|
||||
/// getSubOperandNumber - Unflatten a operand number into an
|
||||
/// operand/suboperand pair.
|
||||
std::pair<unsigned, unsigned> getSubOperandNumber(unsigned Op) const {
|
||||
for (unsigned i = 0;; ++i) {
|
||||
assert(i < OperandList.size() && "Invalid flat operand #");
|
||||
if (OperandList[i].MIOperandNo + OperandList[i].MINumOperands > Op)
|
||||
return std::make_pair(i, Op - OperandList[i].MIOperandNo);
|
||||
}
|
||||
}
|
||||
|
||||
// The record used to infer instruction flags, or NULL if no flag values
|
||||
// have been inferred.
|
||||
Record *InferredFrom;
|
||||
/// isFlatOperandNotEmitted - Return true if the specified flat operand #
|
||||
/// should not be emitted with the code emitter.
|
||||
bool isFlatOperandNotEmitted(unsigned FlatOpNo) const {
|
||||
std::pair<unsigned, unsigned> Op = getSubOperandNumber(FlatOpNo);
|
||||
if (OperandList[Op.first].DoNotEncode.size() > Op.second)
|
||||
return OperandList[Op.first].DoNotEncode[Op.second];
|
||||
return false;
|
||||
}
|
||||
|
||||
// The enum value assigned by CodeGenTarget::computeInstrsByEnum.
|
||||
mutable unsigned EnumVal;
|
||||
void ProcessDisableEncoding(StringRef Value);
|
||||
};
|
||||
|
||||
CodeGenInstruction(Record *R);
|
||||
class CodeGenInstruction {
|
||||
public:
|
||||
Record *TheDef; // The actual record defining this instruction.
|
||||
StringRef Namespace; // The namespace the instruction is in.
|
||||
|
||||
/// HasOneImplicitDefWithKnownVT - If the instruction has at least one
|
||||
/// implicit def and it has a known VT, return the VT, otherwise return
|
||||
/// MVT::Other.
|
||||
MVT::SimpleValueType
|
||||
HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const;
|
||||
/// AsmString - The format string used to emit a .s file for the
|
||||
/// instruction.
|
||||
std::string AsmString;
|
||||
|
||||
/// Operands - This is information about the (ins) and (outs) list specified
|
||||
/// to the instruction.
|
||||
CGIOperandList Operands;
|
||||
|
||||
/// FlattenAsmStringVariants - Flatten the specified AsmString to only
|
||||
/// include text from the specified variant, returning the new string.
|
||||
static std::string FlattenAsmStringVariants(StringRef AsmString,
|
||||
unsigned Variant);
|
||||
/// ImplicitDefs/ImplicitUses - These are lists of registers that are
|
||||
/// implicitly defined and used by the instruction.
|
||||
std::vector<Record *> ImplicitDefs, ImplicitUses;
|
||||
|
||||
// Is the specified operand in a generic instruction implicitly a pointer.
|
||||
// This can be used on intructions that use typeN or ptypeN to identify
|
||||
// operands that should be considered as pointers even though SelectionDAG
|
||||
// didn't make a distinction between integer and pointers.
|
||||
bool isInOperandAPointer(unsigned i) const {
|
||||
return isOperandImpl("InOperandList", i, "IsPointer");
|
||||
}
|
||||
// Various boolean values we track for the instruction.
|
||||
bool isPreISelOpcode : 1;
|
||||
bool isReturn : 1;
|
||||
bool isEHScopeReturn : 1;
|
||||
bool isBranch : 1;
|
||||
bool isIndirectBranch : 1;
|
||||
bool isCompare : 1;
|
||||
bool isMoveImm : 1;
|
||||
bool isMoveReg : 1;
|
||||
bool isBitcast : 1;
|
||||
bool isSelect : 1;
|
||||
bool isBarrier : 1;
|
||||
bool isCall : 1;
|
||||
bool isAdd : 1;
|
||||
bool isTrap : 1;
|
||||
bool canFoldAsLoad : 1;
|
||||
bool mayLoad : 1;
|
||||
bool mayLoad_Unset : 1;
|
||||
bool mayStore : 1;
|
||||
bool mayStore_Unset : 1;
|
||||
bool mayRaiseFPException : 1;
|
||||
bool isPredicable : 1;
|
||||
bool isConvertibleToThreeAddress : 1;
|
||||
bool isCommutable : 1;
|
||||
bool isTerminator : 1;
|
||||
bool isReMaterializable : 1;
|
||||
bool hasDelaySlot : 1;
|
||||
bool usesCustomInserter : 1;
|
||||
bool hasPostISelHook : 1;
|
||||
bool hasCtrlDep : 1;
|
||||
bool isNotDuplicable : 1;
|
||||
bool hasSideEffects : 1;
|
||||
bool hasSideEffects_Unset : 1;
|
||||
bool isAsCheapAsAMove : 1;
|
||||
bool hasExtraSrcRegAllocReq : 1;
|
||||
bool hasExtraDefRegAllocReq : 1;
|
||||
bool isCodeGenOnly : 1;
|
||||
bool isPseudo : 1;
|
||||
bool isMeta : 1;
|
||||
bool isRegSequence : 1;
|
||||
bool isExtractSubreg : 1;
|
||||
bool isInsertSubreg : 1;
|
||||
bool isConvergent : 1;
|
||||
bool hasNoSchedulingInfo : 1;
|
||||
bool FastISelShouldIgnore : 1;
|
||||
bool hasChain : 1;
|
||||
bool hasChain_Inferred : 1;
|
||||
bool variadicOpsAreDefs : 1;
|
||||
bool isAuthenticated : 1;
|
||||
|
||||
bool isOutOperandAPointer(unsigned i) const {
|
||||
return isOperandImpl("OutOperandList", i, "IsPointer");
|
||||
}
|
||||
std::string DeprecatedReason;
|
||||
bool HasComplexDeprecationPredicate;
|
||||
|
||||
/// Check if the operand is required to be an immediate.
|
||||
bool isInOperandImmArg(unsigned i) const {
|
||||
return isOperandImpl("InOperandList", i, "IsImmediate");
|
||||
}
|
||||
/// Are there any undefined flags?
|
||||
bool hasUndefFlags() const {
|
||||
return mayLoad_Unset || mayStore_Unset || hasSideEffects_Unset;
|
||||
}
|
||||
|
||||
private:
|
||||
bool isOperandImpl(StringRef OpListName, unsigned i,
|
||||
StringRef PropertyName) const;
|
||||
};
|
||||
// The record used to infer instruction flags, or NULL if no flag values
|
||||
// have been inferred.
|
||||
Record *InferredFrom;
|
||||
|
||||
// The enum value assigned by CodeGenTarget::computeInstrsByEnum.
|
||||
mutable unsigned EnumVal;
|
||||
|
||||
CodeGenInstruction(Record *R);
|
||||
|
||||
/// HasOneImplicitDefWithKnownVT - If the instruction has at least one
|
||||
/// implicit def and it has a known VT, return the VT, otherwise return
|
||||
/// MVT::Other.
|
||||
MVT::SimpleValueType
|
||||
HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const;
|
||||
|
||||
/// FlattenAsmStringVariants - Flatten the specified AsmString to only
|
||||
/// include text from the specified variant, returning the new string.
|
||||
static std::string FlattenAsmStringVariants(StringRef AsmString,
|
||||
unsigned Variant);
|
||||
|
||||
// Is the specified operand in a generic instruction implicitly a pointer.
|
||||
// This can be used on intructions that use typeN or ptypeN to identify
|
||||
// operands that should be considered as pointers even though SelectionDAG
|
||||
// didn't make a distinction between integer and pointers.
|
||||
bool isInOperandAPointer(unsigned i) const {
|
||||
return isOperandImpl("InOperandList", i, "IsPointer");
|
||||
}
|
||||
|
||||
bool isOutOperandAPointer(unsigned i) const {
|
||||
return isOperandImpl("OutOperandList", i, "IsPointer");
|
||||
}
|
||||
|
||||
/// Check if the operand is required to be an immediate.
|
||||
bool isInOperandImmArg(unsigned i) const {
|
||||
return isOperandImpl("InOperandList", i, "IsImmediate");
|
||||
}
|
||||
|
||||
private:
|
||||
bool isOperandImpl(StringRef OpListName, unsigned i,
|
||||
StringRef PropertyName) const;
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,12 +25,12 @@ class Record;
|
||||
class RecordKeeper;
|
||||
|
||||
struct CodeGenIntrinsic {
|
||||
Record *TheDef; // The actual record defining this intrinsic.
|
||||
std::string Name; // The name of the LLVM function "llvm.bswap.i32"
|
||||
std::string EnumName; // The name of the enum "bswap_i32"
|
||||
Record *TheDef; // The actual record defining this intrinsic.
|
||||
std::string Name; // The name of the LLVM function "llvm.bswap.i32"
|
||||
std::string EnumName; // The name of the enum "bswap_i32"
|
||||
std::string ClangBuiltinName; // Name of the corresponding GCC builtin, or "".
|
||||
std::string MSBuiltinName; // Name of the corresponding MS builtin, or "".
|
||||
std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics.
|
||||
std::string MSBuiltinName; // Name of the corresponding MS builtin, or "".
|
||||
std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics.
|
||||
|
||||
/// This structure holds the return values and parameter values of an
|
||||
/// intrinsic. If the number of return values is > 1, then the intrinsic
|
||||
@@ -136,9 +136,7 @@ struct CodeGenIntrinsic {
|
||||
|
||||
void addArgAttribute(unsigned Idx, ArgAttrKind AK, uint64_t V = 0);
|
||||
|
||||
bool hasProperty(enum SDNP Prop) const {
|
||||
return Properties & (1 << Prop);
|
||||
}
|
||||
bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); }
|
||||
|
||||
/// Goes through all IntrProperties that have IsDefault
|
||||
/// value set and sets the property.
|
||||
@@ -182,6 +180,6 @@ public:
|
||||
return Intrinsics[Pos];
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
||||
@@ -80,9 +80,9 @@
|
||||
#include "llvm/TableGen/Error.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
using namespace llvm;
|
||||
typedef std::map<std::string, std::vector<Record*> > InstrRelMapTy;
|
||||
typedef std::map<std::string, std::vector<Record *>> InstrRelMapTy;
|
||||
|
||||
typedef std::map<std::vector<Init*>, std::vector<Record*> > RowInstrMapTy;
|
||||
typedef std::map<std::vector<Init *>, std::vector<Record *>> RowInstrMapTy;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -95,10 +95,10 @@ private:
|
||||
ListInit *RowFields;
|
||||
ListInit *ColFields;
|
||||
ListInit *KeyCol;
|
||||
std::vector<ListInit*> ValueCols;
|
||||
std::vector<ListInit *> ValueCols;
|
||||
|
||||
public:
|
||||
InstrMap(Record* MapRec) {
|
||||
InstrMap(Record *MapRec) {
|
||||
Name = std::string(MapRec->getName());
|
||||
|
||||
// FilterClass - It's used to reduce the search space only to the
|
||||
@@ -130,7 +130,8 @@ public:
|
||||
// Each instruction map must specify at least one column for it to be valid.
|
||||
if (ColValList->empty())
|
||||
PrintFatalError(MapRec->getLoc(), "InstrMapping record `" +
|
||||
MapRec->getName() + "' has empty " + "`ValueCols' field!");
|
||||
MapRec->getName() + "' has empty " +
|
||||
"`ValueCols' field!");
|
||||
|
||||
for (Init *I : ColValList->getValues()) {
|
||||
auto *ColI = cast<ListInit>(I);
|
||||
@@ -138,9 +139,10 @@ public:
|
||||
// Make sure that all the sub-lists in 'ValueCols' have same number of
|
||||
// elements as the fields in 'ColFields'.
|
||||
if (ColI->size() != ColFields->size())
|
||||
PrintFatalError(MapRec->getLoc(), "Record `" + MapRec->getName() +
|
||||
"', field `ValueCols' entries don't match with " +
|
||||
" the entries in 'ColFields'!");
|
||||
PrintFatalError(MapRec->getLoc(),
|
||||
"Record `" + MapRec->getName() +
|
||||
"', field `ValueCols' entries don't match with " +
|
||||
" the entries in 'ColFields'!");
|
||||
ValueCols.push_back(ColI);
|
||||
}
|
||||
}
|
||||
@@ -155,13 +157,10 @@ public:
|
||||
|
||||
ListInit *getKeyCol() const { return KeyCol; }
|
||||
|
||||
const std::vector<ListInit*> &getValueCols() const {
|
||||
return ValueCols;
|
||||
}
|
||||
const std::vector<ListInit *> &getValueCols() const { return ValueCols; }
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// class MapTableEmitter : It builds the instruction relation maps using
|
||||
// the information provided in InstrMapping records. It outputs these
|
||||
@@ -171,26 +170,26 @@ public:
|
||||
namespace {
|
||||
class MapTableEmitter {
|
||||
private:
|
||||
// std::string TargetName;
|
||||
// std::string TargetName;
|
||||
const CodeGenTarget &Target;
|
||||
// InstrMapDesc - InstrMapping record to be processed.
|
||||
InstrMap InstrMapDesc;
|
||||
|
||||
// InstrDefs - list of instructions filtered using FilterClass defined
|
||||
// in InstrMapDesc.
|
||||
std::vector<Record*> InstrDefs;
|
||||
std::vector<Record *> InstrDefs;
|
||||
|
||||
// RowInstrMap - maps RowFields values to the instructions. It's keyed by the
|
||||
// values of the row fields and contains vector of records as values.
|
||||
RowInstrMapTy RowInstrMap;
|
||||
|
||||
// KeyInstrVec - list of key instructions.
|
||||
std::vector<Record*> KeyInstrVec;
|
||||
DenseMap<Record*, std::vector<Record*> > MapTable;
|
||||
std::vector<Record *> KeyInstrVec;
|
||||
DenseMap<Record *, std::vector<Record *>> MapTable;
|
||||
|
||||
public:
|
||||
MapTableEmitter(CodeGenTarget &Target, RecordKeeper &Records, Record *IMRec):
|
||||
Target(Target), InstrMapDesc(IMRec) {
|
||||
MapTableEmitter(CodeGenTarget &Target, RecordKeeper &Records, Record *IMRec)
|
||||
: Target(Target), InstrMapDesc(IMRec) {
|
||||
const std::string &FilterClass = InstrMapDesc.getFilterClass();
|
||||
InstrDefs = Records.getAllDerivedDefinitions(FilterClass);
|
||||
}
|
||||
@@ -199,7 +198,7 @@ public:
|
||||
|
||||
// Returns true if an instruction is a key instruction, i.e., its ColFields
|
||||
// have same values as KeyCol.
|
||||
bool isKeyColInstr(Record* CurInstr);
|
||||
bool isKeyColInstr(Record *CurInstr);
|
||||
|
||||
// Find column instruction corresponding to a key instruction based on the
|
||||
// constraints for that column.
|
||||
@@ -215,11 +214,9 @@ public:
|
||||
|
||||
// Lookup functions to query binary search tables.
|
||||
void emitMapFuncBody(raw_ostream &OS, unsigned TableSize);
|
||||
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Process all the instructions that model this relation (alreday present in
|
||||
// InstrDefs) and insert them into RowInstrMap which is keyed by the values of
|
||||
@@ -230,14 +227,15 @@ public:
|
||||
|
||||
void MapTableEmitter::buildRowInstrMap() {
|
||||
for (Record *CurInstr : InstrDefs) {
|
||||
std::vector<Init*> KeyValue;
|
||||
std::vector<Init *> KeyValue;
|
||||
ListInit *RowFields = InstrMapDesc.getRowFields();
|
||||
for (Init *RowField : RowFields->getValues()) {
|
||||
RecordVal *RecVal = CurInstr->getValue(RowField);
|
||||
if (RecVal == nullptr)
|
||||
PrintFatalError(CurInstr->getLoc(), "No value " +
|
||||
RowField->getAsString() + " found in \"" +
|
||||
CurInstr->getName() + "\" instruction description.");
|
||||
PrintFatalError(CurInstr->getLoc(),
|
||||
"No value " + RowField->getAsString() + " found in \"" +
|
||||
CurInstr->getName() +
|
||||
"\" instruction description.");
|
||||
Init *CurInstrVal = RecVal->getValue();
|
||||
KeyValue.push_back(CurInstrVal);
|
||||
}
|
||||
@@ -256,14 +254,14 @@ void MapTableEmitter::buildRowInstrMap() {
|
||||
// Return true if an instruction is a KeyCol instruction.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool MapTableEmitter::isKeyColInstr(Record* CurInstr) {
|
||||
bool MapTableEmitter::isKeyColInstr(Record *CurInstr) {
|
||||
ListInit *ColFields = InstrMapDesc.getColFields();
|
||||
ListInit *KeyCol = InstrMapDesc.getKeyCol();
|
||||
|
||||
// Check if the instruction is a KeyCol instruction.
|
||||
bool MatchFound = true;
|
||||
for (unsigned j = 0, endCF = ColFields->size();
|
||||
(j < endCF) && MatchFound; j++) {
|
||||
for (unsigned j = 0, endCF = ColFields->size(); (j < endCF) && MatchFound;
|
||||
j++) {
|
||||
RecordVal *ColFieldName = CurInstr->getValue(ColFields->getElement(j));
|
||||
std::string CurInstrVal = ColFieldName->getValue()->getAsUnquotedString();
|
||||
std::string KeyColValue = KeyCol->getElement(j)->getAsUnquotedString();
|
||||
@@ -280,10 +278,10 @@ bool MapTableEmitter::isKeyColInstr(Record* CurInstr) {
|
||||
void MapTableEmitter::buildMapTable() {
|
||||
// Find column instructions for a given key based on the ColField
|
||||
// constraints.
|
||||
const std::vector<ListInit*> &ValueCols = InstrMapDesc.getValueCols();
|
||||
const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();
|
||||
unsigned NumOfCols = ValueCols.size();
|
||||
for (Record *CurKeyInstr : KeyInstrVec) {
|
||||
std::vector<Record*> ColInstrVec(NumOfCols);
|
||||
std::vector<Record *> ColInstrVec(NumOfCols);
|
||||
|
||||
// Find the column instruction based on the constraints for the column.
|
||||
for (unsigned ColIdx = 0; ColIdx < NumOfCols; ColIdx++) {
|
||||
@@ -302,7 +300,7 @@ void MapTableEmitter::buildMapTable() {
|
||||
Record *MapTableEmitter::getInstrForColumn(Record *KeyInstr,
|
||||
ListInit *CurValueCol) {
|
||||
ListInit *RowFields = InstrMapDesc.getRowFields();
|
||||
std::vector<Init*> KeyValue;
|
||||
std::vector<Init *> KeyValue;
|
||||
|
||||
// Construct KeyValue using KeyInstr's values for RowFields.
|
||||
for (Init *RowField : RowFields->getValues()) {
|
||||
@@ -314,15 +312,15 @@ Record *MapTableEmitter::getInstrForColumn(Record *KeyInstr,
|
||||
// in RowInstrMap. We search through these instructions to find a match
|
||||
// for the current column, i.e., the instruction which has the same values
|
||||
// as CurValueCol for all the fields in ColFields.
|
||||
const std::vector<Record*> &RelatedInstrVec = RowInstrMap[KeyValue];
|
||||
const std::vector<Record *> &RelatedInstrVec = RowInstrMap[KeyValue];
|
||||
|
||||
ListInit *ColFields = InstrMapDesc.getColFields();
|
||||
Record *MatchInstr = nullptr;
|
||||
|
||||
for (llvm::Record *CurInstr : RelatedInstrVec) {
|
||||
bool MatchFound = true;
|
||||
for (unsigned j = 0, endCF = ColFields->size();
|
||||
(j < endCF) && MatchFound; j++) {
|
||||
for (unsigned j = 0, endCF = ColFields->size(); (j < endCF) && MatchFound;
|
||||
j++) {
|
||||
Init *ColFieldJ = ColFields->getElement(j);
|
||||
Init *CurInstrInit = CurInstr->getValue(ColFieldJ)->getValue();
|
||||
std::string CurInstrVal = CurInstrInit->getAsUnquotedString();
|
||||
@@ -360,21 +358,21 @@ Record *MapTableEmitter::getInstrForColumn(Record *KeyInstr,
|
||||
|
||||
unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) {
|
||||
|
||||
ArrayRef<const CodeGenInstruction*> NumberedInstructions =
|
||||
Target.getInstructionsByEnumValue();
|
||||
ArrayRef<const CodeGenInstruction *> NumberedInstructions =
|
||||
Target.getInstructionsByEnumValue();
|
||||
StringRef Namespace = Target.getInstNamespace();
|
||||
const std::vector<ListInit*> &ValueCols = InstrMapDesc.getValueCols();
|
||||
const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();
|
||||
unsigned NumCol = ValueCols.size();
|
||||
unsigned TotalNumInstr = NumberedInstructions.size();
|
||||
unsigned TableSize = 0;
|
||||
|
||||
OS << "static const uint16_t "<<InstrMapDesc.getName();
|
||||
OS << "static const uint16_t " << InstrMapDesc.getName();
|
||||
// Number of columns in the table are NumCol+1 because key instructions are
|
||||
// emitted as first column.
|
||||
OS << "Table[]["<< NumCol+1 << "] = {\n";
|
||||
OS << "Table[][" << NumCol + 1 << "] = {\n";
|
||||
for (unsigned i = 0; i < TotalNumInstr; i++) {
|
||||
Record *CurInstr = NumberedInstructions[i]->TheDef;
|
||||
std::vector<Record*> ColInstrs = MapTable[CurInstr];
|
||||
std::vector<Record *> ColInstrs = MapTable[CurInstr];
|
||||
std::string OutStr;
|
||||
unsigned RelExists = 0;
|
||||
if (!ColInstrs.empty()) {
|
||||
@@ -385,19 +383,23 @@ unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) {
|
||||
OutStr += Namespace;
|
||||
OutStr += "::";
|
||||
OutStr += ColInstrs[j]->getName();
|
||||
} else { OutStr += ", (uint16_t)-1U";}
|
||||
} else {
|
||||
OutStr += ", (uint16_t)-1U";
|
||||
}
|
||||
}
|
||||
|
||||
if (RelExists) {
|
||||
OS << " { " << Namespace << "::" << CurInstr->getName();
|
||||
OS << OutStr <<" },\n";
|
||||
OS << OutStr << " },\n";
|
||||
TableSize++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!TableSize) {
|
||||
OS << " { " << Namespace << "::" << "INSTRUCTION_LIST_END, ";
|
||||
OS << Namespace << "::" << "INSTRUCTION_LIST_END }";
|
||||
OS << " { " << Namespace << "::"
|
||||
<< "INSTRUCTION_LIST_END, ";
|
||||
OS << Namespace << "::"
|
||||
<< "INSTRUCTION_LIST_END }";
|
||||
}
|
||||
OS << "}; // End of " << InstrMapDesc.getName() << "Table\n\n";
|
||||
return TableSize;
|
||||
@@ -430,11 +432,10 @@ void MapTableEmitter::emitBinSearch(raw_ostream &OS, unsigned TableSize) {
|
||||
// Emit functions to query relation tables.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void MapTableEmitter::emitMapFuncBody(raw_ostream &OS,
|
||||
unsigned TableSize) {
|
||||
void MapTableEmitter::emitMapFuncBody(raw_ostream &OS, unsigned TableSize) {
|
||||
|
||||
ListInit *ColFields = InstrMapDesc.getColFields();
|
||||
const std::vector<ListInit*> &ValueCols = InstrMapDesc.getValueCols();
|
||||
const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();
|
||||
|
||||
// Emit binary search algorithm to locate instructions in the
|
||||
// relation table. If found, return opcode value from the appropriate column
|
||||
@@ -455,14 +456,13 @@ void MapTableEmitter::emitMapFuncBody(raw_ostream &OS,
|
||||
}
|
||||
OS << ")\n";
|
||||
OS << " return " << InstrMapDesc.getName();
|
||||
OS << "Table[mid]["<<i+1<<"];\n";
|
||||
OS << "Table[mid][" << i + 1 << "];\n";
|
||||
}
|
||||
OS << " return -1;";
|
||||
}
|
||||
else
|
||||
} else
|
||||
OS << " return " << InstrMapDesc.getName() << "Table[mid][1];\n";
|
||||
|
||||
OS <<"}\n\n";
|
||||
OS << "}\n\n";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -477,9 +477,9 @@ void MapTableEmitter::emitTablesWithFunc(raw_ostream &OS) {
|
||||
// to pass another input to indicate the column to be selected.
|
||||
|
||||
ListInit *ColFields = InstrMapDesc.getColFields();
|
||||
const std::vector<ListInit*> &ValueCols = InstrMapDesc.getValueCols();
|
||||
OS << "// "<< InstrMapDesc.getName() << "\nLLVM_READONLY\n";
|
||||
OS << "int "<< InstrMapDesc.getName() << "(uint16_t Opcode";
|
||||
const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();
|
||||
OS << "// " << InstrMapDesc.getName() << "\nLLVM_READONLY\n";
|
||||
OS << "int " << InstrMapDesc.getName() << "(uint16_t Opcode";
|
||||
if (ValueCols.size() > 1) {
|
||||
for (Init *CF : ColFields->getValues()) {
|
||||
std::string ColName = CF->getAsUnquotedString();
|
||||
@@ -501,9 +501,9 @@ void MapTableEmitter::emitTablesWithFunc(raw_ostream &OS) {
|
||||
|
||||
static void emitEnums(raw_ostream &OS, RecordKeeper &Records) {
|
||||
|
||||
std::vector<Record*> InstrMapVec;
|
||||
std::vector<Record *> InstrMapVec;
|
||||
InstrMapVec = Records.getAllDerivedDefinitions("InstrMapping");
|
||||
std::map<std::string, std::vector<Init*> > ColFieldValueMap;
|
||||
std::map<std::string, std::vector<Init *>> ColFieldValueMap;
|
||||
|
||||
// Iterate over all InstrMapping records and create a map between column
|
||||
// fields and their possible values across all records.
|
||||
@@ -511,20 +511,22 @@ static void emitEnums(raw_ostream &OS, RecordKeeper &Records) {
|
||||
ListInit *ColFields;
|
||||
ColFields = CurMap->getValueAsListInit("ColFields");
|
||||
ListInit *List = CurMap->getValueAsListInit("ValueCols");
|
||||
std::vector<ListInit*> ValueCols;
|
||||
std::vector<ListInit *> ValueCols;
|
||||
unsigned ListSize = List->size();
|
||||
|
||||
for (unsigned j = 0; j < ListSize; j++) {
|
||||
auto *ListJ = cast<ListInit>(List->getElement(j));
|
||||
|
||||
if (ListJ->size() != ColFields->size())
|
||||
PrintFatalError("Record `" + CurMap->getName() + "', field "
|
||||
"`ValueCols' entries don't match with the entries in 'ColFields' !");
|
||||
PrintFatalError("Record `" + CurMap->getName() +
|
||||
"', field "
|
||||
"`ValueCols' entries don't match with the entries in "
|
||||
"'ColFields' !");
|
||||
ValueCols.push_back(ListJ);
|
||||
}
|
||||
|
||||
for (unsigned j = 0, endCF = ColFields->size(); j < endCF; j++) {
|
||||
for (unsigned k = 0; k < ListSize; k++){
|
||||
for (unsigned k = 0; k < ListSize; k++) {
|
||||
std::string ColName = ColFields->getElement(j)->getAsUnquotedString();
|
||||
ColFieldValueMap[ColName].push_back((ValueCols[k])->getElement(j));
|
||||
}
|
||||
@@ -532,14 +534,14 @@ static void emitEnums(raw_ostream &OS, RecordKeeper &Records) {
|
||||
}
|
||||
|
||||
for (auto &Entry : ColFieldValueMap) {
|
||||
std::vector<Init*> FieldValues = Entry.second;
|
||||
std::vector<Init *> FieldValues = Entry.second;
|
||||
|
||||
// Delete duplicate entries from ColFieldValueMap
|
||||
for (unsigned i = 0; i < FieldValues.size() - 1; i++) {
|
||||
Init *CurVal = FieldValues[i];
|
||||
for (unsigned j = i+1; j < FieldValues.size(); j++) {
|
||||
for (unsigned j = i + 1; j < FieldValues.size(); j++) {
|
||||
if (CurVal == FieldValues[j]) {
|
||||
FieldValues.erase(FieldValues.begin()+j);
|
||||
FieldValues.erase(FieldValues.begin() + j);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
@@ -566,7 +568,7 @@ namespace llvm {
|
||||
void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) {
|
||||
CodeGenTarget Target(Records);
|
||||
StringRef NameSpace = Target.getInstNamespace();
|
||||
std::vector<Record*> InstrMapVec;
|
||||
std::vector<Record *> InstrMapVec;
|
||||
InstrMapVec = Records.getAllDerivedDefinitions("InstrMapping");
|
||||
|
||||
if (InstrMapVec.empty())
|
||||
@@ -603,4 +605,4 @@ void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) {
|
||||
OS << "#endif // GET_INSTRMAP_INFO\n\n";
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
} // namespace llvm
|
||||
|
||||
@@ -48,7 +48,7 @@ using namespace llvm;
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CodeGenSubRegIndex::CodeGenSubRegIndex(Record *R, unsigned Enum)
|
||||
: TheDef(R), EnumValue(Enum), AllSuperRegsCovered(true), Artificial(true) {
|
||||
: TheDef(R), EnumValue(Enum), AllSuperRegsCovered(true), Artificial(true) {
|
||||
Name = std::string(R->getName());
|
||||
if (R->getValue("Namespace"))
|
||||
Namespace = std::string(R->getValueAsString("Namespace"));
|
||||
@@ -74,7 +74,7 @@ void CodeGenSubRegIndex::updateComponents(CodeGenRegBank &RegBank) {
|
||||
if (!TheDef)
|
||||
return;
|
||||
|
||||
std::vector<Record*> Comps = TheDef->getValueAsListOfDefs("ComposedOf");
|
||||
std::vector<Record *> Comps = TheDef->getValueAsListOfDefs("ComposedOf");
|
||||
if (!Comps.empty()) {
|
||||
if (Comps.size() != 2)
|
||||
PrintFatalError(TheDef->getLoc(),
|
||||
@@ -86,13 +86,13 @@ void CodeGenSubRegIndex::updateComponents(CodeGenRegBank &RegBank) {
|
||||
PrintFatalError(TheDef->getLoc(), "Ambiguous ComposedOf entries");
|
||||
}
|
||||
|
||||
std::vector<Record*> Parts =
|
||||
TheDef->getValueAsListOfDefs("CoveringSubRegIndices");
|
||||
std::vector<Record *> Parts =
|
||||
TheDef->getValueAsListOfDefs("CoveringSubRegIndices");
|
||||
if (!Parts.empty()) {
|
||||
if (Parts.size() < 2)
|
||||
PrintFatalError(TheDef->getLoc(),
|
||||
"CoveredBySubRegs must have two or more entries");
|
||||
SmallVector<CodeGenSubRegIndex*, 8> IdxParts;
|
||||
SmallVector<CodeGenSubRegIndex *, 8> IdxParts;
|
||||
for (Record *Part : Parts)
|
||||
IdxParts.push_back(RegBank.getSubRegIdx(Part));
|
||||
setConcatenationOf(IdxParts);
|
||||
@@ -117,17 +117,19 @@ LaneBitmask CodeGenSubRegIndex::computeLaneMask() const {
|
||||
}
|
||||
|
||||
void CodeGenSubRegIndex::setConcatenationOf(
|
||||
ArrayRef<CodeGenSubRegIndex*> Parts) {
|
||||
ArrayRef<CodeGenSubRegIndex *> Parts) {
|
||||
if (ConcatenationOf.empty())
|
||||
ConcatenationOf.assign(Parts.begin(), Parts.end());
|
||||
else
|
||||
assert(std::equal(Parts.begin(), Parts.end(),
|
||||
ConcatenationOf.begin()) && "parts consistent");
|
||||
assert(std::equal(Parts.begin(), Parts.end(), ConcatenationOf.begin()) &&
|
||||
"parts consistent");
|
||||
}
|
||||
|
||||
void CodeGenSubRegIndex::computeConcatTransitiveClosure() {
|
||||
for (SmallVectorImpl<CodeGenSubRegIndex*>::iterator
|
||||
I = ConcatenationOf.begin(); I != ConcatenationOf.end(); /*empty*/) {
|
||||
for (SmallVectorImpl<CodeGenSubRegIndex *>::iterator I =
|
||||
ConcatenationOf.begin();
|
||||
I != ConcatenationOf.end();
|
||||
/*empty*/) {
|
||||
CodeGenSubRegIndex *SubIdx = *I;
|
||||
SubIdx->computeConcatTransitiveClosure();
|
||||
#ifndef NDEBUG
|
||||
@@ -160,8 +162,8 @@ CodeGenRegister::CodeGenRegister(Record *R, unsigned Enum)
|
||||
}
|
||||
|
||||
void CodeGenRegister::buildObjectGraph(CodeGenRegBank &RegBank) {
|
||||
std::vector<Record*> SRIs = TheDef->getValueAsListOfDefs("SubRegIndices");
|
||||
std::vector<Record*> SRs = TheDef->getValueAsListOfDefs("SubRegs");
|
||||
std::vector<Record *> SRIs = TheDef->getValueAsListOfDefs("SubRegIndices");
|
||||
std::vector<Record *> SRs = TheDef->getValueAsListOfDefs("SubRegs");
|
||||
|
||||
if (SRIs.size() != SRs.size())
|
||||
PrintFatalError(TheDef->getLoc(),
|
||||
@@ -182,7 +184,7 @@ void CodeGenRegister::buildObjectGraph(CodeGenRegBank &RegBank) {
|
||||
|
||||
// Add ad hoc alias links. This is a symmetric relationship between two
|
||||
// registers, so build a symmetric graph by adding links in both ends.
|
||||
std::vector<Record*> Aliases = TheDef->getValueAsListOfDefs("Aliases");
|
||||
std::vector<Record *> Aliases = TheDef->getValueAsListOfDefs("Aliases");
|
||||
for (Record *Alias : Aliases) {
|
||||
CodeGenRegister *Reg = RegBank.getReg(Alias);
|
||||
ExplicitAliases.push_back(Reg);
|
||||
@@ -204,8 +206,8 @@ class RegUnitIterator {
|
||||
static CodeGenRegister::RegUnitList Sentinel;
|
||||
|
||||
public:
|
||||
RegUnitIterator(const CodeGenRegister::Vec &Regs):
|
||||
RegI(Regs.begin()), RegE(Regs.end()) {
|
||||
RegUnitIterator(const CodeGenRegister::Vec &Regs)
|
||||
: RegI(Regs.begin()), RegE(Regs.end()) {
|
||||
|
||||
if (RegI == RegE) {
|
||||
UnitI = Sentinel.end();
|
||||
@@ -219,9 +221,15 @@ public:
|
||||
|
||||
bool isValid() const { return UnitI != UnitE; }
|
||||
|
||||
unsigned operator* () const { assert(isValid()); return *UnitI; }
|
||||
unsigned operator*() const {
|
||||
assert(isValid());
|
||||
return *UnitI;
|
||||
}
|
||||
|
||||
const CodeGenRegister *getReg() const { assert(isValid()); return *RegI; }
|
||||
const CodeGenRegister *getReg() const {
|
||||
assert(isValid());
|
||||
return *RegI;
|
||||
}
|
||||
|
||||
/// Preincrement. Move to the next unit.
|
||||
void operator++() {
|
||||
@@ -280,14 +288,15 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) {
|
||||
Idx->Artificial = false;
|
||||
if (!SubRegs.insert(std::make_pair(Idx, SR)).second)
|
||||
PrintFatalError(TheDef->getLoc(), "SubRegIndex " + Idx->getName() +
|
||||
" appears twice in Register " + getName());
|
||||
" appears twice in Register " +
|
||||
getName());
|
||||
// Map explicit sub-registers first, so the names take precedence.
|
||||
// The inherited sub-registers are mapped below.
|
||||
SubReg2Idx.insert(std::make_pair(SR, Idx));
|
||||
}
|
||||
|
||||
// Keep track of inherited subregs and how they can be reached.
|
||||
SmallPtrSet<CodeGenRegister*, 8> Orphans;
|
||||
SmallPtrSet<CodeGenRegister *, 8> Orphans;
|
||||
|
||||
// Clone inherited subregs and place duplicate entries in Orphans.
|
||||
// Here the order is important - earlier subregs take precedence.
|
||||
@@ -305,7 +314,7 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) {
|
||||
// If dsub_2 has ComposedOf = [qsub_1, dsub_0], and this register has a
|
||||
// qsub_1 subreg, add a dsub_2 subreg. Keep growing Indices and process
|
||||
// expanded subreg indices recursively.
|
||||
SmallVector<CodeGenSubRegIndex*, 8> Indices = ExplicitSubRegIndices;
|
||||
SmallVector<CodeGenSubRegIndex *, 8> Indices = ExplicitSubRegIndices;
|
||||
for (unsigned i = 0; i != Indices.size(); ++i) {
|
||||
CodeGenSubRegIndex *Idx = Indices[i];
|
||||
const CodeGenSubRegIndex::CompMap &Comps = Idx->getComposites();
|
||||
@@ -350,7 +359,8 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) {
|
||||
const SubRegMap &Map = SR->computeSubRegs(RegBank);
|
||||
for (const auto &SubReg : Map)
|
||||
if (Orphans.erase(SubReg.second))
|
||||
SubRegs[RegBank.getCompositeSubRegIndex(Idx, SubReg.first)] = SubReg.second;
|
||||
SubRegs[RegBank.getCompositeSubRegIndex(Idx, SubReg.first)] =
|
||||
SubReg.second;
|
||||
}
|
||||
|
||||
// Compute the inverse SubReg -> Idx map.
|
||||
@@ -360,7 +370,7 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) {
|
||||
if (TheDef)
|
||||
Loc = TheDef->getLoc();
|
||||
PrintFatalError(Loc, "Register " + getName() +
|
||||
" has itself as a sub-register");
|
||||
" has itself as a sub-register");
|
||||
}
|
||||
|
||||
// Compute AllSuperRegsCovered.
|
||||
@@ -368,17 +378,18 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) {
|
||||
SubReg.first->AllSuperRegsCovered = false;
|
||||
|
||||
// Ensure that every sub-register has a unique name.
|
||||
DenseMap<const CodeGenRegister*, CodeGenSubRegIndex*>::iterator Ins =
|
||||
SubReg2Idx.insert(std::make_pair(SubReg.second, SubReg.first)).first;
|
||||
DenseMap<const CodeGenRegister *, CodeGenSubRegIndex *>::iterator Ins =
|
||||
SubReg2Idx.insert(std::make_pair(SubReg.second, SubReg.first)).first;
|
||||
if (Ins->second == SubReg.first)
|
||||
continue;
|
||||
// Trouble: Two different names for SubReg.second.
|
||||
ArrayRef<SMLoc> Loc;
|
||||
if (TheDef)
|
||||
Loc = TheDef->getLoc();
|
||||
PrintFatalError(Loc, "Sub-register can't have two names: " +
|
||||
SubReg.second->getName() + " available as " +
|
||||
SubReg.first->getName() + " and " + Ins->second->getName());
|
||||
PrintFatalError(
|
||||
Loc, "Sub-register can't have two names: " + SubReg.second->getName() +
|
||||
" available as " + SubReg.first->getName() + " and " +
|
||||
Ins->second->getName());
|
||||
}
|
||||
|
||||
// Derive possible names for sub-register concatenations from any explicit
|
||||
@@ -392,7 +403,7 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) {
|
||||
continue;
|
||||
|
||||
// SR is composed of multiple sub-regs. Find their names in this register.
|
||||
SmallVector<CodeGenSubRegIndex*, 8> Parts;
|
||||
SmallVector<CodeGenSubRegIndex *, 8> Parts;
|
||||
for (unsigned j = 0, e = SR->ExplicitSubRegs.size(); j != e; ++j) {
|
||||
CodeGenSubRegIndex &I = *SR->ExplicitSubRegIndices[j];
|
||||
if (!I.Artificial)
|
||||
@@ -464,8 +475,8 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) {
|
||||
void CodeGenRegister::computeSecondarySubRegs(CodeGenRegBank &RegBank) {
|
||||
SmallVector<SubRegMap::value_type, 8> NewSubRegs;
|
||||
|
||||
std::queue<std::pair<CodeGenSubRegIndex*,CodeGenRegister*>> SubRegQueue;
|
||||
for (std::pair<CodeGenSubRegIndex*,CodeGenRegister*> P : SubRegs)
|
||||
std::queue<std::pair<CodeGenSubRegIndex *, CodeGenRegister *>> SubRegQueue;
|
||||
for (std::pair<CodeGenSubRegIndex *, CodeGenRegister *> P : SubRegs)
|
||||
SubRegQueue.push(P);
|
||||
|
||||
// Look at the leading super-registers of each sub-register. Those are the
|
||||
@@ -479,7 +490,7 @@ void CodeGenRegister::computeSecondarySubRegs(CodeGenRegBank &RegBank) {
|
||||
|
||||
const CodeGenRegister::SuperRegList &Leads = SubReg->LeadingSuperRegs;
|
||||
for (unsigned i = 0, e = Leads.size(); i != e; ++i) {
|
||||
CodeGenRegister *Cand = const_cast<CodeGenRegister*>(Leads[i]);
|
||||
CodeGenRegister *Cand = const_cast<CodeGenRegister *>(Leads[i]);
|
||||
// Already got this sub-register?
|
||||
if (Cand == this || getSubRegIndex(Cand))
|
||||
continue;
|
||||
@@ -488,7 +499,7 @@ void CodeGenRegister::computeSecondarySubRegs(CodeGenRegBank &RegBank) {
|
||||
"Super-register has no sub-registers");
|
||||
if (Cand->ExplicitSubRegs.size() == 1)
|
||||
continue;
|
||||
SmallVector<CodeGenSubRegIndex*, 8> Parts;
|
||||
SmallVector<CodeGenSubRegIndex *, 8> Parts;
|
||||
// We know that the first component is (SubRegIdx,SubReg). However we
|
||||
// may still need to split it into smaller subregister parts.
|
||||
assert(Cand->ExplicitSubRegs[0] == SubReg && "LeadingSuperRegs correct");
|
||||
@@ -513,7 +524,7 @@ void CodeGenRegister::computeSecondarySubRegs(CodeGenRegBank &RegBank) {
|
||||
// Each part of Cand is a sub-register of this. Make the full Cand also
|
||||
// a sub-register with a concatenated sub-register index.
|
||||
CodeGenSubRegIndex *Concat = RegBank.getConcatSubRegIndex(Parts);
|
||||
std::pair<CodeGenSubRegIndex*,CodeGenRegister*> NewSubReg =
|
||||
std::pair<CodeGenSubRegIndex *, CodeGenRegister *> NewSubReg =
|
||||
std::make_pair(Concat, Cand);
|
||||
|
||||
if (!SubRegs.insert(NewSubReg).second)
|
||||
@@ -570,9 +581,8 @@ void CodeGenRegister::computeSuperRegs(CodeGenRegBank &RegBank) {
|
||||
TopoSig = RegBank.getTopoSig(Id);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenRegister::addSubRegsPreOrder(SetVector<const CodeGenRegister*> &OSet,
|
||||
CodeGenRegBank &RegBank) const {
|
||||
void CodeGenRegister::addSubRegsPreOrder(
|
||||
SetVector<const CodeGenRegister *> &OSet, CodeGenRegBank &RegBank) const {
|
||||
assert(SubRegsComplete && "Must precompute sub-registers");
|
||||
for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) {
|
||||
CodeGenRegister *SR = ExplicitSubRegs[i];
|
||||
@@ -611,7 +621,7 @@ struct TupleExpander : SetTheory::Expander {
|
||||
: SynthDefs(SynthDefs) {}
|
||||
|
||||
void expand(SetTheory &ST, Record *Def, SetTheory::RecSet &Elts) override {
|
||||
std::vector<Record*> Indices = Def->getValueAsListOfDefs("SubRegIndices");
|
||||
std::vector<Record *> Indices = Def->getValueAsListOfDefs("SubRegIndices");
|
||||
unsigned Dim = Indices.size();
|
||||
ListInit *SubRegs = Def->getValueAsListInit("SubRegs");
|
||||
if (Dim != SubRegs->size())
|
||||
@@ -635,17 +645,18 @@ struct TupleExpander : SetTheory::Expander {
|
||||
Record *RegisterCl = Def->getRecords().getClass("Register");
|
||||
RecTy *RegisterRecTy = RecordRecTy::get(RegisterCl);
|
||||
std::vector<StringRef> RegNames =
|
||||
Def->getValueAsListOfStrings("RegAsmNames");
|
||||
Def->getValueAsListOfStrings("RegAsmNames");
|
||||
|
||||
// Zip them up.
|
||||
RecordKeeper &RK = Def->getRecords();
|
||||
for (unsigned n = 0; n != Length; ++n) {
|
||||
std::string Name;
|
||||
Record *Proto = Lists[0][n];
|
||||
std::vector<Init*> Tuple;
|
||||
std::vector<Init *> Tuple;
|
||||
for (unsigned i = 0; i != Dim; ++i) {
|
||||
Record *Reg = Lists[i][n];
|
||||
if (i) Name += '_';
|
||||
if (i)
|
||||
Name += '_';
|
||||
Name += Reg->getName();
|
||||
Tuple.push_back(DefInit::get(Reg));
|
||||
}
|
||||
@@ -660,7 +671,7 @@ struct TupleExpander : SetTheory::Expander {
|
||||
if (RegNames.size() <= n)
|
||||
PrintFatalError(Def->getLoc(),
|
||||
"Register tuple definition missing name for '" +
|
||||
Name + "'.");
|
||||
Name + "'.");
|
||||
AsmName = StringInit::get(RK, RegNames[n]);
|
||||
}
|
||||
|
||||
@@ -703,15 +714,13 @@ struct TupleExpander : SetTheory::Expander {
|
||||
RV.setValue(BitInit::get(RK, true));
|
||||
|
||||
// Copy fields from the RegisterTuples def.
|
||||
if (Field == "SubRegIndices" ||
|
||||
Field == "CompositeIndices") {
|
||||
if (Field == "SubRegIndices" || Field == "CompositeIndices") {
|
||||
NewReg->addValue(*Def->getValue(Field));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Some fields get their default uninitialized value.
|
||||
if (Field == "DwarfNumbers" ||
|
||||
Field == "DwarfAlias" ||
|
||||
if (Field == "DwarfNumbers" || Field == "DwarfAlias" ||
|
||||
Field == "Aliases") {
|
||||
if (const RecordVal *DefRV = RegisterCl->getValue(Field))
|
||||
NewReg->addValue(*DefRV);
|
||||
@@ -740,7 +749,7 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
|
||||
: TheDef(R), Name(std::string(R->getName())),
|
||||
TopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1), TSFlags(0) {
|
||||
GeneratePressureSet = R->getValueAsBit("GeneratePressureSet");
|
||||
std::vector<Record*> TypeList = R->getValueAsListOfDefs("RegTypes");
|
||||
std::vector<Record *> TypeList = R->getValueAsListOfDefs("RegTypes");
|
||||
if (TypeList.empty())
|
||||
PrintFatalError(R->getLoc(), "RegTypes list must not be empty!");
|
||||
for (unsigned i = 0, e = TypeList.size(); i != e; ++i) {
|
||||
@@ -779,7 +788,7 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
|
||||
Order.pop_back();
|
||||
if (!contains(Reg))
|
||||
PrintFatalError(R->getLoc(), " AltOrder register " + Reg->getName() +
|
||||
" is not a class member");
|
||||
" is not a class member");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,8 +802,8 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
|
||||
"Impossible to determine register size");
|
||||
if (!RSI.hasDefault()) {
|
||||
RegSizeInfo RI;
|
||||
RI.RegSize = RI.SpillSize = Size ? Size
|
||||
: VTs[0].getSimple().getSizeInBits();
|
||||
RI.RegSize = RI.SpillSize =
|
||||
Size ? Size : VTs[0].getSimple().getSizeInBits();
|
||||
RI.SpillAlignment = R->getValueAsInt("Alignment");
|
||||
RSI.insertRegSizeForMode(DefaultMode, RI);
|
||||
}
|
||||
@@ -890,7 +899,7 @@ bool CodeGenRegisterClass::contains(const CodeGenRegister *Reg) const {
|
||||
deref<std::less<>>());
|
||||
}
|
||||
|
||||
unsigned CodeGenRegisterClass::getWeight(const CodeGenRegBank& RegBank) const {
|
||||
unsigned CodeGenRegisterClass::getWeight(const CodeGenRegBank &RegBank) const {
|
||||
if (TheDef && !TheDef->isValueUnset("Weight"))
|
||||
return TheDef->getValueAsInt("Weight");
|
||||
|
||||
@@ -902,19 +911,19 @@ unsigned CodeGenRegisterClass::getWeight(const CodeGenRegBank& RegBank) const {
|
||||
|
||||
namespace llvm {
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const CodeGenRegisterClass::Key &K) {
|
||||
OS << "{ " << K.RSI;
|
||||
for (const auto R : *K.Members)
|
||||
OS << ", " << R->getName();
|
||||
return OS << " }";
|
||||
}
|
||||
raw_ostream &operator<<(raw_ostream &OS, const CodeGenRegisterClass::Key &K) {
|
||||
OS << "{ " << K.RSI;
|
||||
for (const auto R : *K.Members)
|
||||
OS << ", " << R->getName();
|
||||
return OS << " }";
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
// This is a simple lexicographical order that can be used to search for sets.
|
||||
// It is not the same as the topological order provided by TopoOrderRC.
|
||||
bool CodeGenRegisterClass::Key::
|
||||
operator<(const CodeGenRegisterClass::Key &B) const {
|
||||
bool CodeGenRegisterClass::Key::operator<(
|
||||
const CodeGenRegisterClass::Key &B) const {
|
||||
assert(Members && B.Members);
|
||||
return std::tie(*Members, RSI) < std::tie(*B.Members, B.RSI);
|
||||
}
|
||||
@@ -1066,7 +1075,7 @@ CodeGenRegisterClass::getMatchingSubClassWithSubRegs(
|
||||
|
||||
// Find all the subreg classes and order them by size too.
|
||||
std::vector<std::pair<CodeGenRegisterClass *, BitVector>> SuperRegClasses;
|
||||
for (auto &RC: RegClasses) {
|
||||
for (auto &RC : RegClasses) {
|
||||
BitVector SuperRegClassesBV(RegClasses.size());
|
||||
RC.getSuperRegClasses(SubIdx, SuperRegClassesBV);
|
||||
if (SuperRegClassesBV.any())
|
||||
@@ -1129,8 +1138,8 @@ void CodeGenRegisterClass::getSuperRegClasses(const CodeGenSubRegIndex *SubIdx,
|
||||
}
|
||||
|
||||
// Populate a unique sorted list of units from a register set.
|
||||
void CodeGenRegisterClass::buildRegUnitSet(const CodeGenRegBank &RegBank,
|
||||
std::vector<unsigned> &RegUnits) const {
|
||||
void CodeGenRegisterClass::buildRegUnitSet(
|
||||
const CodeGenRegBank &RegBank, std::vector<unsigned> &RegUnits) const {
|
||||
std::vector<unsigned> TmpUnits;
|
||||
for (RegUnitIterator UnitI(Members); UnitI.isValid(); ++UnitI) {
|
||||
const RegUnit &RU = RegBank.getRegUnit(*UnitI);
|
||||
@@ -1158,7 +1167,8 @@ CodeGenRegisterCategory::CodeGenRegisterCategory(CodeGenRegBank &RegBank,
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records,
|
||||
const CodeGenHwModes &Modes) : CGH(Modes) {
|
||||
const CodeGenHwModes &Modes)
|
||||
: CGH(Modes) {
|
||||
// Configure register Sets to understand register classes and tuples.
|
||||
Sets.addFieldExpander("RegisterClass", "MemberList");
|
||||
Sets.addFieldExpander("CalleeSavedRegs", "SaveList");
|
||||
@@ -1167,7 +1177,7 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records,
|
||||
|
||||
// Read in the user-defined (named) sub-register indices.
|
||||
// More indices will be synthesized later.
|
||||
std::vector<Record*> SRIs = Records.getAllDerivedDefinitions("SubRegIndex");
|
||||
std::vector<Record *> SRIs = Records.getAllDerivedDefinitions("SubRegIndex");
|
||||
llvm::sort(SRIs, LessRecord());
|
||||
for (unsigned i = 0, e = SRIs.size(); i != e; ++i)
|
||||
getSubRegIdx(SRIs[i]);
|
||||
@@ -1238,8 +1248,9 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records,
|
||||
SRI.computeConcatTransitiveClosure();
|
||||
if (!SRI.ConcatenationOf.empty())
|
||||
ConcatIdx.insert(std::make_pair(
|
||||
SmallVector<CodeGenSubRegIndex*,8>(SRI.ConcatenationOf.begin(),
|
||||
SRI.ConcatenationOf.end()), &SRI));
|
||||
SmallVector<CodeGenSubRegIndex *, 8>(SRI.ConcatenationOf.begin(),
|
||||
SRI.ConcatenationOf.end()),
|
||||
&SRI));
|
||||
}
|
||||
|
||||
// Infer even more sub-registers by combining leading super-registers.
|
||||
@@ -1269,7 +1280,7 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records,
|
||||
NumNativeRegUnits = RegUnits.size();
|
||||
|
||||
// Read in register class definitions.
|
||||
std::vector<Record*> RCs = Records.getAllDerivedDefinitions("RegisterClass");
|
||||
std::vector<Record *> RCs = Records.getAllDerivedDefinitions("RegisterClass");
|
||||
if (RCs.empty())
|
||||
PrintFatalError("No 'RegisterClass' subclasses defined!");
|
||||
|
||||
@@ -1299,8 +1310,8 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records,
|
||||
}
|
||||
|
||||
// Create a synthetic CodeGenSubRegIndex without a corresponding Record.
|
||||
CodeGenSubRegIndex*
|
||||
CodeGenRegBank::createSubRegIndex(StringRef Name, StringRef Namespace) {
|
||||
CodeGenSubRegIndex *CodeGenRegBank::createSubRegIndex(StringRef Name,
|
||||
StringRef Namespace) {
|
||||
SubRegIndices.emplace_back(Name, Namespace, SubRegIndices.size() + 1);
|
||||
return &SubRegIndices.back();
|
||||
}
|
||||
@@ -1315,7 +1326,7 @@ CodeGenSubRegIndex *CodeGenRegBank::getSubRegIdx(Record *Def) {
|
||||
}
|
||||
|
||||
const CodeGenSubRegIndex *
|
||||
CodeGenRegBank::findSubRegIdx(const Record* Def) const {
|
||||
CodeGenRegBank::findSubRegIdx(const Record *Def) const {
|
||||
return Def2SubRegIdx.lookup(Def);
|
||||
}
|
||||
|
||||
@@ -1339,7 +1350,7 @@ void CodeGenRegBank::addToMaps(CodeGenRegisterClass *RC) {
|
||||
}
|
||||
|
||||
// Create a synthetic sub-class if it is missing.
|
||||
CodeGenRegisterClass*
|
||||
CodeGenRegisterClass *
|
||||
CodeGenRegBank::getOrCreateSubClass(const CodeGenRegisterClass *RC,
|
||||
const CodeGenRegister::Vec *Members,
|
||||
StringRef Name) {
|
||||
@@ -1362,7 +1373,7 @@ CodeGenRegisterClass *CodeGenRegBank::getRegClass(const Record *Def) const {
|
||||
PrintFatalError(Def->getLoc(), "Not a known RegisterClass!");
|
||||
}
|
||||
|
||||
CodeGenSubRegIndex*
|
||||
CodeGenSubRegIndex *
|
||||
CodeGenRegBank::getCompositeSubRegIndex(CodeGenSubRegIndex *A,
|
||||
CodeGenSubRegIndex *B) {
|
||||
// Look for an existing entry.
|
||||
@@ -1377,8 +1388,8 @@ CodeGenRegBank::getCompositeSubRegIndex(CodeGenSubRegIndex *A,
|
||||
return Comp;
|
||||
}
|
||||
|
||||
CodeGenSubRegIndex *CodeGenRegBank::
|
||||
getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex *, 8> &Parts) {
|
||||
CodeGenSubRegIndex *CodeGenRegBank::getConcatSubRegIndex(
|
||||
const SmallVector<CodeGenSubRegIndex *, 8> &Parts) {
|
||||
assert(Parts.size() > 1 && "Need two parts to concatenate");
|
||||
#ifndef NDEBUG
|
||||
for (CodeGenSubRegIndex *Idx : Parts) {
|
||||
@@ -1419,26 +1430,26 @@ getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex *, 8> &Parts) {
|
||||
}
|
||||
|
||||
void CodeGenRegBank::computeComposites() {
|
||||
using RegMap = std::map<const CodeGenRegister*, const CodeGenRegister*>;
|
||||
using RegMap = std::map<const CodeGenRegister *, const CodeGenRegister *>;
|
||||
|
||||
// Subreg -> { Reg->Reg }, where the right-hand side is the mapping from
|
||||
// register to (sub)register associated with the action of the left-hand
|
||||
// side subregister.
|
||||
std::map<const CodeGenSubRegIndex*, RegMap> SubRegAction;
|
||||
std::map<const CodeGenSubRegIndex *, RegMap> SubRegAction;
|
||||
for (const CodeGenRegister &R : Registers) {
|
||||
const CodeGenRegister::SubRegMap &SM = R.getSubRegs();
|
||||
for (std::pair<const CodeGenSubRegIndex*, const CodeGenRegister*> P : SM)
|
||||
for (std::pair<const CodeGenSubRegIndex *, const CodeGenRegister *> P : SM)
|
||||
SubRegAction[P.first].insert({&R, P.second});
|
||||
}
|
||||
|
||||
// Calculate the composition of two subregisters as compositions of their
|
||||
// associated actions.
|
||||
auto compose = [&SubRegAction] (const CodeGenSubRegIndex *Sub1,
|
||||
const CodeGenSubRegIndex *Sub2) {
|
||||
auto compose = [&SubRegAction](const CodeGenSubRegIndex *Sub1,
|
||||
const CodeGenSubRegIndex *Sub2) {
|
||||
RegMap C;
|
||||
const RegMap &Img1 = SubRegAction.at(Sub1);
|
||||
const RegMap &Img2 = SubRegAction.at(Sub2);
|
||||
for (std::pair<const CodeGenRegister*, const CodeGenRegister*> P : Img1) {
|
||||
for (std::pair<const CodeGenRegister *, const CodeGenRegister *> P : Img1) {
|
||||
auto F = Img2.find(P.second);
|
||||
if (F != Img2.end())
|
||||
C.insert({P.first, F->second});
|
||||
@@ -1447,13 +1458,13 @@ void CodeGenRegBank::computeComposites() {
|
||||
};
|
||||
|
||||
// Check if the two maps agree on the intersection of their domains.
|
||||
auto agree = [] (const RegMap &Map1, const RegMap &Map2) {
|
||||
auto agree = [](const RegMap &Map1, const RegMap &Map2) {
|
||||
// Technically speaking, an empty map agrees with any other map, but
|
||||
// this could flag false positives. We're interested in non-vacuous
|
||||
// agreements.
|
||||
if (Map1.empty() || Map2.empty())
|
||||
return false;
|
||||
for (std::pair<const CodeGenRegister*, const CodeGenRegister*> P : Map1) {
|
||||
for (std::pair<const CodeGenRegister *, const CodeGenRegister *> P : Map1) {
|
||||
auto F = Map2.find(P.first);
|
||||
if (F == Map2.end() || P.second != F->second)
|
||||
return false;
|
||||
@@ -1461,9 +1472,9 @@ void CodeGenRegBank::computeComposites() {
|
||||
return true;
|
||||
};
|
||||
|
||||
using CompositePair = std::pair<const CodeGenSubRegIndex*,
|
||||
const CodeGenSubRegIndex*>;
|
||||
SmallSet<CompositePair,4> UserDefined;
|
||||
using CompositePair =
|
||||
std::pair<const CodeGenSubRegIndex *, const CodeGenSubRegIndex *>;
|
||||
SmallSet<CompositePair, 4> UserDefined;
|
||||
for (const CodeGenSubRegIndex &Idx : SubRegIndices)
|
||||
for (auto P : Idx.getComposites())
|
||||
UserDefined.insert(std::make_pair(&Idx, P.first));
|
||||
@@ -1528,8 +1539,8 @@ void CodeGenRegBank::computeSubRegLaneMasks() {
|
||||
if (Idx.getComposites().empty()) {
|
||||
if (Bit > LaneBitmask::BitWidth) {
|
||||
PrintFatalError(
|
||||
Twine("Ran out of lanemask bits to represent subregister ")
|
||||
+ Idx.getName());
|
||||
Twine("Ran out of lanemask bits to represent subregister ") +
|
||||
Idx.getName());
|
||||
}
|
||||
Idx.LaneMask = LaneBitmask::getLane(Bit);
|
||||
++Bit;
|
||||
@@ -1556,7 +1567,7 @@ void CodeGenRegBank::computeSubRegLaneMasks() {
|
||||
unsigned DstBit = Idx.LaneMask.getHighestLane();
|
||||
assert(Idx.LaneMask == LaneBitmask::getLane(DstBit) &&
|
||||
"Must be a leaf subregister");
|
||||
MaskRolPair MaskRol = { LaneBitmask::getLane(0), (uint8_t)DstBit };
|
||||
MaskRolPair MaskRol = {LaneBitmask::getLane(0), (uint8_t)DstBit};
|
||||
LaneTransforms.push_back(MaskRol);
|
||||
} else {
|
||||
// Go through all leaf subregisters and find the ones that compose with
|
||||
@@ -1571,7 +1582,7 @@ void CodeGenRegBank::computeSubRegLaneMasks() {
|
||||
// Replicate the behaviour from the lane mask generation loop above.
|
||||
unsigned SrcBit = NextBit;
|
||||
LaneBitmask SrcMask = LaneBitmask::getLane(SrcBit);
|
||||
if (NextBit < LaneBitmask::BitWidth-1)
|
||||
if (NextBit < LaneBitmask::BitWidth - 1)
|
||||
++NextBit;
|
||||
assert(Idx2.LaneMask == SrcMask);
|
||||
|
||||
@@ -1586,8 +1597,8 @@ void CodeGenRegBank::computeSubRegLaneMasks() {
|
||||
// Create Mask+Rotate operation and merge with existing ops if possible.
|
||||
unsigned DstBit = Composite->LaneMask.getHighestLane();
|
||||
int Shift = DstBit - SrcBit;
|
||||
uint8_t RotateLeft = Shift >= 0 ? (uint8_t)Shift
|
||||
: LaneBitmask::BitWidth + Shift;
|
||||
uint8_t RotateLeft =
|
||||
Shift >= 0 ? (uint8_t)Shift : LaneBitmask::BitWidth + Shift;
|
||||
for (auto &I : LaneTransforms) {
|
||||
if (I.RotateLeft == RotateLeft) {
|
||||
I.Mask |= SrcMask;
|
||||
@@ -1595,7 +1606,7 @@ void CodeGenRegBank::computeSubRegLaneMasks() {
|
||||
}
|
||||
}
|
||||
if (SrcMask.any()) {
|
||||
MaskRolPair MaskRol = { SrcMask, RotateLeft };
|
||||
MaskRolPair MaskRol = {SrcMask, RotateLeft};
|
||||
LaneTransforms.push_back(MaskRol);
|
||||
}
|
||||
}
|
||||
@@ -1611,7 +1622,7 @@ void CodeGenRegBank::computeSubRegLaneMasks() {
|
||||
// in a sequence with 0 entries we can just pick any other. Choose
|
||||
// Mask 0xffffffff with Rotation 0.
|
||||
if (LaneTransforms.size() == 0) {
|
||||
MaskRolPair P = { LaneBitmask::getAll(), 0 };
|
||||
MaskRolPair P = {LaneBitmask::getAll(), 0};
|
||||
LaneTransforms.push_back(P);
|
||||
}
|
||||
}
|
||||
@@ -1679,7 +1690,7 @@ struct UberRegSet {
|
||||
//
|
||||
// UberRegSets[0] is a special non-allocatable set.
|
||||
static void computeUberSets(std::vector<UberRegSet> &UberSets,
|
||||
std::vector<UberRegSet*> &RegSets,
|
||||
std::vector<UberRegSet *> &RegSets,
|
||||
CodeGenRegBank &RegBank) {
|
||||
const auto &Registers = RegBank.getRegisters();
|
||||
|
||||
@@ -1742,7 +1753,8 @@ static void computeUberWeights(std::vector<UberRegSet> &UberSets,
|
||||
CodeGenRegBank &RegBank) {
|
||||
// Skip the first unallocatable set.
|
||||
for (std::vector<UberRegSet>::iterator I = std::next(UberSets.begin()),
|
||||
E = UberSets.end(); I != E; ++I) {
|
||||
E = UberSets.end();
|
||||
I != E; ++I) {
|
||||
|
||||
// Initialize all unit weights in this set, and remember the max units/reg.
|
||||
const CodeGenRegister *Reg = nullptr;
|
||||
@@ -1797,7 +1809,7 @@ static void computeUberWeights(std::vector<UberRegSet> &UberSets,
|
||||
// - induces recomputation of UberWeights.
|
||||
static bool normalizeWeight(CodeGenRegister *Reg,
|
||||
std::vector<UberRegSet> &UberSets,
|
||||
std::vector<UberRegSet*> &RegSets,
|
||||
std::vector<UberRegSet *> &RegSets,
|
||||
BitVector &NormalRegs,
|
||||
CodeGenRegister::RegUnitList &NormalUnits,
|
||||
CodeGenRegBank &RegBank) {
|
||||
@@ -1830,15 +1842,14 @@ static bool normalizeWeight(CodeGenRegister *Reg,
|
||||
// for this register, has not been used to normalize a subregister's set,
|
||||
// and has not already been used to singularly determine this UberRegSet.
|
||||
unsigned AdjustUnit = *Reg->getRegUnits().begin();
|
||||
if (Reg->getRegUnits().count() != 1
|
||||
|| hasRegUnit(NormalUnits, AdjustUnit)
|
||||
|| hasRegUnit(UberSet->SingularDeterminants, AdjustUnit)) {
|
||||
if (Reg->getRegUnits().count() != 1 ||
|
||||
hasRegUnit(NormalUnits, AdjustUnit) ||
|
||||
hasRegUnit(UberSet->SingularDeterminants, AdjustUnit)) {
|
||||
// We don't have an adjustable unit, so adopt a new one.
|
||||
AdjustUnit = RegBank.newRegUnit(UberSet->Weight - RegWeight);
|
||||
Reg->adoptRegUnit(AdjustUnit);
|
||||
// Adopting a unit does not immediately require recomputing set weights.
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Adjust the existing single unit.
|
||||
if (!RegBank.getRegUnit(AdjustUnit).Artificial)
|
||||
RegBank.increaseRegUnitWeight(AdjustUnit, UberSet->Weight - RegWeight);
|
||||
@@ -1860,7 +1871,7 @@ static bool normalizeWeight(CodeGenRegister *Reg,
|
||||
// where each register's weight is defined as sum of its units' weights.
|
||||
void CodeGenRegBank::computeRegUnitWeights() {
|
||||
std::vector<UberRegSet> UberSets;
|
||||
std::vector<UberRegSet*> RegSets(Registers.size());
|
||||
std::vector<UberRegSet *> RegSets(Registers.size());
|
||||
computeUberSets(UberSets, RegSets, *this);
|
||||
// UberSets and RegSets are now immutable.
|
||||
|
||||
@@ -1871,7 +1882,7 @@ void CodeGenRegBank::computeRegUnitWeights() {
|
||||
unsigned NumIters = 0;
|
||||
for (bool Changed = true; Changed; ++NumIters) {
|
||||
assert(NumIters <= NumNativeRegUnits && "Runaway register unit weights");
|
||||
(void) NumIters;
|
||||
(void)NumIters;
|
||||
Changed = false;
|
||||
for (auto &Reg : Registers) {
|
||||
CodeGenRegister::RegUnitList NormalUnits;
|
||||
@@ -1887,9 +1898,9 @@ void CodeGenRegBank::computeRegUnitWeights() {
|
||||
static std::vector<RegUnitSet>::const_iterator
|
||||
findRegUnitSet(const std::vector<RegUnitSet> &UniqueSets,
|
||||
const RegUnitSet &Set) {
|
||||
std::vector<RegUnitSet>::const_iterator
|
||||
I = UniqueSets.begin(), E = UniqueSets.end();
|
||||
for(;I != E; ++I) {
|
||||
std::vector<RegUnitSet>::const_iterator I = UniqueSets.begin(),
|
||||
E = UniqueSets.end();
|
||||
for (; I != E; ++I) {
|
||||
if (I->Units == Set.Units)
|
||||
break;
|
||||
}
|
||||
@@ -1899,8 +1910,8 @@ findRegUnitSet(const std::vector<RegUnitSet> &UniqueSets,
|
||||
// Return true if the RUSubSet is a subset of RUSuperSet.
|
||||
static bool isRegUnitSubSet(const std::vector<unsigned> &RUSubSet,
|
||||
const std::vector<unsigned> &RUSuperSet) {
|
||||
return std::includes(RUSuperSet.begin(), RUSuperSet.end(),
|
||||
RUSubSet.begin(), RUSubSet.end());
|
||||
return std::includes(RUSuperSet.begin(), RUSuperSet.end(), RUSubSet.begin(),
|
||||
RUSubSet.end());
|
||||
}
|
||||
|
||||
/// Iteratively prune unit sets. Prune subsets that are close to the superset,
|
||||
@@ -1925,8 +1936,8 @@ void CodeGenRegBank::pruneUnitSets() {
|
||||
|
||||
// Form an equivalence class of UnitSets with no significant difference.
|
||||
std::vector<unsigned> SuperSetIDs;
|
||||
for (unsigned SubIdx = 0, EndIdx = RegUnitSets.size();
|
||||
SubIdx != EndIdx; ++SubIdx) {
|
||||
for (unsigned SubIdx = 0, EndIdx = RegUnitSets.size(); SubIdx != EndIdx;
|
||||
++SubIdx) {
|
||||
const RegUnitSet &SubSet = RegUnitSets[SubIdx];
|
||||
unsigned SuperIdx = 0;
|
||||
for (; SuperIdx != EndIdx; ++SuperIdx) {
|
||||
@@ -1935,10 +1946,10 @@ void CodeGenRegBank::pruneUnitSets() {
|
||||
|
||||
unsigned UnitWeight = RegUnits[SubSet.Units[0]].Weight;
|
||||
const RegUnitSet &SuperSet = RegUnitSets[SuperIdx];
|
||||
if (isRegUnitSubSet(SubSet.Units, SuperSet.Units)
|
||||
&& (SubSet.Units.size() + 3 > SuperSet.Units.size())
|
||||
&& UnitWeight == RegUnits[SuperSet.Units[0]].Weight
|
||||
&& UnitWeight == RegUnits[SuperSet.Units.back()].Weight) {
|
||||
if (isRegUnitSubSet(SubSet.Units, SuperSet.Units) &&
|
||||
(SubSet.Units.size() + 3 > SuperSet.Units.size()) &&
|
||||
UnitWeight == RegUnits[SuperSet.Units[0]].Weight &&
|
||||
UnitWeight == RegUnits[SuperSet.Units.back()].Weight) {
|
||||
LLVM_DEBUG(dbgs() << "UnitSet " << SubIdx << " subsumed by " << SuperIdx
|
||||
<< "\n");
|
||||
// We can pick any of the set names for the merged set. Go for the
|
||||
@@ -1988,7 +1999,7 @@ void CodeGenRegBank::computeRegUnitSets() {
|
||||
|
||||
// Find an existing RegUnitSet.
|
||||
std::vector<RegUnitSet>::const_iterator SetI =
|
||||
findRegUnitSet(RegUnitSets, RegUnitSets.back());
|
||||
findRegUnitSet(RegUnitSets, RegUnitSets.back());
|
||||
if (SetI != std::prev(RegUnitSets.end()))
|
||||
RegUnitSets.pop_back();
|
||||
}
|
||||
@@ -2023,10 +2034,10 @@ void CodeGenRegBank::computeRegUnitSets() {
|
||||
// In theory, this is combinatorial. In practice, it needs to be bounded
|
||||
// by a small number of sets for regpressure to be efficient.
|
||||
// If the assert is hit, we need to implement pruning.
|
||||
assert(Idx < (2*NumRegUnitSubSets) && "runaway unit set inference");
|
||||
assert(Idx < (2 * NumRegUnitSubSets) && "runaway unit set inference");
|
||||
|
||||
// Compare new sets with all original classes.
|
||||
for (unsigned SearchIdx = (Idx >= NumRegUnitSubSets) ? 0 : Idx+1;
|
||||
for (unsigned SearchIdx = (Idx >= NumRegUnitSubSets) ? 0 : Idx + 1;
|
||||
SearchIdx != EndIdx; ++SearchIdx) {
|
||||
std::set<unsigned> Intersection;
|
||||
std::set_intersection(RegUnitSets[Idx].Units.begin(),
|
||||
@@ -2040,7 +2051,7 @@ void CodeGenRegBank::computeRegUnitSets() {
|
||||
// Speculatively grow the RegUnitSets to hold the new set.
|
||||
RegUnitSets.resize(RegUnitSets.size() + 1);
|
||||
RegUnitSets.back().Name =
|
||||
RegUnitSets[Idx].Name + "_with_" + RegUnitSets[SearchIdx].Name;
|
||||
RegUnitSets[Idx].Name + "_with_" + RegUnitSets[SearchIdx].Name;
|
||||
|
||||
std::set_union(RegUnitSets[Idx].Units.begin(),
|
||||
RegUnitSets[Idx].Units.end(),
|
||||
@@ -2051,7 +2062,7 @@ void CodeGenRegBank::computeRegUnitSets() {
|
||||
|
||||
// Find an existing RegUnitSet, or add the union to the unique sets.
|
||||
std::vector<RegUnitSet>::const_iterator SetI =
|
||||
findRegUnitSet(RegUnitSets, RegUnitSets.back());
|
||||
findRegUnitSet(RegUnitSets, RegUnitSets.back());
|
||||
if (SetI != std::prev(RegUnitSets.end()))
|
||||
RegUnitSets.pop_back();
|
||||
else {
|
||||
@@ -2098,8 +2109,8 @@ void CodeGenRegBank::computeRegUnitSets() {
|
||||
dbgs() << "\n UnitSetIDs:");
|
||||
|
||||
// Find all supersets.
|
||||
for (unsigned USIdx = 0, USEnd = RegUnitSets.size();
|
||||
USIdx != USEnd; ++USIdx) {
|
||||
for (unsigned USIdx = 0, USEnd = RegUnitSets.size(); USIdx != USEnd;
|
||||
++USIdx) {
|
||||
if (isRegUnitSubSet(RCRegUnits, RegUnitSets[USIdx].Units)) {
|
||||
LLVM_DEBUG(dbgs() << " " << USIdx);
|
||||
RegClassUnitSets[RCIdx].push_back(USIdx);
|
||||
@@ -2114,8 +2125,8 @@ void CodeGenRegBank::computeRegUnitSets() {
|
||||
// contain the unit. Normally, this matches an existing list of UnitSets for a
|
||||
// register class. If not, we create a new entry in RegClassUnitSets as a
|
||||
// "fake" register class.
|
||||
for (unsigned UnitIdx = 0, UnitEnd = NumNativeRegUnits;
|
||||
UnitIdx < UnitEnd; ++UnitIdx) {
|
||||
for (unsigned UnitIdx = 0, UnitEnd = NumNativeRegUnits; UnitIdx < UnitEnd;
|
||||
++UnitIdx) {
|
||||
std::vector<unsigned> RUSets;
|
||||
for (unsigned i = 0, e = RegUnitSets.size(); i != e; ++i) {
|
||||
RegUnitSet &RUSet = RegUnitSets[i];
|
||||
@@ -2124,8 +2135,8 @@ void CodeGenRegBank::computeRegUnitSets() {
|
||||
RUSets.push_back(i);
|
||||
}
|
||||
unsigned RCUnitSetsIdx = 0;
|
||||
for (unsigned e = RegClassUnitSets.size();
|
||||
RCUnitSetsIdx != e; ++RCUnitSetsIdx) {
|
||||
for (unsigned e = RegClassUnitSets.size(); RCUnitSetsIdx != e;
|
||||
++RCUnitSetsIdx) {
|
||||
if (RegClassUnitSets[RCUnitSetsIdx] == RUSets) {
|
||||
break;
|
||||
}
|
||||
@@ -2301,9 +2312,8 @@ void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) {
|
||||
continue;
|
||||
}
|
||||
// This is a real subset. See if we have a matching class.
|
||||
CodeGenRegisterClass *SubRC =
|
||||
getOrCreateSubClass(RC, &I->second,
|
||||
RC->getName() + "_with_" + I->first->getName());
|
||||
CodeGenRegisterClass *SubRC = getOrCreateSubClass(
|
||||
RC, &I->second, RC->getName() + "_with_" + I->first->getName());
|
||||
RC->setSubClassWithSubReg(&SubIdx, SubRC);
|
||||
}
|
||||
}
|
||||
@@ -2315,8 +2325,9 @@ void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) {
|
||||
// has a maximal result for any SubIdx and any X >= FirstSubRegRC.
|
||||
//
|
||||
|
||||
void CodeGenRegBank::inferMatchingSuperRegClass(CodeGenRegisterClass *RC,
|
||||
std::list<CodeGenRegisterClass>::iterator FirstSubRegRC) {
|
||||
void CodeGenRegBank::inferMatchingSuperRegClass(
|
||||
CodeGenRegisterClass *RC,
|
||||
std::list<CodeGenRegisterClass>::iterator FirstSubRegRC) {
|
||||
DenseMap<const CodeGenRegister *, std::vector<const CodeGenRegister *>>
|
||||
SubToSuperRegs;
|
||||
BitVector TopoSigs(getNumTopoSigs());
|
||||
@@ -2374,9 +2385,9 @@ void CodeGenRegBank::inferMatchingSuperRegClass(CodeGenRegisterClass *RC,
|
||||
|
||||
// Only a subset of RC maps into SubRC. Make sure it is represented by a
|
||||
// class.
|
||||
getOrCreateSubClass(RC, &SubSetVec, RC->getName() + "_with_" +
|
||||
SubIdx.getName() + "_in_" +
|
||||
SubRC.getName());
|
||||
getOrCreateSubClass(RC, &SubSetVec,
|
||||
RC->getName() + "_with_" + SubIdx.getName() + "_in_" +
|
||||
SubRC.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2431,8 +2442,7 @@ void CodeGenRegBank::computeInferredRegisterClasses() {
|
||||
/// return null. If the register is in multiple classes, and the classes have a
|
||||
/// superset-subset relationship and the same set of types, return the
|
||||
/// superclass. Otherwise return null.
|
||||
const CodeGenRegisterClass*
|
||||
CodeGenRegBank::getRegClassForRegister(Record *R) {
|
||||
const CodeGenRegisterClass *CodeGenRegBank::getRegClassForRegister(Record *R) {
|
||||
const CodeGenRegister *Reg = getReg(R);
|
||||
const CodeGenRegisterClass *FoundRC = nullptr;
|
||||
for (const auto &RC : getRegClasses()) {
|
||||
@@ -2477,8 +2487,8 @@ CodeGenRegBank::getMinimalPhysRegClass(Record *RegRecord,
|
||||
const CodeGenRegister *Reg = getReg(RegRecord);
|
||||
const CodeGenRegisterClass *BestRC = nullptr;
|
||||
for (const auto &RC : getRegClasses()) {
|
||||
if ((!VT || RC.hasType(*VT)) &&
|
||||
RC.contains(Reg) && (!BestRC || BestRC->hasSubClass(&RC)))
|
||||
if ((!VT || RC.hasType(*VT)) && RC.contains(Reg) &&
|
||||
(!BestRC || BestRC->hasSubClass(&RC)))
|
||||
BestRC = &RC;
|
||||
}
|
||||
|
||||
@@ -2486,8 +2496,8 @@ CodeGenRegBank::getMinimalPhysRegClass(Record *RegRecord,
|
||||
return BestRC;
|
||||
}
|
||||
|
||||
BitVector CodeGenRegBank::computeCoveredRegisters(ArrayRef<Record*> Regs) {
|
||||
SetVector<const CodeGenRegister*> Set;
|
||||
BitVector CodeGenRegBank::computeCoveredRegisters(ArrayRef<Record *> Regs) {
|
||||
SetVector<const CodeGenRegister *> Set;
|
||||
|
||||
// First add Regs with all sub-registers.
|
||||
for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -51,7 +51,7 @@ struct InstrsOp : public SetTheory::Operator {
|
||||
// (instregex "OpcPat",...) Find all instructions matching an opcode pattern.
|
||||
struct InstRegexOp : public SetTheory::Operator {
|
||||
const CodeGenTarget &Target;
|
||||
InstRegexOp(const CodeGenTarget &t): Target(t) {}
|
||||
InstRegexOp(const CodeGenTarget &t) : Target(t) {}
|
||||
|
||||
/// Remove any text inside of parentheses from S.
|
||||
static std::string removeParens(llvm::StringRef S) {
|
||||
@@ -182,8 +182,8 @@ struct InstRegexOp : public SetTheory::Operator {
|
||||
|
||||
/// CodeGenModels ctor interprets machine model records and populates maps.
|
||||
CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
|
||||
const CodeGenTarget &TGT):
|
||||
Records(RK), Target(TGT) {
|
||||
const CodeGenTarget &TGT)
|
||||
: Records(RK), Target(TGT) {
|
||||
|
||||
Sets.addFieldExpander("InstRW", "Instrs");
|
||||
|
||||
@@ -298,9 +298,8 @@ static APInt constructOperandMask(ArrayRef<int64_t> Indices) {
|
||||
return OperandMask;
|
||||
}
|
||||
|
||||
static void
|
||||
processSTIPredicate(STIPredicateFunction &Fn,
|
||||
const ProcModelMapTy &ProcModelMap) {
|
||||
static void processSTIPredicate(STIPredicateFunction &Fn,
|
||||
const ProcModelMapTy &ProcModelMap) {
|
||||
DenseMap<const Record *, unsigned> Opcode2Index;
|
||||
using OpcodeMapPair = std::pair<const Record *, OpcodeInfo>;
|
||||
std::vector<OpcodeMapPair> OpcodeMappings;
|
||||
@@ -380,30 +379,29 @@ processSTIPredicate(STIPredicateFunction &Fn,
|
||||
|
||||
// Sort OpcodeMappings elements based on their CPU and predicate masks.
|
||||
// As a last resort, order elements by opcode identifier.
|
||||
llvm::sort(OpcodeMappings,
|
||||
[&](const OpcodeMapPair &Lhs, const OpcodeMapPair &Rhs) {
|
||||
unsigned LhsIdx = Opcode2Index[Lhs.first];
|
||||
unsigned RhsIdx = Opcode2Index[Rhs.first];
|
||||
const std::pair<APInt, APInt> &LhsMasks = OpcodeMasks[LhsIdx];
|
||||
const std::pair<APInt, APInt> &RhsMasks = OpcodeMasks[RhsIdx];
|
||||
llvm::sort(
|
||||
OpcodeMappings, [&](const OpcodeMapPair &Lhs, const OpcodeMapPair &Rhs) {
|
||||
unsigned LhsIdx = Opcode2Index[Lhs.first];
|
||||
unsigned RhsIdx = Opcode2Index[Rhs.first];
|
||||
const std::pair<APInt, APInt> &LhsMasks = OpcodeMasks[LhsIdx];
|
||||
const std::pair<APInt, APInt> &RhsMasks = OpcodeMasks[RhsIdx];
|
||||
|
||||
auto PopulationCountAndLeftBit =
|
||||
[](const APInt &Other) -> std::pair<int, int> {
|
||||
return std::pair<int, int>(Other.popcount(),
|
||||
-Other.countl_zero());
|
||||
};
|
||||
auto lhsmask_first = PopulationCountAndLeftBit(LhsMasks.first);
|
||||
auto rhsmask_first = PopulationCountAndLeftBit(RhsMasks.first);
|
||||
if (lhsmask_first != rhsmask_first)
|
||||
return lhsmask_first < rhsmask_first;
|
||||
auto PopulationCountAndLeftBit =
|
||||
[](const APInt &Other) -> std::pair<int, int> {
|
||||
return std::pair<int, int>(Other.popcount(), -Other.countl_zero());
|
||||
};
|
||||
auto lhsmask_first = PopulationCountAndLeftBit(LhsMasks.first);
|
||||
auto rhsmask_first = PopulationCountAndLeftBit(RhsMasks.first);
|
||||
if (lhsmask_first != rhsmask_first)
|
||||
return lhsmask_first < rhsmask_first;
|
||||
|
||||
auto lhsmask_second = PopulationCountAndLeftBit(LhsMasks.second);
|
||||
auto rhsmask_second = PopulationCountAndLeftBit(RhsMasks.second);
|
||||
if (lhsmask_second != rhsmask_second)
|
||||
return lhsmask_second < rhsmask_second;
|
||||
auto lhsmask_second = PopulationCountAndLeftBit(LhsMasks.second);
|
||||
auto rhsmask_second = PopulationCountAndLeftBit(RhsMasks.second);
|
||||
if (lhsmask_second != rhsmask_second)
|
||||
return lhsmask_second < rhsmask_second;
|
||||
|
||||
return LhsIdx < RhsIdx;
|
||||
});
|
||||
return LhsIdx < RhsIdx;
|
||||
});
|
||||
|
||||
// Now construct opcode groups. Groups are used by the SubtargetEmitter when
|
||||
// expanding the body of a STIPredicate function. In particular, each opcode
|
||||
@@ -498,8 +496,7 @@ void CodeGenSchedModels::collectLoadStoreQueueInfo() {
|
||||
CodeGenProcModel &PM = getProcModel(Queue->getValueAsDef("SchedModel"));
|
||||
if (Queue->isSubClassOf("LoadQueue")) {
|
||||
if (PM.LoadQueue) {
|
||||
PrintError(Queue->getLoc(),
|
||||
"Expected a single LoadQueue definition");
|
||||
PrintError(Queue->getLoc(), "Expected a single LoadQueue definition");
|
||||
PrintNote(PM.LoadQueue->getLoc(),
|
||||
"Previous definition of LoadQueue was here");
|
||||
}
|
||||
@@ -509,8 +506,7 @@ void CodeGenSchedModels::collectLoadStoreQueueInfo() {
|
||||
|
||||
if (Queue->isSubClassOf("StoreQueue")) {
|
||||
if (PM.StoreQueue) {
|
||||
PrintError(Queue->getLoc(),
|
||||
"Expected a single StoreQueue definition");
|
||||
PrintError(Queue->getLoc(), "Expected a single StoreQueue definition");
|
||||
PrintNote(PM.StoreQueue->getLoc(),
|
||||
"Previous definition of StoreQueue was here");
|
||||
}
|
||||
@@ -542,14 +538,15 @@ void CodeGenSchedModels::collectProcModels() {
|
||||
// Check for duplicated names.
|
||||
auto I = std::adjacent_find(ProcRecords.begin(), ProcRecords.end(),
|
||||
[](const Record *Rec1, const Record *Rec2) {
|
||||
return Rec1->getValueAsString("Name") == Rec2->getValueAsString("Name");
|
||||
});
|
||||
return Rec1->getValueAsString("Name") ==
|
||||
Rec2->getValueAsString("Name");
|
||||
});
|
||||
if (I != ProcRecords.end())
|
||||
PrintFatalError((*I)->getLoc(), "Duplicate processor name " +
|
||||
(*I)->getValueAsString("Name"));
|
||||
(*I)->getValueAsString("Name"));
|
||||
|
||||
// Reserve space because we can. Reallocation would be ok.
|
||||
ProcModels.reserve(ProcRecords.size()+1);
|
||||
ProcModels.reserve(ProcRecords.size() + 1);
|
||||
|
||||
// Use idx=0 for NoModel/NoItineraries.
|
||||
Record *NoModelDef = Records.getDef("NoSchedModel");
|
||||
@@ -574,8 +571,7 @@ void CodeGenSchedModels::addProcModel(Record *ProcDef) {
|
||||
if (ModelKey->isSubClassOf("SchedMachineModel")) {
|
||||
Record *ItinsDef = ModelKey->getValueAsDef("Itineraries");
|
||||
ProcModels.emplace_back(ProcModels.size(), Name, ModelKey, ItinsDef);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// An itinerary is defined without a machine model. Infer a new model.
|
||||
if (!ModelKey->getValueAsListOfDefs("IID").empty())
|
||||
Name = Name + "Model";
|
||||
@@ -587,7 +583,7 @@ void CodeGenSchedModels::addProcModel(Record *ProcDef) {
|
||||
|
||||
// Recursively find all reachable SchedReadWrite records.
|
||||
static void scanSchedRW(Record *RWDef, RecVec &RWDefs,
|
||||
SmallPtrSet<Record*, 16> &RWSet) {
|
||||
SmallPtrSet<Record *, 16> &RWSet) {
|
||||
if (!RWSet.insert(RWDef).second)
|
||||
return;
|
||||
RWDefs.push_back(RWDef);
|
||||
@@ -596,8 +592,7 @@ static void scanSchedRW(Record *RWDef, RecVec &RWDefs,
|
||||
RecVec Seq = RWDef->getValueAsListOfDefs("Writes");
|
||||
for (Record *WSRec : Seq)
|
||||
scanSchedRW(WSRec, RWDefs, RWSet);
|
||||
}
|
||||
else if (RWDef->isSubClassOf("SchedVariant")) {
|
||||
} else if (RWDef->isSubClassOf("SchedVariant")) {
|
||||
// Visit each variant (guarded by a different predicate).
|
||||
RecVec Vars = RWDef->getValueAsListOfDefs("Variants");
|
||||
for (Record *Variant : Vars) {
|
||||
@@ -616,7 +611,7 @@ void CodeGenSchedModels::collectSchedRW() {
|
||||
SchedWrites.resize(1);
|
||||
SchedReads.resize(1);
|
||||
|
||||
SmallPtrSet<Record*, 16> RWSet;
|
||||
SmallPtrSet<Record *, 16> RWSet;
|
||||
|
||||
// Find all SchedReadWrites referenced by instruction defs.
|
||||
RecVec SWDefs, SRDefs;
|
||||
@@ -673,8 +668,7 @@ void CodeGenSchedModels::collectSchedRW() {
|
||||
if (!AliasDef->isSubClassOf("SchedWrite"))
|
||||
PrintFatalError(ADef->getLoc(), "SchedWrite Alias must be SchedWrite");
|
||||
scanSchedRW(AliasDef, SWDefs, RWSet);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
assert(MatchDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
|
||||
if (!AliasDef->isSubClassOf("SchedRead"))
|
||||
PrintFatalError(ADef->getLoc(), "SchedRead Alias must be SchedRead");
|
||||
@@ -690,7 +684,7 @@ void CodeGenSchedModels::collectSchedRW() {
|
||||
}
|
||||
llvm::sort(SRDefs, LessRecord());
|
||||
for (Record *SRDef : SRDefs) {
|
||||
assert(!getSchedRWIdx(SRDef, /*IsRead-*/true) && "duplicate SchedWrite");
|
||||
assert(!getSchedRWIdx(SRDef, /*IsRead-*/ true) && "duplicate SchedWrite");
|
||||
SchedReads.emplace_back(SchedReads.size(), SRDef);
|
||||
}
|
||||
// Initialize WriteSequence vectors.
|
||||
@@ -753,9 +747,9 @@ unsigned CodeGenSchedModels::getSchedRWIdx(const Record *Def,
|
||||
}
|
||||
|
||||
bool CodeGenSchedModels::hasReadOfWrite(Record *WriteDef) const {
|
||||
for (auto& ProcModel : ProcModels) {
|
||||
for (auto &ProcModel : ProcModels) {
|
||||
const RecVec &RADefs = ProcModel.ReadAdvanceDefs;
|
||||
for (auto& RADef : RADefs) {
|
||||
for (auto &RADef : RADefs) {
|
||||
RecVec ValidWrites = RADef->getValueAsListOfDefs("ValidWrites");
|
||||
if (is_contained(ValidWrites, WriteDef))
|
||||
return true;
|
||||
@@ -764,8 +758,8 @@ bool CodeGenSchedModels::hasReadOfWrite(Record *WriteDef) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void splitSchedReadWrites(const RecVec &RWDefs,
|
||||
RecVec &WriteDefs, RecVec &ReadDefs) {
|
||||
static void splitSchedReadWrites(const RecVec &RWDefs, RecVec &WriteDefs,
|
||||
RecVec &ReadDefs) {
|
||||
for (Record *RWDef : RWDefs) {
|
||||
if (RWDef->isSubClassOf("SchedWrite"))
|
||||
WriteDefs.push_back(RWDef);
|
||||
@@ -777,8 +771,8 @@ static void splitSchedReadWrites(const RecVec &RWDefs,
|
||||
}
|
||||
|
||||
// Split the SchedReadWrites defs and call findRWs for each list.
|
||||
void CodeGenSchedModels::findRWs(const RecVec &RWDefs,
|
||||
IdxVec &Writes, IdxVec &Reads) const {
|
||||
void CodeGenSchedModels::findRWs(const RecVec &RWDefs, IdxVec &Writes,
|
||||
IdxVec &Reads) const {
|
||||
RecVec WriteDefs;
|
||||
RecVec ReadDefs;
|
||||
splitSchedReadWrites(RWDefs, WriteDefs, ReadDefs);
|
||||
@@ -803,8 +797,7 @@ void CodeGenSchedModels::expandRWSequence(unsigned RWIdx, IdxVec &RWSeq,
|
||||
RWSeq.push_back(RWIdx);
|
||||
return;
|
||||
}
|
||||
int Repeat =
|
||||
SchedRW.TheDef ? SchedRW.TheDef->getValueAsInt("Repeat") : 1;
|
||||
int Repeat = SchedRW.TheDef ? SchedRW.TheDef->getValueAsInt("Repeat") : 1;
|
||||
for (int i = 0; i < Repeat; ++i) {
|
||||
for (unsigned I : SchedRW.Sequence) {
|
||||
expandRWSequence(I, RWSeq, IsRead);
|
||||
@@ -815,8 +808,8 @@ void CodeGenSchedModels::expandRWSequence(unsigned RWIdx, IdxVec &RWSeq,
|
||||
// Expand a SchedWrite as a sequence following any aliases that coincide with
|
||||
// the given processor model.
|
||||
void CodeGenSchedModels::expandRWSeqForProc(
|
||||
unsigned RWIdx, IdxVec &RWSeq, bool IsRead,
|
||||
const CodeGenProcModel &ProcModel) const {
|
||||
unsigned RWIdx, IdxVec &RWSeq, bool IsRead,
|
||||
const CodeGenProcModel &ProcModel) const {
|
||||
|
||||
const CodeGenSchedRW &SchedWrite = getSchedRW(RWIdx, IsRead);
|
||||
Record *AliasDef = nullptr;
|
||||
@@ -828,14 +821,16 @@ void CodeGenSchedModels::expandRWSeqForProc(
|
||||
continue;
|
||||
}
|
||||
if (AliasDef)
|
||||
PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "
|
||||
"defined for processor " + ProcModel.ModelName +
|
||||
" Ensure only one SchedAlias exists per RW.");
|
||||
PrintFatalError(AliasRW.TheDef->getLoc(),
|
||||
"Multiple aliases "
|
||||
"defined for processor " +
|
||||
ProcModel.ModelName +
|
||||
" Ensure only one SchedAlias exists per RW.");
|
||||
AliasDef = AliasRW.TheDef;
|
||||
}
|
||||
if (AliasDef) {
|
||||
expandRWSeqForProc(getSchedRWIdx(AliasDef, IsRead),
|
||||
RWSeq, IsRead,ProcModel);
|
||||
expandRWSeqForProc(getSchedRWIdx(AliasDef, IsRead), RWSeq, IsRead,
|
||||
ProcModel);
|
||||
return;
|
||||
}
|
||||
if (!SchedWrite.IsSequence) {
|
||||
@@ -843,7 +838,7 @@ void CodeGenSchedModels::expandRWSeqForProc(
|
||||
return;
|
||||
}
|
||||
int Repeat =
|
||||
SchedWrite.TheDef ? SchedWrite.TheDef->getValueAsInt("Repeat") : 1;
|
||||
SchedWrite.TheDef ? SchedWrite.TheDef->getValueAsInt("Repeat") : 1;
|
||||
for (int I = 0, E = Repeat; I < E; ++I) {
|
||||
for (unsigned Idx : SchedWrite.Sequence) {
|
||||
expandRWSeqForProc(Idx, RWSeq, IsRead, ProcModel);
|
||||
@@ -888,8 +883,7 @@ void CodeGenSchedModels::collectSchedClasses() {
|
||||
|
||||
// NoItinerary is always the first class at Idx=0
|
||||
assert(SchedClasses.empty() && "Expected empty sched class");
|
||||
SchedClasses.emplace_back(0, "NoInstrModel",
|
||||
Records.getDef("NoItinerary"));
|
||||
SchedClasses.emplace_back(0, "NoInstrModel", Records.getDef("NoItinerary"));
|
||||
SchedClasses.back().ProcIndices.push_back(0);
|
||||
|
||||
// Create a SchedClass for each unique combination of itinerary class and
|
||||
@@ -901,7 +895,7 @@ void CodeGenSchedModels::collectSchedClasses() {
|
||||
findRWs(Inst->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads);
|
||||
|
||||
// ProcIdx == 0 indicates the class applies to all processors.
|
||||
unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, /*ProcIndices*/{0});
|
||||
unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, /*ProcIndices*/ {0});
|
||||
InstrClassMap[Inst->TheDef] = SCIdx;
|
||||
}
|
||||
// Create classes for InstRW defs.
|
||||
@@ -933,7 +927,8 @@ void CodeGenSchedModels::collectSchedClasses() {
|
||||
}
|
||||
CodeGenSchedClass &SC = getSchedClass(SCIdx);
|
||||
if (SC.ProcIndices[0] != 0)
|
||||
PrintFatalError(Inst->TheDef->getLoc(), "Instruction's sched class "
|
||||
PrintFatalError(Inst->TheDef->getLoc(),
|
||||
"Instruction's sched class "
|
||||
"must not be subtarget specific.");
|
||||
|
||||
IdxVec ProcIndices;
|
||||
@@ -962,8 +957,7 @@ void CodeGenSchedModels::collectSchedClasses() {
|
||||
<< InstName);
|
||||
IdxVec Writes;
|
||||
IdxVec Reads;
|
||||
findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"),
|
||||
Writes, Reads);
|
||||
findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
|
||||
LLVM_DEBUG({
|
||||
for (unsigned WIdx : Writes)
|
||||
dbgs() << " " << SchedWrites[WIdx].Name;
|
||||
@@ -1032,25 +1026,23 @@ unsigned CodeGenSchedModels::addSchedClass(Record *ItinClassDef,
|
||||
assert(!ProcIndices.empty() && "expect at least one ProcIdx");
|
||||
|
||||
auto IsKeyEqual = [=](const CodeGenSchedClass &SC) {
|
||||
return SC.isKeyEqual(ItinClassDef, OperWrites, OperReads);
|
||||
};
|
||||
return SC.isKeyEqual(ItinClassDef, OperWrites, OperReads);
|
||||
};
|
||||
|
||||
auto I = find_if(make_range(schedClassBegin(), schedClassEnd()), IsKeyEqual);
|
||||
unsigned Idx = I == schedClassEnd() ? 0 : std::distance(schedClassBegin(), I);
|
||||
if (Idx || SchedClasses[0].isKeyEqual(ItinClassDef, OperWrites, OperReads)) {
|
||||
IdxVec PI;
|
||||
std::set_union(SchedClasses[Idx].ProcIndices.begin(),
|
||||
SchedClasses[Idx].ProcIndices.end(),
|
||||
ProcIndices.begin(), ProcIndices.end(),
|
||||
std::back_inserter(PI));
|
||||
SchedClasses[Idx].ProcIndices.end(), ProcIndices.begin(),
|
||||
ProcIndices.end(), std::back_inserter(PI));
|
||||
SchedClasses[Idx].ProcIndices = std::move(PI);
|
||||
return Idx;
|
||||
}
|
||||
Idx = SchedClasses.size();
|
||||
SchedClasses.emplace_back(Idx,
|
||||
createSchedClassName(ItinClassDef, OperWrites,
|
||||
OperReads),
|
||||
ItinClassDef);
|
||||
SchedClasses.emplace_back(
|
||||
Idx, createSchedClassName(ItinClassDef, OperWrites, OperReads),
|
||||
ItinClassDef);
|
||||
CodeGenSchedClass &SC = SchedClasses.back();
|
||||
SC.Writes = OperWrites;
|
||||
SC.Reads = OperReads;
|
||||
@@ -1083,17 +1075,16 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
|
||||
// the Instrs to it.
|
||||
for (auto &Entry : ClassInstrs) {
|
||||
unsigned OldSCIdx = Entry.first;
|
||||
ArrayRef<Record*> InstDefs = Entry.second;
|
||||
ArrayRef<Record *> InstDefs = Entry.second;
|
||||
// If the all instrs in the current class are accounted for, then leave
|
||||
// them mapped to their old class.
|
||||
if (OldSCIdx) {
|
||||
const RecVec &RWDefs = SchedClasses[OldSCIdx].InstRWs;
|
||||
if (!RWDefs.empty()) {
|
||||
const RecVec *OrigInstDefs = Sets.expand(RWDefs[0]);
|
||||
unsigned OrigNumInstrs =
|
||||
count_if(*OrigInstDefs, [&](Record *OIDef) {
|
||||
return InstrClassMap[OIDef] == OldSCIdx;
|
||||
});
|
||||
unsigned OrigNumInstrs = count_if(*OrigInstDefs, [&](Record *OIDef) {
|
||||
return InstrClassMap[OIDef] == OldSCIdx;
|
||||
});
|
||||
if (OrigNumInstrs == InstDefs.size()) {
|
||||
assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 &&
|
||||
"expected a generic SchedClass");
|
||||
@@ -1148,8 +1139,7 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
|
||||
"\".");
|
||||
PrintFatalNote(OldRWDef->getLoc(), "Previous match was here.");
|
||||
}
|
||||
assert(OldRWDef != InstRWDef &&
|
||||
"SchedClass has duplicate InstRW def");
|
||||
assert(OldRWDef != InstRWDef && "SchedClass has duplicate InstRW def");
|
||||
SC.InstRWs.push_back(OldRWDef);
|
||||
}
|
||||
}
|
||||
@@ -1162,7 +1152,8 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
|
||||
|
||||
// True if collectProcItins found anything.
|
||||
bool CodeGenSchedModels::hasItineraries() const {
|
||||
for (const CodeGenProcModel &PM : make_range(procModelBegin(),procModelEnd()))
|
||||
for (const CodeGenProcModel &PM :
|
||||
make_range(procModelBegin(), procModelEnd()))
|
||||
if (PM.hasItineraries())
|
||||
return true;
|
||||
return false;
|
||||
@@ -1217,14 +1208,14 @@ void CodeGenSchedModels::collectProcItins() {
|
||||
void CodeGenSchedModels::collectProcItinRW() {
|
||||
RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW");
|
||||
llvm::sort(ItinRWDefs, LessRecord());
|
||||
for (Record *RWDef : ItinRWDefs) {
|
||||
for (Record *RWDef : ItinRWDefs) {
|
||||
if (!RWDef->getValueInit("SchedModel")->isComplete())
|
||||
PrintFatalError(RWDef->getLoc(), "SchedModel is undefined");
|
||||
Record *ModelDef = RWDef->getValueAsDef("SchedModel");
|
||||
ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef);
|
||||
if (I == ProcModelMap.end()) {
|
||||
PrintFatalError(RWDef->getLoc(), "Undefined SchedMachineModel "
|
||||
+ ModelDef->getName());
|
||||
PrintFatalError(RWDef->getLoc(),
|
||||
"Undefined SchedMachineModel " + ModelDef->getName());
|
||||
}
|
||||
ProcModels[I->second].ItinRWDefs.push_back(RWDef);
|
||||
}
|
||||
@@ -1254,10 +1245,10 @@ void CodeGenSchedModels::inferSchedClasses() {
|
||||
if (!SchedClasses[Idx].InstRWs.empty())
|
||||
inferFromInstRWs(Idx);
|
||||
if (!SchedClasses[Idx].Writes.empty()) {
|
||||
inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads,
|
||||
Idx, SchedClasses[Idx].ProcIndices);
|
||||
inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads, Idx,
|
||||
SchedClasses[Idx].ProcIndices);
|
||||
}
|
||||
assert(SchedClasses.size() < (NumInstrSchedClasses*6) &&
|
||||
assert(SchedClasses.size() < (NumInstrSchedClasses * 6) &&
|
||||
"too many SchedVariants");
|
||||
}
|
||||
}
|
||||
@@ -1274,9 +1265,9 @@ void CodeGenSchedModels::inferFromItinClass(Record *ItinClassDef,
|
||||
if (!llvm::is_contained(Matched, ItinClassDef))
|
||||
continue;
|
||||
if (HasMatch)
|
||||
PrintFatalError(Rec->getLoc(), "Duplicate itinerary class "
|
||||
+ ItinClassDef->getName()
|
||||
+ " in ItinResources for " + PM.ModelName);
|
||||
PrintFatalError(Rec->getLoc(),
|
||||
"Duplicate itinerary class " + ItinClassDef->getName() +
|
||||
" in ItinResources for " + PM.ModelName);
|
||||
HasMatch = true;
|
||||
IdxVec Writes, Reads;
|
||||
findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
|
||||
@@ -1317,8 +1308,8 @@ struct TransVariant {
|
||||
unsigned ProcIdx; // Processor model index or zero for any.
|
||||
unsigned TransVecIdx; // Index into PredTransitions::TransVec.
|
||||
|
||||
TransVariant(Record *def, unsigned rwi, unsigned pi, unsigned ti):
|
||||
VarOrSeqDef(def), RWIdx(rwi), ProcIdx(pi), TransVecIdx(ti) {}
|
||||
TransVariant(Record *def, unsigned rwi, unsigned pi, unsigned ti)
|
||||
: VarOrSeqDef(def), RWIdx(rwi), ProcIdx(pi), TransVecIdx(ti) {}
|
||||
};
|
||||
|
||||
// Associate a predicate with the SchedReadWrite that it guards.
|
||||
@@ -1328,15 +1319,16 @@ struct PredCheck {
|
||||
unsigned RWIdx;
|
||||
Record *Predicate;
|
||||
|
||||
PredCheck(bool r, unsigned w, Record *p): IsRead(r), RWIdx(w), Predicate(p) {}
|
||||
PredCheck(bool r, unsigned w, Record *p)
|
||||
: IsRead(r), RWIdx(w), Predicate(p) {}
|
||||
};
|
||||
|
||||
// A Predicate transition is a list of RW sequences guarded by a PredTerm.
|
||||
struct PredTransition {
|
||||
// A predicate term is a conjunction of PredChecks.
|
||||
SmallVector<PredCheck, 4> PredTerm;
|
||||
SmallVector<SmallVector<unsigned,4>, 16> WriteSequences;
|
||||
SmallVector<SmallVector<unsigned,4>, 16> ReadSequences;
|
||||
SmallVector<SmallVector<unsigned, 4>, 16> WriteSequences;
|
||||
SmallVector<SmallVector<unsigned, 4>, 16> ReadSequences;
|
||||
unsigned ProcIndex = 0;
|
||||
|
||||
PredTransition() = default;
|
||||
@@ -1354,7 +1346,7 @@ class PredTransitions {
|
||||
public:
|
||||
std::vector<PredTransition> TransVec;
|
||||
|
||||
PredTransitions(CodeGenSchedModels &sm): SchedModels(sm) {}
|
||||
PredTransitions(CodeGenSchedModels &sm) : SchedModels(sm) {}
|
||||
|
||||
bool substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq,
|
||||
bool IsRead, unsigned StartIdx);
|
||||
@@ -1368,9 +1360,8 @@ public:
|
||||
private:
|
||||
bool mutuallyExclusive(Record *PredDef, ArrayRef<Record *> Preds,
|
||||
ArrayRef<PredCheck> Term);
|
||||
void getIntersectingVariants(
|
||||
const CodeGenSchedRW &SchedRW, unsigned TransIdx,
|
||||
std::vector<TransVariant> &IntersectingVariants);
|
||||
void getIntersectingVariants(const CodeGenSchedRW &SchedRW, unsigned TransIdx,
|
||||
std::vector<TransVariant> &IntersectingVariants);
|
||||
void pushVariant(const TransVariant &VInfo, bool IsRead);
|
||||
};
|
||||
|
||||
@@ -1388,7 +1379,7 @@ private:
|
||||
bool PredTransitions::mutuallyExclusive(Record *PredDef,
|
||||
ArrayRef<Record *> Preds,
|
||||
ArrayRef<PredCheck> Term) {
|
||||
for (const PredCheck &PC: Term) {
|
||||
for (const PredCheck &PC : Term) {
|
||||
if (PC.Predicate == PredDef)
|
||||
return false;
|
||||
|
||||
@@ -1446,8 +1437,8 @@ static std::vector<Record *> getAllPredicates(ArrayRef<TransVariant> Variants,
|
||||
// given SchedRW whose processor indices and predicates are not mutually
|
||||
// exclusive with the given transition.
|
||||
void PredTransitions::getIntersectingVariants(
|
||||
const CodeGenSchedRW &SchedRW, unsigned TransIdx,
|
||||
std::vector<TransVariant> &IntersectingVariants) {
|
||||
const CodeGenSchedRW &SchedRW, unsigned TransIdx,
|
||||
std::vector<TransVariant> &IntersectingVariants) {
|
||||
|
||||
bool GenericRW = false;
|
||||
|
||||
@@ -1489,7 +1480,7 @@ void PredTransitions::getIntersectingVariants(
|
||||
}
|
||||
|
||||
const CodeGenSchedRW &AliasRW =
|
||||
SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));
|
||||
SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));
|
||||
|
||||
if (AliasRW.HasVariants) {
|
||||
const RecVec VarDefs = AliasRW.TheDef->getValueAsListOfDefs("Variants");
|
||||
@@ -1516,8 +1507,7 @@ void PredTransitions::getIntersectingVariants(
|
||||
// The first variant builds on the existing transition.
|
||||
Variant.TransVecIdx = TransIdx;
|
||||
IntersectingVariants.push_back(Variant);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Push another copy of the current transition for more variants.
|
||||
Variant.TransVecIdx = TransVec.size();
|
||||
IntersectingVariants.push_back(Variant);
|
||||
@@ -1525,15 +1515,15 @@ void PredTransitions::getIntersectingVariants(
|
||||
}
|
||||
}
|
||||
if (GenericRW && IntersectingVariants.empty()) {
|
||||
PrintFatalError(SchedRW.TheDef->getLoc(), "No variant of this type has "
|
||||
PrintFatalError(SchedRW.TheDef->getLoc(),
|
||||
"No variant of this type has "
|
||||
"a matching predicate on any processor");
|
||||
}
|
||||
}
|
||||
|
||||
// Push the Reads/Writes selected by this variant onto the PredTransition
|
||||
// specified by VInfo.
|
||||
void PredTransitions::
|
||||
pushVariant(const TransVariant &VInfo, bool IsRead) {
|
||||
void PredTransitions::pushVariant(const TransVariant &VInfo, bool IsRead) {
|
||||
PredTransition &Trans = TransVec[VInfo.TransVecIdx];
|
||||
|
||||
// If this operand transition is reached through a processor-specific alias,
|
||||
@@ -1541,11 +1531,10 @@ pushVariant(const TransVariant &VInfo, bool IsRead) {
|
||||
IdxVec SelectedRWs;
|
||||
if (VInfo.VarOrSeqDef->isSubClassOf("SchedVar")) {
|
||||
Record *PredDef = VInfo.VarOrSeqDef->getValueAsDef("Predicate");
|
||||
Trans.PredTerm.emplace_back(IsRead, VInfo.RWIdx,PredDef);
|
||||
Trans.PredTerm.emplace_back(IsRead, VInfo.RWIdx, PredDef);
|
||||
RecVec SelectedDefs = VInfo.VarOrSeqDef->getValueAsListOfDefs("Selected");
|
||||
SchedModels.findRWs(SelectedDefs, SelectedRWs, IsRead);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
assert(VInfo.VarOrSeqDef->isSubClassOf("WriteSequence") &&
|
||||
"variant must be a SchedVariant or aliased WriteSequence");
|
||||
SelectedRWs.push_back(SchedModels.getSchedRWIdx(VInfo.VarOrSeqDef, IsRead));
|
||||
@@ -1553,10 +1542,10 @@ pushVariant(const TransVariant &VInfo, bool IsRead) {
|
||||
|
||||
const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(VInfo.RWIdx, IsRead);
|
||||
|
||||
SmallVectorImpl<SmallVector<unsigned,4>> &RWSequences = IsRead
|
||||
? Trans.ReadSequences : Trans.WriteSequences;
|
||||
SmallVectorImpl<SmallVector<unsigned, 4>> &RWSequences =
|
||||
IsRead ? Trans.ReadSequences : Trans.WriteSequences;
|
||||
if (SchedRW.IsVariadic) {
|
||||
unsigned OperIdx = RWSequences.size()-1;
|
||||
unsigned OperIdx = RWSequences.size() - 1;
|
||||
// Make N-1 copies of this transition's last sequence.
|
||||
RWSequences.reserve(RWSequences.size() + SelectedRWs.size() - 1);
|
||||
RWSequences.insert(RWSequences.end(), SelectedRWs.size() - 1,
|
||||
@@ -1565,8 +1554,8 @@ pushVariant(const TransVariant &VInfo, bool IsRead) {
|
||||
// sequence (split the current operand into N operands).
|
||||
// Note that write sequences should be expanded within this loop--the entire
|
||||
// sequence belongs to a single operand.
|
||||
for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end();
|
||||
RWI != RWE; ++RWI, ++OperIdx) {
|
||||
for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end(); RWI != RWE;
|
||||
++RWI, ++OperIdx) {
|
||||
IdxVec ExpandedRWs;
|
||||
if (IsRead)
|
||||
ExpandedRWs.push_back(*RWI);
|
||||
@@ -1575,8 +1564,7 @@ pushVariant(const TransVariant &VInfo, bool IsRead) {
|
||||
llvm::append_range(RWSequences[OperIdx], ExpandedRWs);
|
||||
}
|
||||
assert(OperIdx == RWSequences.size() && "missed a sequence");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Push this transition's expanded sequence onto this transition's last
|
||||
// sequence (add to the current operand's sequence).
|
||||
SmallVectorImpl<unsigned> &Seq = RWSequences.back();
|
||||
@@ -1644,8 +1632,9 @@ bool PredTransitions::substituteVariants(const PredTransition &Trans) {
|
||||
// Visit each original write sequence.
|
||||
for (const auto &WriteSequence : Trans.WriteSequences) {
|
||||
// Push a new (empty) write sequence onto all partial Transitions.
|
||||
for (std::vector<PredTransition>::iterator I =
|
||||
TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {
|
||||
for (std::vector<PredTransition>::iterator I = TransVec.begin() + StartIdx,
|
||||
E = TransVec.end();
|
||||
I != E; ++I) {
|
||||
I->WriteSequences.emplace_back();
|
||||
}
|
||||
Subst |=
|
||||
@@ -1654,8 +1643,9 @@ bool PredTransitions::substituteVariants(const PredTransition &Trans) {
|
||||
// Visit each original read sequence.
|
||||
for (const auto &ReadSequence : Trans.ReadSequences) {
|
||||
// Push a new (empty) read sequence onto all partial Transitions.
|
||||
for (std::vector<PredTransition>::iterator I =
|
||||
TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {
|
||||
for (std::vector<PredTransition>::iterator I = TransVec.begin() + StartIdx,
|
||||
E = TransVec.end();
|
||||
I != E; ++I) {
|
||||
I->ReadSequences.emplace_back();
|
||||
}
|
||||
Subst |= substituteVariantOperand(ReadSequence, /*IsRead=*/true, StartIdx);
|
||||
@@ -1814,7 +1804,7 @@ bool CodeGenSchedModels::hasSuperGroup(RecVec &SubUnits, CodeGenProcModel &PM) {
|
||||
continue;
|
||||
RecVec SuperUnits = ProcResourceDef->getValueAsListOfDefs("Resources");
|
||||
RecIter RI = SubUnits.begin(), RE = SubUnits.end();
|
||||
for ( ; RI != RE; ++RI) {
|
||||
for (; RI != RE; ++RI) {
|
||||
if (!is_contained(SuperUnits, *RI)) {
|
||||
break;
|
||||
}
|
||||
@@ -1831,22 +1821,22 @@ void CodeGenSchedModels::verifyProcResourceGroups(CodeGenProcModel &PM) {
|
||||
if (!PM.ProcResourceDefs[i]->isSubClassOf("ProcResGroup"))
|
||||
continue;
|
||||
RecVec CheckUnits =
|
||||
PM.ProcResourceDefs[i]->getValueAsListOfDefs("Resources");
|
||||
for (unsigned j = i+1; j < e; ++j) {
|
||||
PM.ProcResourceDefs[i]->getValueAsListOfDefs("Resources");
|
||||
for (unsigned j = i + 1; j < e; ++j) {
|
||||
if (!PM.ProcResourceDefs[j]->isSubClassOf("ProcResGroup"))
|
||||
continue;
|
||||
RecVec OtherUnits =
|
||||
PM.ProcResourceDefs[j]->getValueAsListOfDefs("Resources");
|
||||
PM.ProcResourceDefs[j]->getValueAsListOfDefs("Resources");
|
||||
if (std::find_first_of(CheckUnits.begin(), CheckUnits.end(),
|
||||
OtherUnits.begin(), OtherUnits.end())
|
||||
!= CheckUnits.end()) {
|
||||
OtherUnits.begin(),
|
||||
OtherUnits.end()) != CheckUnits.end()) {
|
||||
// CheckUnits and OtherUnits overlap
|
||||
llvm::append_range(OtherUnits, CheckUnits);
|
||||
if (!hasSuperGroup(OtherUnits, PM)) {
|
||||
PrintFatalError((PM.ProcResourceDefs[i])->getLoc(),
|
||||
"proc resource group overlaps with "
|
||||
+ PM.ProcResourceDefs[j]->getName()
|
||||
+ " but no supergroup contains both.");
|
||||
"proc resource group overlaps with " +
|
||||
PM.ProcResourceDefs[j]->getName() +
|
||||
" but no supergroup contains both.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1862,7 +1852,7 @@ void CodeGenSchedModels::collectRegisterFiles() {
|
||||
// For each register file definition, construct a CodeGenRegisterFile object
|
||||
// and add it to the appropriate scheduling model.
|
||||
CodeGenProcModel &PM = getProcModel(RF->getValueAsDef("SchedModel"));
|
||||
PM.RegisterFiles.emplace_back(CodeGenRegisterFile(RF->getName(),RF));
|
||||
PM.RegisterFiles.emplace_back(CodeGenRegisterFile(RF->getName(), RF));
|
||||
CodeGenRegisterFile &CGRF = PM.RegisterFiles.back();
|
||||
CGRF.MaxMovesEliminatedPerCycle =
|
||||
RF->getValueAsInt("MaxMovesEliminatedPerCycle");
|
||||
@@ -2013,7 +2003,7 @@ void CodeGenSchedModels::checkCompleteness() {
|
||||
PrintError(Inst->TheDef->getLoc(),
|
||||
"No schedule information for instruction '" +
|
||||
Inst->TheDef->getName() + "' in SchedMachineModel '" +
|
||||
ProcModel.ModelDef->getName() + "'");
|
||||
ProcModel.ModelDef->getName() + "'");
|
||||
Complete = false;
|
||||
}
|
||||
continue;
|
||||
@@ -2039,14 +2029,18 @@ void CodeGenSchedModels::checkCompleteness() {
|
||||
}
|
||||
}
|
||||
if (!Complete) {
|
||||
errs() << "\n\nIncomplete schedule models found.\n"
|
||||
<< "- Consider setting 'CompleteModel = 0' while developing new models.\n"
|
||||
<< "- Pseudo instructions can be marked with 'hasNoSchedulingInfo = 1'.\n"
|
||||
<< "- Instructions should usually have Sched<[...]> as a superclass, "
|
||||
"you may temporarily use an empty list.\n"
|
||||
<< "- Instructions related to unsupported features can be excluded with "
|
||||
"list<Predicate> UnsupportedFeatures = [HasA,..,HasY]; in the "
|
||||
"processor model.\n\n";
|
||||
errs()
|
||||
<< "\n\nIncomplete schedule models found.\n"
|
||||
<< "- Consider setting 'CompleteModel = 0' while developing new "
|
||||
"models.\n"
|
||||
<< "- Pseudo instructions can be marked with 'hasNoSchedulingInfo = "
|
||||
"1'.\n"
|
||||
<< "- Instructions should usually have Sched<[...]> as a superclass, "
|
||||
"you may temporarily use an empty list.\n"
|
||||
<< "- Instructions related to unsupported features can be excluded "
|
||||
"with "
|
||||
"list<Predicate> UnsupportedFeatures = [HasA,..,HasY]; in the "
|
||||
"processor model.\n\n";
|
||||
PrintFatalError("Incomplete schedule model");
|
||||
}
|
||||
}
|
||||
@@ -2057,15 +2051,15 @@ void CodeGenSchedModels::collectItinProcResources(Record *ItinClassDef) {
|
||||
const CodeGenProcModel &PM = ProcModels[PIdx];
|
||||
// For all ItinRW entries.
|
||||
bool HasMatch = false;
|
||||
for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end();
|
||||
II != IE; ++II) {
|
||||
for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end(); II != IE;
|
||||
++II) {
|
||||
RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");
|
||||
if (!llvm::is_contained(Matched, ItinClassDef))
|
||||
continue;
|
||||
if (HasMatch)
|
||||
PrintFatalError((*II)->getLoc(), "Duplicate itinerary class "
|
||||
+ ItinClassDef->getName()
|
||||
+ " in ItinResources for " + PM.ModelName);
|
||||
PrintFatalError((*II)->getLoc(),
|
||||
"Duplicate itinerary class " + ItinClassDef->getName() +
|
||||
" in ItinResources for " + PM.ModelName);
|
||||
HasMatch = true;
|
||||
IdxVec Writes, Reads;
|
||||
findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
|
||||
@@ -2081,8 +2075,7 @@ void CodeGenSchedModels::collectRWResources(unsigned RWIdx, bool IsRead,
|
||||
if (!IsRead && SchedRW.TheDef->isSubClassOf("SchedWriteRes")) {
|
||||
for (unsigned Idx : ProcIndices)
|
||||
addWriteRes(SchedRW.TheDef, Idx);
|
||||
}
|
||||
else if (IsRead && SchedRW.TheDef->isSubClassOf("SchedReadAdvance")) {
|
||||
} else if (IsRead && SchedRW.TheDef->isSubClassOf("SchedReadAdvance")) {
|
||||
for (unsigned Idx : ProcIndices)
|
||||
addReadAdvance(SchedRW.TheDef, Idx);
|
||||
}
|
||||
@@ -2128,31 +2121,30 @@ Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind,
|
||||
assert(!ProcResGroups.empty());
|
||||
|
||||
for (Record *ProcResDef : ProcResourceDefs) {
|
||||
if (ProcResDef->getValueAsDef("Kind") == ProcResKind
|
||||
&& ProcResDef->getValueAsDef("SchedModel") == PM.ModelDef) {
|
||||
if (ProcResDef->getValueAsDef("Kind") == ProcResKind &&
|
||||
ProcResDef->getValueAsDef("SchedModel") == PM.ModelDef) {
|
||||
if (ProcUnitDef) {
|
||||
PrintFatalError(Loc,
|
||||
"Multiple ProcessorResourceUnits associated with "
|
||||
+ ProcResKind->getName());
|
||||
"Multiple ProcessorResourceUnits associated with " +
|
||||
ProcResKind->getName());
|
||||
}
|
||||
ProcUnitDef = ProcResDef;
|
||||
}
|
||||
}
|
||||
for (Record *ProcResGroup : ProcResGroups) {
|
||||
if (ProcResGroup == ProcResKind
|
||||
&& ProcResGroup->getValueAsDef("SchedModel") == PM.ModelDef) {
|
||||
if (ProcResGroup == ProcResKind &&
|
||||
ProcResGroup->getValueAsDef("SchedModel") == PM.ModelDef) {
|
||||
if (ProcUnitDef) {
|
||||
PrintFatalError(Loc,
|
||||
"Multiple ProcessorResourceUnits associated with "
|
||||
+ ProcResKind->getName());
|
||||
"Multiple ProcessorResourceUnits associated with " +
|
||||
ProcResKind->getName());
|
||||
}
|
||||
ProcUnitDef = ProcResGroup;
|
||||
}
|
||||
}
|
||||
if (!ProcUnitDef) {
|
||||
PrintFatalError(Loc,
|
||||
"No ProcessorResources associated with "
|
||||
+ ProcResKind->getName());
|
||||
PrintFatalError(Loc, "No ProcessorResources associated with " +
|
||||
ProcResKind->getName());
|
||||
}
|
||||
return ProcUnitDef;
|
||||
}
|
||||
@@ -2208,14 +2200,16 @@ unsigned CodeGenProcModel::getProcResourceIdx(Record *PRDef) const {
|
||||
RecIter PRPos = find(ProcResourceDefs, PRDef);
|
||||
if (PRPos == ProcResourceDefs.end())
|
||||
PrintFatalError(PRDef->getLoc(), "ProcResource def is not included in "
|
||||
"the ProcResources list for " + ModelName);
|
||||
"the ProcResources list for " +
|
||||
ModelName);
|
||||
// Idx=0 is reserved for invalid.
|
||||
return 1 + (PRPos - ProcResourceDefs.begin());
|
||||
}
|
||||
|
||||
bool CodeGenProcModel::isUnsupported(const CodeGenInstruction &Inst) const {
|
||||
for (const Record *TheDef : UnsupportedFeaturesDefs) {
|
||||
for (const Record *PredDef : Inst.TheDef->getValueAsListOfDefs("Predicates")) {
|
||||
for (const Record *PredDef :
|
||||
Inst.TheDef->getValueAsListOfDefs("Predicates")) {
|
||||
if (TheDef->getName() == PredDef->getName())
|
||||
return true;
|
||||
}
|
||||
@@ -2239,12 +2233,11 @@ void CodeGenSchedRW::dump() const {
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const {
|
||||
dbgs() << "SCHEDCLASS " << Index << ":" << Name << '\n'
|
||||
<< " Writes: ";
|
||||
void CodeGenSchedClass::dump(const CodeGenSchedModels *SchedModels) const {
|
||||
dbgs() << "SCHEDCLASS " << Index << ":" << Name << '\n' << " Writes: ";
|
||||
for (unsigned i = 0, N = Writes.size(); i < N; ++i) {
|
||||
SchedModels->getSchedWrite(Writes[i]).dump();
|
||||
if (i < N-1) {
|
||||
if (i < N - 1) {
|
||||
dbgs() << '\n';
|
||||
dbgs().indent(10);
|
||||
}
|
||||
@@ -2252,12 +2245,13 @@ void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const {
|
||||
dbgs() << "\n Reads: ";
|
||||
for (unsigned i = 0, N = Reads.size(); i < N; ++i) {
|
||||
SchedModels->getSchedRead(Reads[i]).dump();
|
||||
if (i < N-1) {
|
||||
if (i < N - 1) {
|
||||
dbgs() << '\n';
|
||||
dbgs().indent(10);
|
||||
}
|
||||
}
|
||||
dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices);
|
||||
dbgs() << "\n ProcIdx: ";
|
||||
dumpIdxVec(ProcIndices);
|
||||
if (!Transitions.empty()) {
|
||||
dbgs() << "\n Transitions for Proc ";
|
||||
for (const CodeGenSchedTransition &Transition : Transitions) {
|
||||
|
||||
@@ -33,8 +33,8 @@ class CodeGenTarget;
|
||||
class CodeGenSchedModels;
|
||||
class CodeGenInstruction;
|
||||
|
||||
using RecVec = std::vector<Record*>;
|
||||
using RecIter = std::vector<Record*>::const_iterator;
|
||||
using RecVec = std::vector<Record *>;
|
||||
using RecIter = std::vector<Record *>::const_iterator;
|
||||
|
||||
using IdxVec = std::vector<unsigned>;
|
||||
using IdxIter = std::vector<unsigned>::const_iterator;
|
||||
@@ -59,10 +59,10 @@ struct CodeGenSchedRW {
|
||||
RecVec Aliases;
|
||||
|
||||
CodeGenSchedRW()
|
||||
: Index(0), TheDef(nullptr), IsRead(false), IsAlias(false),
|
||||
HasVariants(false), IsVariadic(false), IsSequence(false) {}
|
||||
: Index(0), TheDef(nullptr), IsRead(false), IsAlias(false),
|
||||
HasVariants(false), IsVariadic(false), IsSequence(false) {}
|
||||
CodeGenSchedRW(unsigned Idx, Record *Def)
|
||||
: Index(Idx), TheDef(Def), IsAlias(false), IsVariadic(false) {
|
||||
: Index(Idx), TheDef(Def), IsAlias(false), IsVariadic(false) {
|
||||
Name = std::string(Def->getName());
|
||||
IsRead = Def->isSubClassOf("SchedRead");
|
||||
HasVariants = Def->isSubClassOf("SchedVariant");
|
||||
@@ -148,7 +148,7 @@ struct CodeGenSchedClass {
|
||||
DenseSet<unsigned> InstRWProcIndices;
|
||||
|
||||
CodeGenSchedClass(unsigned Index, std::string Name, Record *ItinClassDef)
|
||||
: Index(Index), Name(std::move(Name)), ItinClassDef(ItinClassDef) {}
|
||||
: Index(Index), Name(std::move(Name)), ItinClassDef(ItinClassDef) {}
|
||||
|
||||
bool isKeyEqual(Record *IC, ArrayRef<unsigned> W,
|
||||
ArrayRef<unsigned> R) const {
|
||||
@@ -173,7 +173,8 @@ struct CodeGenRegisterCost {
|
||||
Record *RCDef;
|
||||
unsigned Cost;
|
||||
bool AllowMoveElimination;
|
||||
CodeGenRegisterCost(Record *RC, unsigned RegisterCost, bool AllowMoveElim = false)
|
||||
CodeGenRegisterCost(Record *RC, unsigned RegisterCost,
|
||||
bool AllowMoveElim = false)
|
||||
: RCDef(RC), Cost(RegisterCost), AllowMoveElimination(AllowMoveElim) {}
|
||||
CodeGenRegisterCost(const CodeGenRegisterCost &) = default;
|
||||
CodeGenRegisterCost &operator=(const CodeGenRegisterCost &) = delete;
|
||||
@@ -193,12 +194,12 @@ struct CodeGenRegisterFile {
|
||||
unsigned NumPhysRegs;
|
||||
std::vector<CodeGenRegisterCost> Costs;
|
||||
|
||||
CodeGenRegisterFile(StringRef name, Record *def, unsigned MaxMoveElimPerCy = 0,
|
||||
CodeGenRegisterFile(StringRef name, Record *def,
|
||||
unsigned MaxMoveElimPerCy = 0,
|
||||
bool AllowZeroMoveElimOnly = false)
|
||||
: Name(name), RegisterFileDef(def),
|
||||
MaxMovesEliminatedPerCycle(MaxMoveElimPerCy),
|
||||
AllowZeroMoveEliminationOnly(AllowZeroMoveElimOnly),
|
||||
NumPhysRegs(0) {}
|
||||
AllowZeroMoveEliminationOnly(AllowZeroMoveElimOnly), NumPhysRegs(0) {}
|
||||
|
||||
bool hasDefaultCosts() const { return Costs.empty(); }
|
||||
};
|
||||
@@ -255,10 +256,9 @@ struct CodeGenProcModel {
|
||||
Record *LoadQueue;
|
||||
Record *StoreQueue;
|
||||
|
||||
CodeGenProcModel(unsigned Idx, std::string Name, Record *MDef,
|
||||
Record *IDef) :
|
||||
Index(Idx), ModelName(std::move(Name)), ModelDef(MDef), ItinsDef(IDef),
|
||||
RetireControlUnit(nullptr), LoadQueue(nullptr), StoreQueue(nullptr) {}
|
||||
CodeGenProcModel(unsigned Idx, std::string Name, Record *MDef, Record *IDef)
|
||||
: Index(Idx), ModelName(std::move(Name)), ModelDef(MDef), ItinsDef(IDef),
|
||||
RetireControlUnit(nullptr), LoadQueue(nullptr), StoreQueue(nullptr) {}
|
||||
|
||||
bool hasItineraries() const {
|
||||
return !ItinsDef->getValueAsListOfDefs("IID").empty();
|
||||
@@ -443,14 +443,14 @@ class CodeGenSchedModels {
|
||||
|
||||
// Map each instruction to its unique SchedClass index considering the
|
||||
// combination of it's itinerary class, SchedRW list, and InstRW records.
|
||||
using InstClassMapTy = DenseMap<Record*, unsigned>;
|
||||
using InstClassMapTy = DenseMap<Record *, unsigned>;
|
||||
InstClassMapTy InstrClassMap;
|
||||
|
||||
std::vector<STIPredicateFunction> STIPredicates;
|
||||
std::vector<unsigned> getAllProcIndices() const;
|
||||
|
||||
public:
|
||||
CodeGenSchedModels(RecordKeeper& RK, const CodeGenTarget &TGT);
|
||||
CodeGenSchedModels(RecordKeeper &RK, const CodeGenTarget &TGT);
|
||||
|
||||
// iterator access to the scheduling classes.
|
||||
using class_iterator = std::vector<CodeGenSchedClass>::iterator;
|
||||
@@ -460,10 +460,10 @@ public:
|
||||
class_iterator classes_end() { return SchedClasses.end(); }
|
||||
const_class_iterator classes_end() const { return SchedClasses.end(); }
|
||||
iterator_range<class_iterator> classes() {
|
||||
return make_range(classes_begin(), classes_end());
|
||||
return make_range(classes_begin(), classes_end());
|
||||
}
|
||||
iterator_range<const_class_iterator> classes() const {
|
||||
return make_range(classes_begin(), classes_end());
|
||||
return make_range(classes_begin(), classes_end());
|
||||
}
|
||||
iterator_range<class_iterator> explicit_classes() {
|
||||
return make_range(classes_begin(), classes_begin() + NumInstrSchedClasses);
|
||||
@@ -476,8 +476,8 @@ public:
|
||||
Record *ModelDef = ProcDef->getValueAsDef("SchedModel");
|
||||
Record *ItinsDef = ProcDef->getValueAsDef("ProcItin");
|
||||
if (!ItinsDef->getValueAsListOfDefs("IID").empty()) {
|
||||
assert(ModelDef->getValueAsBit("NoModel")
|
||||
&& "Itineraries must be defined within SchedMachineModel");
|
||||
assert(ModelDef->getValueAsBit("NoModel") &&
|
||||
"Itineraries must be defined within SchedMachineModel");
|
||||
return ItinsDef;
|
||||
}
|
||||
return ModelDef;
|
||||
@@ -496,7 +496,7 @@ public:
|
||||
return ProcModels[I->second];
|
||||
}
|
||||
const CodeGenProcModel &getProcModel(Record *ModelDef) const {
|
||||
return const_cast<CodeGenSchedModels*>(this)->getProcModel(ModelDef);
|
||||
return const_cast<CodeGenSchedModels *>(this)->getProcModel(ModelDef);
|
||||
}
|
||||
|
||||
// Iterate over the unique processor models.
|
||||
@@ -527,11 +527,11 @@ public:
|
||||
CodeGenSchedRW &getSchedRW(Record *Def) {
|
||||
bool IsRead = Def->isSubClassOf("SchedRead");
|
||||
unsigned Idx = getSchedRWIdx(Def, IsRead);
|
||||
return const_cast<CodeGenSchedRW&>(
|
||||
IsRead ? getSchedRead(Idx) : getSchedWrite(Idx));
|
||||
return const_cast<CodeGenSchedRW &>(IsRead ? getSchedRead(Idx)
|
||||
: getSchedWrite(Idx));
|
||||
}
|
||||
const CodeGenSchedRW &getSchedRW(Record *Def) const {
|
||||
return const_cast<CodeGenSchedModels&>(*this).getSchedRW(Def);
|
||||
return const_cast<CodeGenSchedModels &>(*this).getSchedRW(Def);
|
||||
}
|
||||
|
||||
unsigned getSchedRWIdx(const Record *Def, bool IsRead) const;
|
||||
@@ -579,6 +579,7 @@ public:
|
||||
ArrayRef<STIPredicateFunction> getSTIPredicates() const {
|
||||
return STIPredicates;
|
||||
}
|
||||
|
||||
private:
|
||||
void collectProcModels();
|
||||
|
||||
|
||||
@@ -49,10 +49,14 @@ MVT::SimpleValueType llvm::getValueType(const Record *Rec) {
|
||||
|
||||
StringRef llvm::getName(MVT::SimpleValueType T) {
|
||||
switch (T) {
|
||||
case MVT::Other: return "UNKNOWN";
|
||||
case MVT::iPTR: return "TLI.getPointerTy()";
|
||||
case MVT::iPTRAny: return "TLI.getPointerTy()";
|
||||
default: return getEnumName(T);
|
||||
case MVT::Other:
|
||||
return "UNKNOWN";
|
||||
case MVT::iPTR:
|
||||
return "TLI.getPointerTy()";
|
||||
case MVT::iPTRAny:
|
||||
return "TLI.getPointerTy()";
|
||||
default:
|
||||
return getEnumName(T);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,12 +284,11 @@ std::string llvm::getQualifiedName(const Record *R) {
|
||||
return Namespace + "::" + R->getName().str();
|
||||
}
|
||||
|
||||
|
||||
/// getTarget - Return the current instance of the Target class.
|
||||
///
|
||||
CodeGenTarget::CodeGenTarget(RecordKeeper &records)
|
||||
: Records(records), CGH(records) {
|
||||
std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target");
|
||||
: Records(records), CGH(records) {
|
||||
std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target");
|
||||
if (Targets.size() == 0)
|
||||
PrintFatalError("No 'Target' subclasses defined!");
|
||||
if (Targets.size() != 1)
|
||||
@@ -294,8 +297,7 @@ CodeGenTarget::CodeGenTarget(RecordKeeper &records)
|
||||
MacroFusions = Records.getAllDerivedDefinitions("Fusion");
|
||||
}
|
||||
|
||||
CodeGenTarget::~CodeGenTarget() {
|
||||
}
|
||||
CodeGenTarget::~CodeGenTarget() {}
|
||||
|
||||
StringRef CodeGenTarget::getName() const { return TargetRec->getName(); }
|
||||
|
||||
@@ -331,7 +333,7 @@ bool CodeGenTarget::getAllowRegisterRenaming() const {
|
||||
/// getAsmParser - Return the AssemblyParser definition for this target.
|
||||
///
|
||||
Record *CodeGenTarget::getAsmParser() const {
|
||||
std::vector<Record*> LI = TargetRec->getValueAsListOfDefs("AssemblyParsers");
|
||||
std::vector<Record *> LI = TargetRec->getValueAsListOfDefs("AssemblyParsers");
|
||||
if (AsmParserNum >= LI.size())
|
||||
PrintFatalError("Target does not have an AsmParser #" +
|
||||
Twine(AsmParserNum) + "!");
|
||||
@@ -342,8 +344,8 @@ Record *CodeGenTarget::getAsmParser() const {
|
||||
/// this target.
|
||||
///
|
||||
Record *CodeGenTarget::getAsmParserVariant(unsigned i) const {
|
||||
std::vector<Record*> LI =
|
||||
TargetRec->getValueAsListOfDefs("AssemblyParserVariants");
|
||||
std::vector<Record *> LI =
|
||||
TargetRec->getValueAsListOfDefs("AssemblyParserVariants");
|
||||
if (i >= LI.size())
|
||||
PrintFatalError("Target does not have an AsmParserVariant #" + Twine(i) +
|
||||
"!");
|
||||
@@ -354,15 +356,15 @@ Record *CodeGenTarget::getAsmParserVariant(unsigned i) const {
|
||||
/// available for this target.
|
||||
///
|
||||
unsigned CodeGenTarget::getAsmParserVariantCount() const {
|
||||
std::vector<Record*> LI =
|
||||
TargetRec->getValueAsListOfDefs("AssemblyParserVariants");
|
||||
std::vector<Record *> LI =
|
||||
TargetRec->getValueAsListOfDefs("AssemblyParserVariants");
|
||||
return LI.size();
|
||||
}
|
||||
|
||||
/// getAsmWriter - Return the AssemblyWriter definition for this target.
|
||||
///
|
||||
Record *CodeGenTarget::getAsmWriter() const {
|
||||
std::vector<Record*> LI = TargetRec->getValueAsListOfDefs("AssemblyWriters");
|
||||
std::vector<Record *> LI = TargetRec->getValueAsListOfDefs("AssemblyWriters");
|
||||
if (AsmWriterNum >= LI.size())
|
||||
PrintFatalError("Target does not have an AsmWriter #" +
|
||||
Twine(AsmWriterNum) + "!");
|
||||
@@ -437,8 +439,7 @@ const CodeGenRegisterClass &CodeGenTarget::getRegisterClass(Record *R) const {
|
||||
return *getRegBank().getRegClass(R);
|
||||
}
|
||||
|
||||
std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R)
|
||||
const {
|
||||
std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R) const {
|
||||
const CodeGenRegister *Reg = getRegBank().getReg(R);
|
||||
std::vector<ValueTypeByHwMode> Result;
|
||||
for (const auto &RC : getRegBank().getRegClasses()) {
|
||||
@@ -454,16 +455,15 @@ std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R)
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
void CodeGenTarget::ReadLegalValueTypes() const {
|
||||
for (const auto &RC : getRegBank().getRegClasses())
|
||||
llvm::append_range(LegalValueTypes, RC.VTs);
|
||||
|
||||
// Remove duplicates.
|
||||
llvm::sort(LegalValueTypes);
|
||||
LegalValueTypes.erase(std::unique(LegalValueTypes.begin(),
|
||||
LegalValueTypes.end()),
|
||||
LegalValueTypes.end());
|
||||
LegalValueTypes.erase(
|
||||
std::unique(LegalValueTypes.begin(), LegalValueTypes.end()),
|
||||
LegalValueTypes.end());
|
||||
}
|
||||
|
||||
CodeGenSchedModels &CodeGenTarget::getSchedModels() const {
|
||||
@@ -473,7 +473,7 @@ CodeGenSchedModels &CodeGenTarget::getSchedModels() const {
|
||||
}
|
||||
|
||||
void CodeGenTarget::ReadInstructions() const {
|
||||
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
|
||||
std::vector<Record *> Insts = Records.getAllDerivedDefinitions("Instruction");
|
||||
if (Insts.size() <= 2)
|
||||
PrintFatalError("No 'Instruction' subclasses defined!");
|
||||
|
||||
@@ -482,11 +482,10 @@ void CodeGenTarget::ReadInstructions() const {
|
||||
Instructions[Insts[i]] = std::make_unique<CodeGenInstruction>(Insts[i]);
|
||||
}
|
||||
|
||||
static const CodeGenInstruction *
|
||||
GetInstByName(const char *Name,
|
||||
const DenseMap<const Record*,
|
||||
std::unique_ptr<CodeGenInstruction>> &Insts,
|
||||
RecordKeeper &Records) {
|
||||
static const CodeGenInstruction *GetInstByName(
|
||||
const char *Name,
|
||||
const DenseMap<const Record *, std::unique_ptr<CodeGenInstruction>> &Insts,
|
||||
RecordKeeper &Records) {
|
||||
const Record *Rec = Records.getDef(Name);
|
||||
|
||||
const auto I = Insts.find(Rec);
|
||||
@@ -545,7 +544,6 @@ void CodeGenTarget::ComputeInstrsByEnum() const {
|
||||
Inst->EnumVal = Num++;
|
||||
}
|
||||
|
||||
|
||||
/// isLittleEndianEncoding - Return whether this target encodes its instruction
|
||||
/// in little-endian format, i.e. bits laid out in the order [0..n]
|
||||
///
|
||||
@@ -576,7 +574,7 @@ void CodeGenTarget::reverseBitsForLittleEndianEncoding() {
|
||||
unsigned bitSwapIdx = numBits - bit - 1;
|
||||
Init *OrigBit = BI->getBit(bit);
|
||||
Init *BitSwap = BI->getBit(bitSwapIdx);
|
||||
NewBits[bit] = BitSwap;
|
||||
NewBits[bit] = BitSwap;
|
||||
NewBits[bitSwapIdx] = OrigBit;
|
||||
}
|
||||
if (numBits % 2) {
|
||||
@@ -605,10 +603,10 @@ bool CodeGenTarget::guessInstructionProperties() const {
|
||||
// ComplexPattern implementation
|
||||
//
|
||||
ComplexPattern::ComplexPattern(Record *R) {
|
||||
Ty = R->getValueAsDef("Ty");
|
||||
Ty = R->getValueAsDef("Ty");
|
||||
NumOperands = R->getValueAsInt("NumOperands");
|
||||
SelectFunc = std::string(R->getValueAsString("SelectFunc"));
|
||||
RootNodes = R->getValueAsListOfDefs("RootNodes");
|
||||
RootNodes = R->getValueAsListOfDefs("RootNodes");
|
||||
|
||||
// FIXME: This is a hack to statically increase the priority of patterns which
|
||||
// maps a sub-dag to a complex pattern. e.g. favors LEA over ADD. To get best
|
||||
@@ -623,7 +621,7 @@ ComplexPattern::ComplexPattern(Record *R) {
|
||||
// FIXME: Why is this different from parseSDPatternOperatorProperties?
|
||||
// Parse the properties.
|
||||
Properties = 0;
|
||||
std::vector<Record*> PropList = R->getValueAsListOfDefs("Properties");
|
||||
std::vector<Record *> PropList = R->getValueAsListOfDefs("Properties");
|
||||
for (unsigned i = 0, e = PropList.size(); i != e; ++i)
|
||||
if (PropList[i]->getName() == "SDNPHasChain") {
|
||||
Properties |= 1 << SDNPHasChain;
|
||||
|
||||
@@ -58,10 +58,10 @@ class CodeGenTarget {
|
||||
RecordKeeper &Records;
|
||||
Record *TargetRec;
|
||||
|
||||
mutable DenseMap<const Record*,
|
||||
std::unique_ptr<CodeGenInstruction>> Instructions;
|
||||
mutable DenseMap<const Record *, std::unique_ptr<CodeGenInstruction>>
|
||||
Instructions;
|
||||
mutable std::unique_ptr<CodeGenRegBank> RegBank;
|
||||
mutable std::vector<Record*> RegAltNameIndices;
|
||||
mutable std::vector<Record *> RegAltNameIndices;
|
||||
mutable SmallVector<ValueTypeByHwMode, 8> LegalValueTypes;
|
||||
CodeGenHwModes CGH;
|
||||
std::vector<Record *> MacroFusions;
|
||||
@@ -75,6 +75,7 @@ class CodeGenTarget {
|
||||
mutable StringRef InstNamespace;
|
||||
mutable std::vector<const CodeGenInstruction *> InstrsByEnum;
|
||||
mutable unsigned NumPseudoInstructions = 0;
|
||||
|
||||
public:
|
||||
CodeGenTarget(RecordKeeper &Records);
|
||||
~CodeGenTarget();
|
||||
@@ -130,8 +131,9 @@ public:
|
||||
/// return it.
|
||||
const CodeGenRegister *getRegisterByName(StringRef Name) const;
|
||||
|
||||
const std::vector<Record*> &getRegAltNameIndices() const {
|
||||
if (RegAltNameIndices.empty()) ReadRegAltNameIndices();
|
||||
const std::vector<Record *> &getRegAltNameIndices() const {
|
||||
if (RegAltNameIndices.empty())
|
||||
ReadRegAltNameIndices();
|
||||
return RegAltNameIndices;
|
||||
}
|
||||
|
||||
@@ -156,15 +158,17 @@ public:
|
||||
const std::vector<Record *> getMacroFusions() const { return MacroFusions; }
|
||||
|
||||
private:
|
||||
DenseMap<const Record*, std::unique_ptr<CodeGenInstruction>> &
|
||||
DenseMap<const Record *, std::unique_ptr<CodeGenInstruction>> &
|
||||
getInstructions() const {
|
||||
if (Instructions.empty()) ReadInstructions();
|
||||
if (Instructions.empty())
|
||||
ReadInstructions();
|
||||
return Instructions;
|
||||
}
|
||||
public:
|
||||
|
||||
public:
|
||||
CodeGenInstruction &getInstruction(const Record *InstRec) const {
|
||||
if (Instructions.empty()) ReadInstructions();
|
||||
if (Instructions.empty())
|
||||
ReadInstructions();
|
||||
auto I = Instructions.find(InstRec);
|
||||
assert(I != Instructions.end() && "Not an instruction");
|
||||
return *I->second;
|
||||
@@ -200,10 +204,11 @@ public:
|
||||
}
|
||||
|
||||
typedef ArrayRef<const CodeGenInstruction *>::const_iterator inst_iterator;
|
||||
inst_iterator inst_begin() const{return getInstructionsByEnumValue().begin();}
|
||||
inst_iterator inst_begin() const {
|
||||
return getInstructionsByEnumValue().begin();
|
||||
}
|
||||
inst_iterator inst_end() const { return getInstructionsByEnumValue().end(); }
|
||||
|
||||
|
||||
/// isLittleEndianEncoding - are instruction bit patterns defined as [0..n]?
|
||||
///
|
||||
bool isLittleEndianEncoding() const;
|
||||
@@ -226,22 +231,21 @@ class ComplexPattern {
|
||||
Record *Ty;
|
||||
unsigned NumOperands;
|
||||
std::string SelectFunc;
|
||||
std::vector<Record*> RootNodes;
|
||||
std::vector<Record *> RootNodes;
|
||||
unsigned Properties; // Node properties
|
||||
unsigned Complexity;
|
||||
|
||||
public:
|
||||
ComplexPattern(Record *R);
|
||||
|
||||
Record *getValueType() const { return Ty; }
|
||||
unsigned getNumOperands() const { return NumOperands; }
|
||||
const std::string &getSelectFunc() const { return SelectFunc; }
|
||||
const std::vector<Record*> &getRootNodes() const {
|
||||
return RootNodes;
|
||||
}
|
||||
const std::vector<Record *> &getRootNodes() const { return RootNodes; }
|
||||
bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); }
|
||||
unsigned getComplexity() const { return Complexity; }
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace {
|
||||
class DAGISelEmitter {
|
||||
RecordKeeper &Records; // Just so we can get at the timing functions.
|
||||
CodeGenDAGPatterns CGP;
|
||||
|
||||
public:
|
||||
explicit DAGISelEmitter(RecordKeeper &R) : Records(R), CGP(R) {}
|
||||
void run(raw_ostream &OS);
|
||||
@@ -42,7 +43,8 @@ public:
|
||||
/// latencies in this calculation.
|
||||
static unsigned getResultPatternCost(TreePatternNode *P,
|
||||
CodeGenDAGPatterns &CGP) {
|
||||
if (P->isLeaf()) return 0;
|
||||
if (P->isLeaf())
|
||||
return 0;
|
||||
|
||||
unsigned Cost = 0;
|
||||
Record *Op = P->getOperator();
|
||||
@@ -61,7 +63,8 @@ static unsigned getResultPatternCost(TreePatternNode *P,
|
||||
/// pattern.
|
||||
static unsigned getResultPatternSize(TreePatternNode *P,
|
||||
CodeGenDAGPatterns &CGP) {
|
||||
if (P->isLeaf()) return 0;
|
||||
if (P->isLeaf())
|
||||
return 0;
|
||||
|
||||
unsigned Cost = 0;
|
||||
Record *Op = P->getOperator();
|
||||
@@ -98,19 +101,25 @@ struct PatternSortingPredicate {
|
||||
// input over nodes that cover fewer.
|
||||
int LHSSize = LHS->getPatternComplexity(CGP);
|
||||
int RHSSize = RHS->getPatternComplexity(CGP);
|
||||
if (LHSSize > RHSSize) return true; // LHS -> bigger -> less cost
|
||||
if (LHSSize < RHSSize) return false;
|
||||
if (LHSSize > RHSSize)
|
||||
return true; // LHS -> bigger -> less cost
|
||||
if (LHSSize < RHSSize)
|
||||
return false;
|
||||
|
||||
// If the patterns have equal complexity, compare generated instruction cost
|
||||
unsigned LHSCost = getResultPatternCost(LHS->getDstPattern(), CGP);
|
||||
unsigned RHSCost = getResultPatternCost(RHS->getDstPattern(), CGP);
|
||||
if (LHSCost < RHSCost) return true;
|
||||
if (LHSCost > RHSCost) return false;
|
||||
if (LHSCost < RHSCost)
|
||||
return true;
|
||||
if (LHSCost > RHSCost)
|
||||
return false;
|
||||
|
||||
unsigned LHSPatSize = getResultPatternSize(LHS->getDstPattern(), CGP);
|
||||
unsigned RHSPatSize = getResultPatternSize(RHS->getDstPattern(), CGP);
|
||||
if (LHSPatSize < RHSPatSize) return true;
|
||||
if (LHSPatSize > RHSPatSize) return false;
|
||||
if (LHSPatSize < RHSPatSize)
|
||||
return true;
|
||||
if (LHSPatSize > RHSPatSize)
|
||||
return false;
|
||||
|
||||
// Sort based on the UID of the pattern, to reflect source order.
|
||||
// Note that this is not guaranteed to be unique, since a single source
|
||||
@@ -122,11 +131,11 @@ struct PatternSortingPredicate {
|
||||
};
|
||||
} // End anonymous namespace
|
||||
|
||||
|
||||
void DAGISelEmitter::run(raw_ostream &OS) {
|
||||
Records.startTimer("Parse patterns");
|
||||
emitSourceFileHeader("DAG Instruction Selector for the " +
|
||||
CGP.getTargetInfo().getName().str() + " target", OS);
|
||||
CGP.getTargetInfo().getName().str() + " target",
|
||||
OS);
|
||||
|
||||
OS << "// *** NOTE: This file is #included into the middle of the target\n"
|
||||
<< "// *** instruction selector class. These functions are really "
|
||||
@@ -155,7 +164,7 @@ void DAGISelEmitter::run(raw_ostream &OS) {
|
||||
|
||||
// Add all the patterns to a temporary list so we can sort them.
|
||||
Records.startTimer("Sort patterns");
|
||||
std::vector<const PatternToMatch*> Patterns;
|
||||
std::vector<const PatternToMatch *> Patterns;
|
||||
for (const PatternToMatch &PTM : CGP.ptms())
|
||||
Patterns.push_back(&PTM);
|
||||
|
||||
@@ -167,7 +176,7 @@ void DAGISelEmitter::run(raw_ostream &OS) {
|
||||
Records.startTimer("Convert to matchers");
|
||||
SmallVector<Matcher *, 0> PatternMatchers;
|
||||
for (const PatternToMatch *PTM : Patterns) {
|
||||
for (unsigned Variant = 0; ; ++Variant) {
|
||||
for (unsigned Variant = 0;; ++Variant) {
|
||||
if (Matcher *M = ConvertPatternToMatcher(*PTM, Variant, CGP))
|
||||
PatternMatchers.push_back(M);
|
||||
else
|
||||
@@ -181,7 +190,7 @@ void DAGISelEmitter::run(raw_ostream &OS) {
|
||||
Records.startTimer("Optimize matchers");
|
||||
OptimizeMatcher(TheMatcher, CGP);
|
||||
|
||||
//Matcher->dump();
|
||||
// Matcher->dump();
|
||||
|
||||
Records.startTimer("Emit matcher table");
|
||||
EmitMatcherTable(TheMatcher.get(), CGP, OS);
|
||||
|
||||
@@ -15,11 +15,9 @@
|
||||
#include "llvm/TableGen/Record.h"
|
||||
using namespace llvm;
|
||||
|
||||
void Matcher::anchor() { }
|
||||
void Matcher::anchor() {}
|
||||
|
||||
void Matcher::dump() const {
|
||||
print(errs(), 0);
|
||||
}
|
||||
void Matcher::dump() const { print(errs(), 0); }
|
||||
|
||||
void Matcher::print(raw_ostream &OS, unsigned indent) const {
|
||||
printImpl(OS, indent);
|
||||
@@ -27,9 +25,7 @@ void Matcher::print(raw_ostream &OS, unsigned indent) const {
|
||||
return Next->print(OS, indent);
|
||||
}
|
||||
|
||||
void Matcher::printOne(raw_ostream &OS) const {
|
||||
printImpl(OS, 0);
|
||||
}
|
||||
void Matcher::printOne(raw_ostream &OS) const { printImpl(OS, 0); }
|
||||
|
||||
/// unlinkNode - Unlink the specified node from this chain. If Other == this,
|
||||
/// we unlink the next pointer and return it. Otherwise we unlink Other from
|
||||
@@ -43,7 +39,8 @@ Matcher *Matcher::unlinkNode(Matcher *Other) {
|
||||
for (; Cur && Cur->getNext() != Other; Cur = Cur->getNext())
|
||||
/*empty*/;
|
||||
|
||||
if (!Cur) return nullptr;
|
||||
if (!Cur)
|
||||
return nullptr;
|
||||
Cur->takeNext();
|
||||
Cur->setNext(Other->takeNext());
|
||||
return this;
|
||||
@@ -55,7 +52,8 @@ Matcher *Matcher::unlinkNode(Matcher *Other) {
|
||||
bool Matcher::canMoveBefore(const Matcher *Other) const {
|
||||
for (;; Other = Other->getNext()) {
|
||||
assert(Other && "Other didn't come before 'this'?");
|
||||
if (this == Other) return true;
|
||||
if (this == Other)
|
||||
return true;
|
||||
|
||||
// We have to be able to move this node across the Other node.
|
||||
if (!canMoveBeforeNode(Other))
|
||||
@@ -78,7 +76,6 @@ bool Matcher::canMoveBeforeNode(const Matcher *Other) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ScopeMatcher::~ScopeMatcher() {
|
||||
for (Matcher *C : Children)
|
||||
delete C;
|
||||
@@ -96,8 +93,8 @@ SwitchTypeMatcher::~SwitchTypeMatcher() {
|
||||
|
||||
CheckPredicateMatcher::CheckPredicateMatcher(
|
||||
const TreePredicateFn &pred, const SmallVectorImpl<unsigned> &Ops)
|
||||
: Matcher(CheckPredicate), Pred(pred.getOrigPatFragRecord()),
|
||||
Operands(Ops.begin(), Ops.end()) {}
|
||||
: Matcher(CheckPredicate), Pred(pred.getOrigPatFragRecord()),
|
||||
Operands(Ops.begin(), Ops.end()) {}
|
||||
|
||||
TreePredicateFn CheckPredicateMatcher::getPredicate() const {
|
||||
return TreePredicateFn(Pred);
|
||||
@@ -112,16 +109,15 @@ unsigned CheckPredicateMatcher::getOperandNo(unsigned i) const {
|
||||
return Operands[i];
|
||||
}
|
||||
|
||||
|
||||
// printImpl methods.
|
||||
|
||||
void ScopeMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
OS.indent(indent) << "Scope\n";
|
||||
for (const Matcher *C : Children) {
|
||||
if (!C)
|
||||
OS.indent(indent+1) << "NULL POINTER\n";
|
||||
OS.indent(indent + 1) << "NULL POINTER\n";
|
||||
else
|
||||
C->print(OS, indent+2);
|
||||
C->print(OS, indent + 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +133,8 @@ void RecordMemRefMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
OS.indent(indent) << "RecordMemRef\n";
|
||||
}
|
||||
|
||||
void CaptureGlueInputMatcher::printImpl(raw_ostream &OS, unsigned indent) const{
|
||||
void CaptureGlueInputMatcher::printImpl(raw_ostream &OS,
|
||||
unsigned indent) const {
|
||||
OS.indent(indent) << "CaptureGlueInput\n";
|
||||
}
|
||||
|
||||
@@ -161,8 +158,8 @@ void CheckChildSameMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
OS.indent(indent) << "CheckChild" << ChildNo << "Same\n";
|
||||
}
|
||||
|
||||
void CheckPatternPredicateMatcher::
|
||||
printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
void CheckPatternPredicateMatcher::printImpl(raw_ostream &OS,
|
||||
unsigned indent) const {
|
||||
OS.indent(indent) << "CheckPatternPredicate " << Predicate << '\n';
|
||||
}
|
||||
|
||||
@@ -178,32 +175,30 @@ void SwitchOpcodeMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
OS.indent(indent) << "SwitchOpcode: {\n";
|
||||
for (const auto &C : Cases) {
|
||||
OS.indent(indent) << "case " << C.first->getEnumName() << ":\n";
|
||||
C.second->print(OS, indent+2);
|
||||
C.second->print(OS, indent + 2);
|
||||
}
|
||||
OS.indent(indent) << "}\n";
|
||||
}
|
||||
|
||||
|
||||
void CheckTypeMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
OS.indent(indent) << "CheckType " << getEnumName(Type) << ", ResNo="
|
||||
<< ResNo << '\n';
|
||||
OS.indent(indent) << "CheckType " << getEnumName(Type) << ", ResNo=" << ResNo
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
void SwitchTypeMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
OS.indent(indent) << "SwitchType: {\n";
|
||||
for (const auto &C : Cases) {
|
||||
OS.indent(indent) << "case " << getEnumName(C.first) << ":\n";
|
||||
C.second->print(OS, indent+2);
|
||||
C.second->print(OS, indent + 2);
|
||||
}
|
||||
OS.indent(indent) << "}\n";
|
||||
}
|
||||
|
||||
void CheckChildTypeMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
OS.indent(indent) << "CheckChildType " << ChildNo << " "
|
||||
<< getEnumName(Type) << '\n';
|
||||
OS.indent(indent) << "CheckChildType " << ChildNo << " " << getEnumName(Type)
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
|
||||
void CheckIntegerMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
OS.indent(indent) << "CheckInteger " << Value << '\n';
|
||||
}
|
||||
@@ -258,8 +253,8 @@ void EmitIntegerMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
void EmitStringIntegerMatcher::
|
||||
printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
void EmitStringIntegerMatcher::printImpl(raw_ostream &OS,
|
||||
unsigned indent) const {
|
||||
OS.indent(indent) << "EmitStringInteger " << Val << " VT=" << getEnumName(VT)
|
||||
<< '\n';
|
||||
}
|
||||
@@ -273,13 +268,13 @@ void EmitRegisterMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
OS << " VT=" << getEnumName(VT) << '\n';
|
||||
}
|
||||
|
||||
void EmitConvertToTargetMatcher::
|
||||
printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
void EmitConvertToTargetMatcher::printImpl(raw_ostream &OS,
|
||||
unsigned indent) const {
|
||||
OS.indent(indent) << "EmitConvertToTarget " << Slot << '\n';
|
||||
}
|
||||
|
||||
void EmitMergeInputChainsMatcher::
|
||||
printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
void EmitMergeInputChainsMatcher::printImpl(raw_ostream &OS,
|
||||
unsigned indent) const {
|
||||
OS.indent(indent) << "EmitMergeInputChains <todo: args>\n";
|
||||
}
|
||||
|
||||
@@ -289,10 +284,9 @@ void EmitCopyToRegMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
|
||||
void EmitNodeXFormMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
OS.indent(indent) << "EmitNodeXForm " << NodeXForm->getName()
|
||||
<< " Slot=" << Slot << '\n';
|
||||
<< " Slot=" << Slot << '\n';
|
||||
}
|
||||
|
||||
|
||||
void EmitNodeMatcherCommon::printImpl(raw_ostream &OS, unsigned indent) const {
|
||||
OS.indent(indent);
|
||||
OS << (isa<MorphNodeToMatcher>(this) ? "MorphNodeTo: " : "EmitNode: ")
|
||||
@@ -316,7 +310,7 @@ bool CheckOpcodeMatcher::isEqualImpl(const Matcher *M) const {
|
||||
// Note: pointer equality isn't enough here, we have to check the enum names
|
||||
// to ensure that the nodes are for the same opcode.
|
||||
return cast<CheckOpcodeMatcher>(M)->Opcode.getEnumName() ==
|
||||
Opcode.getEnumName();
|
||||
Opcode.getEnumName();
|
||||
}
|
||||
|
||||
bool EmitNodeMatcherCommon::isEqualImpl(const Matcher *m) const {
|
||||
@@ -327,9 +321,9 @@ bool EmitNodeMatcherCommon::isEqualImpl(const Matcher *m) const {
|
||||
M->NumFixedArityOperands == NumFixedArityOperands;
|
||||
}
|
||||
|
||||
void EmitNodeMatcher::anchor() { }
|
||||
void EmitNodeMatcher::anchor() {}
|
||||
|
||||
void MorphNodeToMatcher::anchor() { }
|
||||
void MorphNodeToMatcher::anchor() {}
|
||||
|
||||
// isContradictoryImpl Implementations.
|
||||
|
||||
@@ -337,7 +331,8 @@ static bool TypesAreContradictory(MVT::SimpleValueType T1,
|
||||
MVT::SimpleValueType T2) {
|
||||
// If the two types are the same, then they are the same, so they don't
|
||||
// contradict.
|
||||
if (T1 == T2) return false;
|
||||
if (T1 == T2)
|
||||
return false;
|
||||
|
||||
// If either type is about iPtr, then they don't conflict unless the other
|
||||
// one is not a scalar integer type.
|
||||
@@ -400,7 +395,8 @@ bool CheckIntegerMatcher::isContradictoryImpl(const Matcher *M) const {
|
||||
}
|
||||
|
||||
bool CheckChildIntegerMatcher::isContradictoryImpl(const Matcher *M) const {
|
||||
if (const CheckChildIntegerMatcher *CCIM = dyn_cast<CheckChildIntegerMatcher>(M)) {
|
||||
if (const CheckChildIntegerMatcher *CCIM =
|
||||
dyn_cast<CheckChildIntegerMatcher>(M)) {
|
||||
// If the two checks are about different nodes, we don't know if they
|
||||
// conflict!
|
||||
if (CCIM->getChildNo() != getChildNo())
|
||||
|
||||
@@ -21,185 +21,186 @@
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
class CodeGenRegister;
|
||||
class CodeGenDAGPatterns;
|
||||
class CodeGenInstruction;
|
||||
class Matcher;
|
||||
class PatternToMatch;
|
||||
class raw_ostream;
|
||||
class ComplexPattern;
|
||||
class Record;
|
||||
class SDNodeInfo;
|
||||
class TreePredicateFn;
|
||||
class TreePattern;
|
||||
class CodeGenRegister;
|
||||
class CodeGenDAGPatterns;
|
||||
class CodeGenInstruction;
|
||||
class Matcher;
|
||||
class PatternToMatch;
|
||||
class raw_ostream;
|
||||
class ComplexPattern;
|
||||
class Record;
|
||||
class SDNodeInfo;
|
||||
class TreePredicateFn;
|
||||
class TreePattern;
|
||||
|
||||
Matcher *ConvertPatternToMatcher(const PatternToMatch &Pattern,
|
||||
unsigned Variant,
|
||||
const CodeGenDAGPatterns &CGP);
|
||||
void OptimizeMatcher(std::unique_ptr<Matcher> &Matcher,
|
||||
const CodeGenDAGPatterns &CGP);
|
||||
void EmitMatcherTable(Matcher *Matcher, const CodeGenDAGPatterns &CGP,
|
||||
raw_ostream &OS);
|
||||
Matcher *ConvertPatternToMatcher(const PatternToMatch &Pattern,
|
||||
unsigned Variant,
|
||||
const CodeGenDAGPatterns &CGP);
|
||||
void OptimizeMatcher(std::unique_ptr<Matcher> &Matcher,
|
||||
const CodeGenDAGPatterns &CGP);
|
||||
void EmitMatcherTable(Matcher *Matcher, const CodeGenDAGPatterns &CGP,
|
||||
raw_ostream &OS);
|
||||
|
||||
/// Matcher - Base class for all the DAG ISel Matcher representation
|
||||
/// nodes.
|
||||
class Matcher {
|
||||
// The next matcher node that is executed after this one. Null if this is
|
||||
// the last stage of a match.
|
||||
std::unique_ptr<Matcher> Next;
|
||||
size_t Size = 0; // Size in bytes of matcher and all its children (if any).
|
||||
virtual void anchor();
|
||||
/// Matcher - Base class for all the DAG ISel Matcher representation
|
||||
/// nodes.
|
||||
class Matcher {
|
||||
// The next matcher node that is executed after this one. Null if this is
|
||||
// the last stage of a match.
|
||||
std::unique_ptr<Matcher> Next;
|
||||
size_t Size = 0; // Size in bytes of matcher and all its children (if any).
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
enum KindTy {
|
||||
// Matcher state manipulation.
|
||||
Scope, // Push a checking scope.
|
||||
RecordNode, // Record the current node.
|
||||
RecordChild, // Record a child of the current node.
|
||||
RecordMemRef, // Record the memref in the current node.
|
||||
CaptureGlueInput, // If the current node has an input glue, save it.
|
||||
MoveChild, // Move current node to specified child.
|
||||
MoveSibling, // Move current node to specified sibling.
|
||||
MoveParent, // Move current node to parent.
|
||||
public:
|
||||
enum KindTy {
|
||||
// Matcher state manipulation.
|
||||
Scope, // Push a checking scope.
|
||||
RecordNode, // Record the current node.
|
||||
RecordChild, // Record a child of the current node.
|
||||
RecordMemRef, // Record the memref in the current node.
|
||||
CaptureGlueInput, // If the current node has an input glue, save it.
|
||||
MoveChild, // Move current node to specified child.
|
||||
MoveSibling, // Move current node to specified sibling.
|
||||
MoveParent, // Move current node to parent.
|
||||
|
||||
// Predicate checking.
|
||||
CheckSame, // Fail if not same as prev match.
|
||||
CheckChildSame, // Fail if child not same as prev match.
|
||||
CheckPatternPredicate,
|
||||
CheckPredicate, // Fail if node predicate fails.
|
||||
CheckOpcode, // Fail if not opcode.
|
||||
SwitchOpcode, // Dispatch based on opcode.
|
||||
CheckType, // Fail if not correct type.
|
||||
SwitchType, // Dispatch based on type.
|
||||
CheckChildType, // Fail if child has wrong type.
|
||||
CheckInteger, // Fail if wrong val.
|
||||
CheckChildInteger, // Fail if child is wrong val.
|
||||
CheckCondCode, // Fail if not condcode.
|
||||
CheckChild2CondCode, // Fail if child is wrong condcode.
|
||||
CheckValueType,
|
||||
CheckComplexPat,
|
||||
CheckAndImm,
|
||||
CheckOrImm,
|
||||
CheckImmAllOnesV,
|
||||
CheckImmAllZerosV,
|
||||
CheckFoldableChainNode,
|
||||
// Predicate checking.
|
||||
CheckSame, // Fail if not same as prev match.
|
||||
CheckChildSame, // Fail if child not same as prev match.
|
||||
CheckPatternPredicate,
|
||||
CheckPredicate, // Fail if node predicate fails.
|
||||
CheckOpcode, // Fail if not opcode.
|
||||
SwitchOpcode, // Dispatch based on opcode.
|
||||
CheckType, // Fail if not correct type.
|
||||
SwitchType, // Dispatch based on type.
|
||||
CheckChildType, // Fail if child has wrong type.
|
||||
CheckInteger, // Fail if wrong val.
|
||||
CheckChildInteger, // Fail if child is wrong val.
|
||||
CheckCondCode, // Fail if not condcode.
|
||||
CheckChild2CondCode, // Fail if child is wrong condcode.
|
||||
CheckValueType,
|
||||
CheckComplexPat,
|
||||
CheckAndImm,
|
||||
CheckOrImm,
|
||||
CheckImmAllOnesV,
|
||||
CheckImmAllZerosV,
|
||||
CheckFoldableChainNode,
|
||||
|
||||
// Node creation/emisssion.
|
||||
EmitInteger, // Create a TargetConstant
|
||||
EmitStringInteger, // Create a TargetConstant from a string.
|
||||
EmitRegister, // Create a register.
|
||||
EmitConvertToTarget, // Convert a imm/fpimm to target imm/fpimm
|
||||
EmitMergeInputChains, // Merge together a chains for an input.
|
||||
EmitCopyToReg, // Emit a copytoreg into a physreg.
|
||||
EmitNode, // Create a DAG node
|
||||
EmitNodeXForm, // Run a SDNodeXForm
|
||||
CompleteMatch, // Finish a match and update the results.
|
||||
MorphNodeTo, // Build a node, finish a match and update results.
|
||||
// Node creation/emisssion.
|
||||
EmitInteger, // Create a TargetConstant
|
||||
EmitStringInteger, // Create a TargetConstant from a string.
|
||||
EmitRegister, // Create a register.
|
||||
EmitConvertToTarget, // Convert a imm/fpimm to target imm/fpimm
|
||||
EmitMergeInputChains, // Merge together a chains for an input.
|
||||
EmitCopyToReg, // Emit a copytoreg into a physreg.
|
||||
EmitNode, // Create a DAG node
|
||||
EmitNodeXForm, // Run a SDNodeXForm
|
||||
CompleteMatch, // Finish a match and update the results.
|
||||
MorphNodeTo, // Build a node, finish a match and update results.
|
||||
|
||||
// Highest enum value; watch out when adding more.
|
||||
HighestKind = MorphNodeTo
|
||||
};
|
||||
const KindTy Kind;
|
||||
|
||||
protected:
|
||||
Matcher(KindTy K) : Kind(K) {}
|
||||
|
||||
public:
|
||||
virtual ~Matcher() {}
|
||||
|
||||
unsigned getSize() const { return Size; }
|
||||
void setSize(unsigned sz) { Size = sz; }
|
||||
KindTy getKind() const { return Kind; }
|
||||
|
||||
Matcher *getNext() { return Next.get(); }
|
||||
const Matcher *getNext() const { return Next.get(); }
|
||||
void setNext(Matcher *C) { Next.reset(C); }
|
||||
Matcher *takeNext() { return Next.release(); }
|
||||
|
||||
std::unique_ptr<Matcher> &getNextPtr() { return Next; }
|
||||
|
||||
bool isEqual(const Matcher *M) const {
|
||||
if (getKind() != M->getKind())
|
||||
return false;
|
||||
return isEqualImpl(M);
|
||||
}
|
||||
|
||||
/// isSimplePredicateNode - Return true if this is a simple predicate that
|
||||
/// operates on the node or its children without potential side effects or a
|
||||
/// change of the current node.
|
||||
bool isSimplePredicateNode() const {
|
||||
switch (getKind()) {
|
||||
default:
|
||||
return false;
|
||||
case CheckSame:
|
||||
case CheckChildSame:
|
||||
case CheckPatternPredicate:
|
||||
case CheckPredicate:
|
||||
case CheckOpcode:
|
||||
case CheckType:
|
||||
case CheckChildType:
|
||||
case CheckInteger:
|
||||
case CheckChildInteger:
|
||||
case CheckCondCode:
|
||||
case CheckChild2CondCode:
|
||||
case CheckValueType:
|
||||
case CheckAndImm:
|
||||
case CheckOrImm:
|
||||
case CheckImmAllOnesV:
|
||||
case CheckImmAllZerosV:
|
||||
case CheckFoldableChainNode:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// isSimplePredicateOrRecordNode - Return true if this is a record node or
|
||||
/// a simple predicate.
|
||||
bool isSimplePredicateOrRecordNode() const {
|
||||
return isSimplePredicateNode() || getKind() == RecordNode ||
|
||||
getKind() == RecordChild;
|
||||
}
|
||||
|
||||
/// unlinkNode - Unlink the specified node from this chain. If Other ==
|
||||
/// this, we unlink the next pointer and return it. Otherwise we unlink
|
||||
/// Other from the list and return this.
|
||||
Matcher *unlinkNode(Matcher *Other);
|
||||
|
||||
/// canMoveBefore - Return true if this matcher is the same as Other, or if
|
||||
/// we can move this matcher past all of the nodes in-between Other and this
|
||||
/// node. Other must be equal to or before this.
|
||||
bool canMoveBefore(const Matcher *Other) const;
|
||||
|
||||
/// canMoveBeforeNode - Return true if it is safe to move the current
|
||||
/// matcher across the specified one.
|
||||
bool canMoveBeforeNode(const Matcher *Other) const;
|
||||
|
||||
/// isContradictory - Return true of these two matchers could never match on
|
||||
/// the same node.
|
||||
bool isContradictory(const Matcher *Other) const {
|
||||
// Since this predicate is reflexive, we canonicalize the ordering so that
|
||||
// we always match a node against nodes with kinds that are greater or
|
||||
// equal to them. For example, we'll pass in a CheckType node as an
|
||||
// argument to the CheckOpcode method, not the other way around.
|
||||
if (getKind() < Other->getKind())
|
||||
return isContradictoryImpl(Other);
|
||||
return Other->isContradictoryImpl(this);
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS, unsigned indent = 0) const;
|
||||
void printOne(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
protected:
|
||||
virtual void printImpl(raw_ostream &OS, unsigned indent) const = 0;
|
||||
virtual bool isEqualImpl(const Matcher *M) const = 0;
|
||||
virtual bool isContradictoryImpl(const Matcher *M) const { return false; }
|
||||
// Highest enum value; watch out when adding more.
|
||||
HighestKind = MorphNodeTo
|
||||
};
|
||||
const KindTy Kind;
|
||||
|
||||
protected:
|
||||
Matcher(KindTy K) : Kind(K) {}
|
||||
|
||||
public:
|
||||
virtual ~Matcher() {}
|
||||
|
||||
unsigned getSize() const { return Size; }
|
||||
void setSize(unsigned sz) { Size = sz; }
|
||||
KindTy getKind() const { return Kind; }
|
||||
|
||||
Matcher *getNext() { return Next.get(); }
|
||||
const Matcher *getNext() const { return Next.get(); }
|
||||
void setNext(Matcher *C) { Next.reset(C); }
|
||||
Matcher *takeNext() { return Next.release(); }
|
||||
|
||||
std::unique_ptr<Matcher> &getNextPtr() { return Next; }
|
||||
|
||||
bool isEqual(const Matcher *M) const {
|
||||
if (getKind() != M->getKind())
|
||||
return false;
|
||||
return isEqualImpl(M);
|
||||
}
|
||||
|
||||
/// isSimplePredicateNode - Return true if this is a simple predicate that
|
||||
/// operates on the node or its children without potential side effects or a
|
||||
/// change of the current node.
|
||||
bool isSimplePredicateNode() const {
|
||||
switch (getKind()) {
|
||||
default:
|
||||
return false;
|
||||
case CheckSame:
|
||||
case CheckChildSame:
|
||||
case CheckPatternPredicate:
|
||||
case CheckPredicate:
|
||||
case CheckOpcode:
|
||||
case CheckType:
|
||||
case CheckChildType:
|
||||
case CheckInteger:
|
||||
case CheckChildInteger:
|
||||
case CheckCondCode:
|
||||
case CheckChild2CondCode:
|
||||
case CheckValueType:
|
||||
case CheckAndImm:
|
||||
case CheckOrImm:
|
||||
case CheckImmAllOnesV:
|
||||
case CheckImmAllZerosV:
|
||||
case CheckFoldableChainNode:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// isSimplePredicateOrRecordNode - Return true if this is a record node or
|
||||
/// a simple predicate.
|
||||
bool isSimplePredicateOrRecordNode() const {
|
||||
return isSimplePredicateNode() || getKind() == RecordNode ||
|
||||
getKind() == RecordChild;
|
||||
}
|
||||
|
||||
/// unlinkNode - Unlink the specified node from this chain. If Other ==
|
||||
/// this, we unlink the next pointer and return it. Otherwise we unlink
|
||||
/// Other from the list and return this.
|
||||
Matcher *unlinkNode(Matcher *Other);
|
||||
|
||||
/// canMoveBefore - Return true if this matcher is the same as Other, or if
|
||||
/// we can move this matcher past all of the nodes in-between Other and this
|
||||
/// node. Other must be equal to or before this.
|
||||
bool canMoveBefore(const Matcher *Other) const;
|
||||
|
||||
/// canMoveBeforeNode - Return true if it is safe to move the current
|
||||
/// matcher across the specified one.
|
||||
bool canMoveBeforeNode(const Matcher *Other) const;
|
||||
|
||||
/// isContradictory - Return true of these two matchers could never match on
|
||||
/// the same node.
|
||||
bool isContradictory(const Matcher *Other) const {
|
||||
// Since this predicate is reflexive, we canonicalize the ordering so that
|
||||
// we always match a node against nodes with kinds that are greater or
|
||||
// equal to them. For example, we'll pass in a CheckType node as an
|
||||
// argument to the CheckOpcode method, not the other way around.
|
||||
if (getKind() < Other->getKind())
|
||||
return isContradictoryImpl(Other);
|
||||
return Other->isContradictoryImpl(this);
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS, unsigned indent = 0) const;
|
||||
void printOne(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
protected:
|
||||
virtual void printImpl(raw_ostream &OS, unsigned indent) const = 0;
|
||||
virtual bool isEqualImpl(const Matcher *M) const = 0;
|
||||
virtual bool isContradictoryImpl(const Matcher *M) const { return false; }
|
||||
};
|
||||
|
||||
/// ScopeMatcher - This attempts to match each of its children to find the first
|
||||
/// one that successfully matches. If one child fails, it tries the next child.
|
||||
/// If none of the children match then this check fails. It never has a 'next'.
|
||||
class ScopeMatcher : public Matcher {
|
||||
SmallVector<Matcher*, 4> Children;
|
||||
SmallVector<Matcher *, 4> Children;
|
||||
|
||||
public:
|
||||
ScopeMatcher(SmallVectorImpl<Matcher *> &&children)
|
||||
: Matcher(Scope), Children(std::move(children)) {}
|
||||
@@ -230,9 +231,7 @@ public:
|
||||
Children.resize(NC);
|
||||
}
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == Scope;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == Scope; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -248,16 +247,15 @@ class RecordMatcher : public Matcher {
|
||||
/// ResultNo - The slot number in the RecordedNodes vector that this will be,
|
||||
/// just printed as a comment.
|
||||
unsigned ResultNo;
|
||||
|
||||
public:
|
||||
RecordMatcher(const std::string &whatfor, unsigned resultNo)
|
||||
: Matcher(RecordNode), WhatFor(whatfor), ResultNo(resultNo) {}
|
||||
: Matcher(RecordNode), WhatFor(whatfor), ResultNo(resultNo) {}
|
||||
|
||||
const std::string &getWhatFor() const { return WhatFor; }
|
||||
unsigned getResultNo() const { return ResultNo; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == RecordNode;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == RecordNode; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -277,19 +275,18 @@ class RecordChildMatcher : public Matcher {
|
||||
/// ResultNo - The slot number in the RecordedNodes vector that this will be,
|
||||
/// just printed as a comment.
|
||||
unsigned ResultNo;
|
||||
|
||||
public:
|
||||
RecordChildMatcher(unsigned childno, const std::string &whatfor,
|
||||
unsigned resultNo)
|
||||
: Matcher(RecordChild), ChildNo(childno), WhatFor(whatfor),
|
||||
ResultNo(resultNo) {}
|
||||
: Matcher(RecordChild), ChildNo(childno), WhatFor(whatfor),
|
||||
ResultNo(resultNo) {}
|
||||
|
||||
unsigned getChildNo() const { return ChildNo; }
|
||||
const std::string &getWhatFor() const { return WhatFor; }
|
||||
unsigned getResultNo() const { return ResultNo; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == RecordChild;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == RecordChild; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -303,16 +300,13 @@ class RecordMemRefMatcher : public Matcher {
|
||||
public:
|
||||
RecordMemRefMatcher() : Matcher(RecordMemRef) {}
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == RecordMemRef;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == RecordMemRef; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
bool isEqualImpl(const Matcher *M) const override { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// CaptureGlueInputMatcher - If the current record has a glue input, record
|
||||
/// it so that it is used as an input to the generated code.
|
||||
class CaptureGlueInputMatcher : public Matcher {
|
||||
@@ -332,14 +326,13 @@ private:
|
||||
/// specified child node.
|
||||
class MoveChildMatcher : public Matcher {
|
||||
unsigned ChildNo;
|
||||
|
||||
public:
|
||||
MoveChildMatcher(unsigned childNo) : Matcher(MoveChild), ChildNo(childNo) {}
|
||||
|
||||
unsigned getChildNo() const { return ChildNo; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == MoveChild;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == MoveChild; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -374,9 +367,7 @@ class MoveParentMatcher : public Matcher {
|
||||
public:
|
||||
MoveParentMatcher() : Matcher(MoveParent) {}
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == MoveParent;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == MoveParent; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -388,15 +379,14 @@ private:
|
||||
/// when patterns have the same name in them, like '(mul GPR:$in, GPR:$in)'.
|
||||
class CheckSameMatcher : public Matcher {
|
||||
unsigned MatchNumber;
|
||||
|
||||
public:
|
||||
CheckSameMatcher(unsigned matchnumber)
|
||||
: Matcher(CheckSame), MatchNumber(matchnumber) {}
|
||||
: Matcher(CheckSame), MatchNumber(matchnumber) {}
|
||||
|
||||
unsigned getMatchNumber() const { return MatchNumber; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == CheckSame;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == CheckSame; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -411,9 +401,10 @@ private:
|
||||
class CheckChildSameMatcher : public Matcher {
|
||||
unsigned ChildNo;
|
||||
unsigned MatchNumber;
|
||||
|
||||
public:
|
||||
CheckChildSameMatcher(unsigned childno, unsigned matchnumber)
|
||||
: Matcher(CheckChildSame), ChildNo(childno), MatchNumber(matchnumber) {}
|
||||
: Matcher(CheckChildSame), ChildNo(childno), MatchNumber(matchnumber) {}
|
||||
|
||||
unsigned getChildNo() const { return ChildNo; }
|
||||
unsigned getMatchNumber() const { return MatchNumber; }
|
||||
@@ -435,9 +426,10 @@ private:
|
||||
/// not take a node as input. This is used for subtarget feature checks etc.
|
||||
class CheckPatternPredicateMatcher : public Matcher {
|
||||
std::string Predicate;
|
||||
|
||||
public:
|
||||
CheckPatternPredicateMatcher(StringRef predicate)
|
||||
: Matcher(CheckPatternPredicate), Predicate(predicate) {}
|
||||
: Matcher(CheckPatternPredicate), Predicate(predicate) {}
|
||||
|
||||
StringRef getPredicate() const { return Predicate; }
|
||||
|
||||
@@ -457,6 +449,7 @@ private:
|
||||
class CheckPredicateMatcher : public Matcher {
|
||||
TreePattern *Pred;
|
||||
const SmallVector<unsigned, 4> Operands;
|
||||
|
||||
public:
|
||||
CheckPredicateMatcher(const TreePredicateFn &pred,
|
||||
const SmallVectorImpl<unsigned> &Operands);
|
||||
@@ -476,20 +469,18 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// CheckOpcodeMatcher - This checks to see if the current node has the
|
||||
/// specified opcode, if not it fails to match.
|
||||
class CheckOpcodeMatcher : public Matcher {
|
||||
const SDNodeInfo &Opcode;
|
||||
|
||||
public:
|
||||
CheckOpcodeMatcher(const SDNodeInfo &opcode)
|
||||
: Matcher(CheckOpcode), Opcode(opcode) {}
|
||||
: Matcher(CheckOpcode), Opcode(opcode) {}
|
||||
|
||||
const SDNodeInfo &getOpcode() const { return Opcode; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == CheckOpcode;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == CheckOpcode; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -502,16 +493,15 @@ private:
|
||||
/// then the match fails. This is semantically equivalent to a Scope node where
|
||||
/// every child does a CheckOpcode, but is much faster.
|
||||
class SwitchOpcodeMatcher : public Matcher {
|
||||
SmallVector<std::pair<const SDNodeInfo*, Matcher*>, 8> Cases;
|
||||
SmallVector<std::pair<const SDNodeInfo *, Matcher *>, 8> Cases;
|
||||
|
||||
public:
|
||||
SwitchOpcodeMatcher(
|
||||
SmallVectorImpl<std::pair<const SDNodeInfo *, Matcher *>> &&cases)
|
||||
: Matcher(SwitchOpcode), Cases(std::move(cases)) {}
|
||||
~SwitchOpcodeMatcher() override;
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == SwitchOpcode;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == SwitchOpcode; }
|
||||
|
||||
unsigned getNumCases() const { return Cases.size(); }
|
||||
|
||||
@@ -529,16 +519,15 @@ private:
|
||||
class CheckTypeMatcher : public Matcher {
|
||||
MVT::SimpleValueType Type;
|
||||
unsigned ResNo;
|
||||
|
||||
public:
|
||||
CheckTypeMatcher(MVT::SimpleValueType type, unsigned resno)
|
||||
: Matcher(CheckType), Type(type), ResNo(resno) {}
|
||||
: Matcher(CheckType), Type(type), ResNo(resno) {}
|
||||
|
||||
MVT::SimpleValueType getType() const { return Type; }
|
||||
unsigned getResNo() const { return ResNo; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == CheckType;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == CheckType; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -553,16 +542,15 @@ private:
|
||||
/// then the match fails. This is semantically equivalent to a Scope node where
|
||||
/// every child does a CheckType, but is much faster.
|
||||
class SwitchTypeMatcher : public Matcher {
|
||||
SmallVector<std::pair<MVT::SimpleValueType, Matcher*>, 8> Cases;
|
||||
SmallVector<std::pair<MVT::SimpleValueType, Matcher *>, 8> Cases;
|
||||
|
||||
public:
|
||||
SwitchTypeMatcher(
|
||||
SmallVectorImpl<std::pair<MVT::SimpleValueType, Matcher *>> &&cases)
|
||||
: Matcher(SwitchType), Cases(std::move(cases)) {}
|
||||
~SwitchTypeMatcher() override;
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == SwitchType;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == SwitchType; }
|
||||
|
||||
unsigned getNumCases() const { return Cases.size(); }
|
||||
|
||||
@@ -575,15 +563,15 @@ private:
|
||||
bool isEqualImpl(const Matcher *M) const override { return false; }
|
||||
};
|
||||
|
||||
|
||||
/// CheckChildTypeMatcher - This checks to see if a child node has the
|
||||
/// specified type, if not it fails to match.
|
||||
class CheckChildTypeMatcher : public Matcher {
|
||||
unsigned ChildNo;
|
||||
MVT::SimpleValueType Type;
|
||||
|
||||
public:
|
||||
CheckChildTypeMatcher(unsigned childno, MVT::SimpleValueType type)
|
||||
: Matcher(CheckChildType), ChildNo(childno), Type(type) {}
|
||||
: Matcher(CheckChildType), ChildNo(childno), Type(type) {}
|
||||
|
||||
unsigned getChildNo() const { return ChildNo; }
|
||||
MVT::SimpleValueType getType() const { return Type; }
|
||||
@@ -601,20 +589,17 @@ private:
|
||||
bool isContradictoryImpl(const Matcher *M) const override;
|
||||
};
|
||||
|
||||
|
||||
/// CheckIntegerMatcher - This checks to see if the current node is a
|
||||
/// ConstantSDNode with the specified integer value, if not it fails to match.
|
||||
class CheckIntegerMatcher : public Matcher {
|
||||
int64_t Value;
|
||||
|
||||
public:
|
||||
CheckIntegerMatcher(int64_t value)
|
||||
: Matcher(CheckInteger), Value(value) {}
|
||||
CheckIntegerMatcher(int64_t value) : Matcher(CheckInteger), Value(value) {}
|
||||
|
||||
int64_t getValue() const { return Value; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == CheckInteger;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == CheckInteger; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -629,9 +614,10 @@ private:
|
||||
class CheckChildIntegerMatcher : public Matcher {
|
||||
unsigned ChildNo;
|
||||
int64_t Value;
|
||||
|
||||
public:
|
||||
CheckChildIntegerMatcher(unsigned childno, int64_t value)
|
||||
: Matcher(CheckChildInteger), ChildNo(childno), Value(value) {}
|
||||
: Matcher(CheckChildInteger), ChildNo(childno), Value(value) {}
|
||||
|
||||
unsigned getChildNo() const { return ChildNo; }
|
||||
int64_t getValue() const { return Value; }
|
||||
@@ -653,9 +639,10 @@ private:
|
||||
/// CondCodeSDNode with the specified condition, if not it fails to match.
|
||||
class CheckCondCodeMatcher : public Matcher {
|
||||
StringRef CondCodeName;
|
||||
|
||||
public:
|
||||
CheckCondCodeMatcher(StringRef condcodename)
|
||||
: Matcher(CheckCondCode), CondCodeName(condcodename) {}
|
||||
: Matcher(CheckCondCode), CondCodeName(condcodename) {}
|
||||
|
||||
StringRef getCondCodeName() const { return CondCodeName; }
|
||||
|
||||
@@ -675,9 +662,10 @@ private:
|
||||
/// CondCodeSDNode with the specified condition, if not it fails to match.
|
||||
class CheckChild2CondCodeMatcher : public Matcher {
|
||||
StringRef CondCodeName;
|
||||
|
||||
public:
|
||||
CheckChild2CondCodeMatcher(StringRef condcodename)
|
||||
: Matcher(CheckChild2CondCode), CondCodeName(condcodename) {}
|
||||
: Matcher(CheckChild2CondCode), CondCodeName(condcodename) {}
|
||||
|
||||
StringRef getCondCodeName() const { return CondCodeName; }
|
||||
|
||||
@@ -697,9 +685,10 @@ private:
|
||||
/// VTSDNode with the specified type, if not it fails to match.
|
||||
class CheckValueTypeMatcher : public Matcher {
|
||||
StringRef TypeName;
|
||||
|
||||
public:
|
||||
CheckValueTypeMatcher(StringRef type_name)
|
||||
: Matcher(CheckValueType), TypeName(type_name) {}
|
||||
: Matcher(CheckValueType), TypeName(type_name) {}
|
||||
|
||||
StringRef getTypeName() const { return TypeName; }
|
||||
|
||||
@@ -715,8 +704,6 @@ private:
|
||||
bool isContradictoryImpl(const Matcher *M) const override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// CheckComplexPatMatcher - This node runs the specified ComplexPattern on
|
||||
/// the current node.
|
||||
class CheckComplexPatMatcher : public Matcher {
|
||||
@@ -732,11 +719,12 @@ class CheckComplexPatMatcher : public Matcher {
|
||||
/// FirstResult - This is the first slot in the RecordedNodes list that the
|
||||
/// result of the match populates.
|
||||
unsigned FirstResult;
|
||||
|
||||
public:
|
||||
CheckComplexPatMatcher(const ComplexPattern &pattern, unsigned matchnumber,
|
||||
const std::string &name, unsigned firstresult)
|
||||
: Matcher(CheckComplexPat), Pattern(pattern), MatchNumber(matchnumber),
|
||||
Name(name), FirstResult(firstresult) {}
|
||||
: Matcher(CheckComplexPat), Pattern(pattern), MatchNumber(matchnumber),
|
||||
Name(name), FirstResult(firstresult) {}
|
||||
|
||||
const ComplexPattern &getPattern() const { return Pattern; }
|
||||
unsigned getMatchNumber() const { return MatchNumber; }
|
||||
@@ -760,15 +748,13 @@ private:
|
||||
/// with something equivalent to the specified immediate.
|
||||
class CheckAndImmMatcher : public Matcher {
|
||||
int64_t Value;
|
||||
|
||||
public:
|
||||
CheckAndImmMatcher(int64_t value)
|
||||
: Matcher(CheckAndImm), Value(value) {}
|
||||
CheckAndImmMatcher(int64_t value) : Matcher(CheckAndImm), Value(value) {}
|
||||
|
||||
int64_t getValue() const { return Value; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == CheckAndImm;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == CheckAndImm; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -781,15 +767,13 @@ private:
|
||||
/// with something equivalent to the specified immediate.
|
||||
class CheckOrImmMatcher : public Matcher {
|
||||
int64_t Value;
|
||||
|
||||
public:
|
||||
CheckOrImmMatcher(int64_t value)
|
||||
: Matcher(CheckOrImm), Value(value) {}
|
||||
CheckOrImmMatcher(int64_t value) : Matcher(CheckOrImm), Value(value) {}
|
||||
|
||||
int64_t getValue() const { return Value; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == CheckOrImm;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == CheckOrImm; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -834,8 +818,7 @@ private:
|
||||
/// (which defines a chain operand) is safe to fold into a larger pattern.
|
||||
class CheckFoldableChainNodeMatcher : public Matcher {
|
||||
public:
|
||||
CheckFoldableChainNodeMatcher()
|
||||
: Matcher(CheckFoldableChainNode) {}
|
||||
CheckFoldableChainNodeMatcher() : Matcher(CheckFoldableChainNode) {}
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == CheckFoldableChainNode;
|
||||
@@ -850,16 +833,15 @@ private:
|
||||
class EmitIntegerMatcher : public Matcher {
|
||||
int64_t Val;
|
||||
MVT::SimpleValueType VT;
|
||||
|
||||
public:
|
||||
EmitIntegerMatcher(int64_t val, MVT::SimpleValueType vt)
|
||||
: Matcher(EmitInteger), Val(val), VT(vt) {}
|
||||
: Matcher(EmitInteger), Val(val), VT(vt) {}
|
||||
|
||||
int64_t getValue() const { return Val; }
|
||||
MVT::SimpleValueType getVT() const { return VT; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == EmitInteger;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == EmitInteger; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -874,9 +856,10 @@ private:
|
||||
class EmitStringIntegerMatcher : public Matcher {
|
||||
std::string Val;
|
||||
MVT::SimpleValueType VT;
|
||||
|
||||
public:
|
||||
EmitStringIntegerMatcher(const std::string &val, MVT::SimpleValueType vt)
|
||||
: Matcher(EmitStringInteger), Val(val), VT(vt) {}
|
||||
: Matcher(EmitStringInteger), Val(val), VT(vt) {}
|
||||
|
||||
const std::string &getValue() const { return Val; }
|
||||
MVT::SimpleValueType getVT() const { return VT; }
|
||||
@@ -899,16 +882,15 @@ class EmitRegisterMatcher : public Matcher {
|
||||
/// this is a reference to zero_reg.
|
||||
const CodeGenRegister *Reg;
|
||||
MVT::SimpleValueType VT;
|
||||
|
||||
public:
|
||||
EmitRegisterMatcher(const CodeGenRegister *reg, MVT::SimpleValueType vt)
|
||||
: Matcher(EmitRegister), Reg(reg), VT(vt) {}
|
||||
: Matcher(EmitRegister), Reg(reg), VT(vt) {}
|
||||
|
||||
const CodeGenRegister *getReg() const { return Reg; }
|
||||
MVT::SimpleValueType getVT() const { return VT; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == EmitRegister;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == EmitRegister; }
|
||||
|
||||
private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
@@ -923,9 +905,10 @@ private:
|
||||
/// ISD::TargetConstant, likewise for ConstantFP.
|
||||
class EmitConvertToTargetMatcher : public Matcher {
|
||||
unsigned Slot;
|
||||
|
||||
public:
|
||||
EmitConvertToTargetMatcher(unsigned slot)
|
||||
: Matcher(EmitConvertToTarget), Slot(slot) {}
|
||||
: Matcher(EmitConvertToTarget), Slot(slot) {}
|
||||
|
||||
unsigned getSlot() const { return Slot; }
|
||||
|
||||
@@ -946,9 +929,10 @@ private:
|
||||
/// chains of these nodes if they are not themselves a node in the pattern.
|
||||
class EmitMergeInputChainsMatcher : public Matcher {
|
||||
SmallVector<unsigned, 3> ChainNodes;
|
||||
|
||||
public:
|
||||
EmitMergeInputChainsMatcher(ArrayRef<unsigned> nodes)
|
||||
: Matcher(EmitMergeInputChains), ChainNodes(nodes.begin(), nodes.end()) {}
|
||||
: Matcher(EmitMergeInputChains), ChainNodes(nodes.begin(), nodes.end()) {}
|
||||
|
||||
unsigned getNumNodes() const { return ChainNodes.size(); }
|
||||
|
||||
@@ -976,9 +960,8 @@ class EmitCopyToRegMatcher : public Matcher {
|
||||
const CodeGenRegister *DestPhysReg;
|
||||
|
||||
public:
|
||||
EmitCopyToRegMatcher(unsigned srcSlot,
|
||||
const CodeGenRegister *destPhysReg)
|
||||
: Matcher(EmitCopyToReg), SrcSlot(srcSlot), DestPhysReg(destPhysReg) {}
|
||||
EmitCopyToRegMatcher(unsigned srcSlot, const CodeGenRegister *destPhysReg)
|
||||
: Matcher(EmitCopyToReg), SrcSlot(srcSlot), DestPhysReg(destPhysReg) {}
|
||||
|
||||
unsigned getSrcSlot() const { return SrcSlot; }
|
||||
const CodeGenRegister *getDestPhysReg() const { return DestPhysReg; }
|
||||
@@ -995,16 +978,15 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// EmitNodeXFormMatcher - Emit an operation that runs an SDNodeXForm on a
|
||||
/// recorded node and records the result.
|
||||
class EmitNodeXFormMatcher : public Matcher {
|
||||
unsigned Slot;
|
||||
Record *NodeXForm;
|
||||
|
||||
public:
|
||||
EmitNodeXFormMatcher(unsigned slot, Record *nodeXForm)
|
||||
: Matcher(EmitNodeXForm), Slot(slot), NodeXForm(nodeXForm) {}
|
||||
: Matcher(EmitNodeXForm), Slot(slot), NodeXForm(nodeXForm) {}
|
||||
|
||||
unsigned getSlot() const { return Slot; }
|
||||
Record *getNodeXForm() const { return NodeXForm; }
|
||||
@@ -1033,6 +1015,7 @@ class EmitNodeMatcherCommon : public Matcher {
|
||||
/// If this is a varidic node, this is set to the number of fixed arity
|
||||
/// operands in the root of the pattern. The rest are appended to this node.
|
||||
int NumFixedArityOperands;
|
||||
|
||||
public:
|
||||
EmitNodeMatcherCommon(const CodeGenInstruction &cgi,
|
||||
ArrayRef<MVT::SimpleValueType> vts,
|
||||
@@ -1061,7 +1044,6 @@ public:
|
||||
const SmallVectorImpl<MVT::SimpleValueType> &getVTList() const { return VTs; }
|
||||
const SmallVectorImpl<unsigned> &getOperandList() const { return Operands; }
|
||||
|
||||
|
||||
bool hasChain() const { return HasChain; }
|
||||
bool hasInGlue() const { return HasInGlue; }
|
||||
bool hasOutGlue() const { return HasOutGlue; }
|
||||
@@ -1081,6 +1063,7 @@ private:
|
||||
class EmitNodeMatcher : public EmitNodeMatcherCommon {
|
||||
void anchor() override;
|
||||
unsigned FirstResultSlot;
|
||||
|
||||
public:
|
||||
EmitNodeMatcher(const CodeGenInstruction &cgi,
|
||||
ArrayRef<MVT::SimpleValueType> vts,
|
||||
@@ -1094,15 +1077,13 @@ public:
|
||||
|
||||
unsigned getFirstResultSlot() const { return FirstResultSlot; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == EmitNode;
|
||||
}
|
||||
|
||||
static bool classof(const Matcher *N) { return N->getKind() == EmitNode; }
|
||||
};
|
||||
|
||||
class MorphNodeToMatcher : public EmitNodeMatcherCommon {
|
||||
void anchor() override;
|
||||
const PatternToMatch &Pattern;
|
||||
|
||||
public:
|
||||
MorphNodeToMatcher(const CodeGenInstruction &cgi,
|
||||
ArrayRef<MVT::SimpleValueType> vts,
|
||||
@@ -1116,9 +1097,7 @@ public:
|
||||
|
||||
const PatternToMatch &getPattern() const { return Pattern; }
|
||||
|
||||
static bool classof(const Matcher *N) {
|
||||
return N->getKind() == MorphNodeTo;
|
||||
}
|
||||
static bool classof(const Matcher *N) { return N->getKind() == MorphNodeTo; }
|
||||
};
|
||||
|
||||
/// CompleteMatchMatcher - Complete a match by replacing the results of the
|
||||
@@ -1127,11 +1106,12 @@ public:
|
||||
class CompleteMatchMatcher : public Matcher {
|
||||
SmallVector<unsigned, 2> Results;
|
||||
const PatternToMatch &Pattern;
|
||||
|
||||
public:
|
||||
CompleteMatchMatcher(ArrayRef<unsigned> results,
|
||||
const PatternToMatch &pattern)
|
||||
: Matcher(CompleteMatch), Results(results.begin(), results.end()),
|
||||
Pattern(pattern) {}
|
||||
: Matcher(CompleteMatch), Results(results.begin(), results.end()),
|
||||
Pattern(pattern) {}
|
||||
|
||||
unsigned getNumResults() const { return Results.size(); }
|
||||
unsigned getResult(unsigned R) const { return Results[R]; }
|
||||
@@ -1145,7 +1125,7 @@ private:
|
||||
void printImpl(raw_ostream &OS, unsigned indent) const override;
|
||||
bool isEqualImpl(const Matcher *M) const override {
|
||||
return cast<CompleteMatchMatcher>(M)->Results == Results &&
|
||||
&cast<CompleteMatchMatcher>(M)->Pattern == &Pattern;
|
||||
&cast<CompleteMatchMatcher>(M)->Pattern == &Pattern;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace {
|
||||
class MatcherTableEmitter {
|
||||
const CodeGenDAGPatterns &CGP;
|
||||
|
||||
SmallVector<unsigned, Matcher::HighestKind+1> OpcodeCounts;
|
||||
SmallVector<unsigned, Matcher::HighestKind + 1> OpcodeCounts;
|
||||
|
||||
std::vector<TreePattern *> NodePredicates;
|
||||
std::vector<TreePattern *> NodePredicatesWithOperands;
|
||||
@@ -62,14 +62,13 @@ class MatcherTableEmitter {
|
||||
|
||||
std::vector<std::string> PatternPredicates;
|
||||
|
||||
std::vector<const ComplexPattern*> ComplexPatterns;
|
||||
std::vector<const ComplexPattern *> ComplexPatterns;
|
||||
|
||||
|
||||
DenseMap<Record*, unsigned> NodeXFormMap;
|
||||
std::vector<Record*> NodeXForms;
|
||||
DenseMap<Record *, unsigned> NodeXFormMap;
|
||||
std::vector<Record *> NodeXForms;
|
||||
|
||||
std::vector<std::string> VecIncludeStrings;
|
||||
MapVector<std::string, unsigned, StringMap<unsigned> > VecPatterns;
|
||||
MapVector<std::string, unsigned, StringMap<unsigned>> VecPatterns;
|
||||
|
||||
unsigned getPatternIdxFromTable(std::string &&P, std::string &&include_loc) {
|
||||
const auto It = VecPatterns.find(P);
|
||||
@@ -184,8 +183,8 @@ private:
|
||||
|
||||
unsigned SizeMatcher(Matcher *N, raw_ostream &OS);
|
||||
|
||||
unsigned EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
raw_ostream &OS);
|
||||
unsigned EmitMatcher(const Matcher *N, const unsigned Indent,
|
||||
unsigned CurrentIdx, raw_ostream &OS);
|
||||
|
||||
unsigned getNodePredicate(TreePredicateFn Pred) {
|
||||
// We use the first predicate.
|
||||
@@ -210,9 +209,8 @@ private:
|
||||
NodeXForms.push_back(Rec);
|
||||
Entry = NodeXForms.size();
|
||||
}
|
||||
return Entry-1;
|
||||
return Entry - 1;
|
||||
}
|
||||
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
@@ -224,14 +222,15 @@ static std::string GetPatFromTreePatternNode(const TreePatternNode *N) {
|
||||
}
|
||||
|
||||
static unsigned GetVBRSize(unsigned Val) {
|
||||
if (Val <= 127) return 1;
|
||||
if (Val <= 127)
|
||||
return 1;
|
||||
|
||||
unsigned NumBytes = 0;
|
||||
while (Val >= 128) {
|
||||
Val >>= 7;
|
||||
++NumBytes;
|
||||
}
|
||||
return NumBytes+1;
|
||||
return NumBytes + 1;
|
||||
}
|
||||
|
||||
/// EmitVBRValue - Emit the specified value as a VBR, returning the number of
|
||||
@@ -245,7 +244,7 @@ static unsigned EmitVBRValue(uint64_t Val, raw_ostream &OS) {
|
||||
uint64_t InVal = Val;
|
||||
unsigned NumBytes = 0;
|
||||
while (Val >= 128) {
|
||||
OS << (Val&127) << "|128,";
|
||||
OS << (Val & 127) << "|128,";
|
||||
Val >>= 7;
|
||||
++NumBytes;
|
||||
}
|
||||
@@ -253,7 +252,7 @@ static unsigned EmitVBRValue(uint64_t Val, raw_ostream &OS) {
|
||||
if (!OmitComments)
|
||||
OS << "/*" << InVal << "*/";
|
||||
OS << ", ";
|
||||
return NumBytes+1;
|
||||
return NumBytes + 1;
|
||||
}
|
||||
|
||||
/// Emit the specified signed value as a VBR. To improve compression we encode
|
||||
@@ -290,8 +289,7 @@ static std::string getIncludePath(const Record *R) {
|
||||
|
||||
/// This function traverses the matcher tree and sizes all the nodes
|
||||
/// that are children of the three kinds of nodes that have them.
|
||||
unsigned MatcherTableEmitter::
|
||||
SizeMatcherList(Matcher *N, raw_ostream &OS) {
|
||||
unsigned MatcherTableEmitter::SizeMatcherList(Matcher *N, raw_ostream &OS) {
|
||||
unsigned Size = 0;
|
||||
while (N) {
|
||||
Size += SizeMatcher(N, OS);
|
||||
@@ -303,8 +301,7 @@ SizeMatcherList(Matcher *N, raw_ostream &OS) {
|
||||
/// This function sizes the children of the three kinds of nodes that
|
||||
/// have them. It does so by using special cases for those three
|
||||
/// nodes, but sharing the code in EmitMatcher() for the other kinds.
|
||||
unsigned MatcherTableEmitter::
|
||||
SizeMatcher(Matcher *N, raw_ostream &OS) {
|
||||
unsigned MatcherTableEmitter::SizeMatcher(Matcher *N, raw_ostream &OS) {
|
||||
unsigned Idx = 0;
|
||||
|
||||
++OpcodeCounts[N->getKind()];
|
||||
@@ -389,7 +386,7 @@ void MatcherTableEmitter::EmitPatternMatchTable(raw_ostream &OS) {
|
||||
"The sizes of Pattern and include vectors should be the same");
|
||||
|
||||
BeginEmitFunction(OS, "StringRef", "getPatternForIndex(unsigned Index)",
|
||||
true/*AddOverride*/);
|
||||
true /*AddOverride*/);
|
||||
OS << "{\n";
|
||||
OS << "static const char *PATTERN_MATCH_TABLE[] = {\n";
|
||||
|
||||
@@ -403,7 +400,7 @@ void MatcherTableEmitter::EmitPatternMatchTable(raw_ostream &OS) {
|
||||
EndEmitFunction(OS);
|
||||
|
||||
BeginEmitFunction(OS, "StringRef", "getIncludePathForIndex(unsigned Index)",
|
||||
true/*AddOverride*/);
|
||||
true /*AddOverride*/);
|
||||
OS << "{\n";
|
||||
OS << "static const char *INCLUDE_PATH_TABLE[] = {\n";
|
||||
|
||||
@@ -419,9 +416,10 @@ void MatcherTableEmitter::EmitPatternMatchTable(raw_ostream &OS) {
|
||||
|
||||
/// EmitMatcher - Emit bytes for the specified matcher and return
|
||||
/// the number of bytes emitted.
|
||||
unsigned MatcherTableEmitter::
|
||||
EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
raw_ostream &OS) {
|
||||
unsigned MatcherTableEmitter::EmitMatcher(const Matcher *N,
|
||||
const unsigned Indent,
|
||||
unsigned CurrentIdx,
|
||||
raw_ostream &OS) {
|
||||
OS.indent(Indent);
|
||||
|
||||
switch (N->getKind()) {
|
||||
@@ -434,7 +432,7 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
if (i == 0) {
|
||||
OS << "OPC_Scope, ";
|
||||
++CurrentIdx;
|
||||
} else {
|
||||
} else {
|
||||
if (!OmitComments) {
|
||||
OS << "/*" << format_decimal(CurrentIdx, IndexWidth) << "*/";
|
||||
OS.indent(Indent) << "/*Scope*/ ";
|
||||
@@ -451,7 +449,7 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
}
|
||||
OS << '\n';
|
||||
|
||||
ChildSize = EmitMatcherList(SM->getChild(i), Indent+1,
|
||||
ChildSize = EmitMatcherList(SM->getChild(i), Indent + 1,
|
||||
CurrentIdx + VBRSize, OS);
|
||||
assert(ChildSize == SM->getChild(i)->getSize() &&
|
||||
"Emitted child size does not match calculated size");
|
||||
@@ -471,18 +469,15 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
case Matcher::RecordNode:
|
||||
OS << "OPC_RecordNode,";
|
||||
if (!OmitComments)
|
||||
OS << " // #"
|
||||
<< cast<RecordMatcher>(N)->getResultNo() << " = "
|
||||
OS << " // #" << cast<RecordMatcher>(N)->getResultNo() << " = "
|
||||
<< cast<RecordMatcher>(N)->getWhatFor();
|
||||
OS << '\n';
|
||||
return 1;
|
||||
|
||||
case Matcher::RecordChild:
|
||||
OS << "OPC_RecordChild" << cast<RecordChildMatcher>(N)->getChildNo()
|
||||
<< ',';
|
||||
OS << "OPC_RecordChild" << cast<RecordChildMatcher>(N)->getChildNo() << ',';
|
||||
if (!OmitComments)
|
||||
OS << " // #"
|
||||
<< cast<RecordChildMatcher>(N)->getResultNo() << " = "
|
||||
OS << " // #" << cast<RecordChildMatcher>(N)->getResultNo() << " = "
|
||||
<< cast<RecordChildMatcher>(N)->getWhatFor();
|
||||
OS << '\n';
|
||||
return 1;
|
||||
@@ -522,14 +517,13 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
return 1;
|
||||
|
||||
case Matcher::CheckSame:
|
||||
OS << "OPC_CheckSame, "
|
||||
<< cast<CheckSameMatcher>(N)->getMatchNumber() << ",\n";
|
||||
OS << "OPC_CheckSame, " << cast<CheckSameMatcher>(N)->getMatchNumber()
|
||||
<< ",\n";
|
||||
return 2;
|
||||
|
||||
case Matcher::CheckChildSame:
|
||||
OS << "OPC_CheckChild"
|
||||
<< cast<CheckChildSameMatcher>(N)->getChildNo() << "Same, "
|
||||
<< cast<CheckChildSameMatcher>(N)->getMatchNumber() << ",\n";
|
||||
OS << "OPC_CheckChild" << cast<CheckChildSameMatcher>(N)->getChildNo()
|
||||
<< "Same, " << cast<CheckChildSameMatcher>(N)->getMatchNumber() << ",\n";
|
||||
return 2;
|
||||
|
||||
case Matcher::CheckPatternPredicate: {
|
||||
@@ -602,10 +596,10 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
unsigned IdxSize;
|
||||
if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N)) {
|
||||
Child = SOM->getCaseMatcher(i);
|
||||
IdxSize = 2; // size of opcode in table is 2 bytes.
|
||||
IdxSize = 2; // size of opcode in table is 2 bytes.
|
||||
} else {
|
||||
Child = cast<SwitchTypeMatcher>(N)->getCaseMatcher(i);
|
||||
IdxSize = 1; // size of type in table is 1 byte.
|
||||
IdxSize = 1; // size of type in table is 1 byte.
|
||||
}
|
||||
|
||||
if (i != 0) {
|
||||
@@ -613,8 +607,8 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
OS << "/*" << format_decimal(CurrentIdx, IndexWidth) << "*/";
|
||||
OS.indent(Indent);
|
||||
if (!OmitComments)
|
||||
OS << (isa<SwitchOpcodeMatcher>(N) ?
|
||||
"/*SwitchOpcode*/ " : "/*SwitchType*/ ");
|
||||
OS << (isa<SwitchOpcodeMatcher>(N) ? "/*SwitchOpcode*/ "
|
||||
: "/*SwitchType*/ ");
|
||||
}
|
||||
|
||||
unsigned ChildSize = Child->getSize();
|
||||
@@ -627,7 +621,7 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
OS << "// ->" << CurrentIdx + ChildSize;
|
||||
OS << '\n';
|
||||
|
||||
ChildSize = EmitMatcherList(Child, Indent+1, CurrentIdx, OS);
|
||||
ChildSize = EmitMatcherList(Child, Indent + 1, CurrentIdx, OS);
|
||||
assert(ChildSize == Child->getSize() &&
|
||||
"Emitted child size does not match calculated size");
|
||||
CurrentIdx += ChildSize;
|
||||
@@ -638,8 +632,8 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
OS << "/*" << format_decimal(CurrentIdx, IndexWidth) << "*/";
|
||||
OS.indent(Indent) << "0,";
|
||||
if (!OmitComments)
|
||||
OS << (isa<SwitchOpcodeMatcher>(N) ?
|
||||
" // EndSwitchOpcode" : " // EndSwitchType");
|
||||
OS << (isa<SwitchOpcodeMatcher>(N) ? " // EndSwitchOpcode"
|
||||
: " // EndSwitchType");
|
||||
|
||||
OS << '\n';
|
||||
return CurrentIdx - StartIdx + 1;
|
||||
@@ -722,7 +716,7 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
OS << " // " << Pattern.getSelectFunc();
|
||||
OS << ":$" << CCPM->getName();
|
||||
for (unsigned i = 0, e = Pattern.getNumOperands(); i != e; ++i)
|
||||
OS << " #" << CCPM->getFirstResult()+i;
|
||||
OS << " #" << CCPM->getFirstResult() + i;
|
||||
|
||||
if (Pattern.hasProperty(SDNPHasChain))
|
||||
OS << " + chain result";
|
||||
@@ -733,14 +727,16 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
|
||||
case Matcher::CheckAndImm: {
|
||||
OS << "OPC_CheckAndImm, ";
|
||||
unsigned Bytes=1+EmitVBRValue(cast<CheckAndImmMatcher>(N)->getValue(), OS);
|
||||
unsigned Bytes =
|
||||
1 + EmitVBRValue(cast<CheckAndImmMatcher>(N)->getValue(), OS);
|
||||
OS << '\n';
|
||||
return Bytes;
|
||||
}
|
||||
|
||||
case Matcher::CheckOrImm: {
|
||||
OS << "OPC_CheckOrImm, ";
|
||||
unsigned Bytes = 1+EmitVBRValue(cast<CheckOrImmMatcher>(N)->getValue(), OS);
|
||||
unsigned Bytes =
|
||||
1 + EmitVBRValue(cast<CheckOrImmMatcher>(N)->getValue(), OS);
|
||||
OS << '\n';
|
||||
return Bytes;
|
||||
}
|
||||
@@ -843,7 +839,7 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
|
||||
case Matcher::EmitMergeInputChains: {
|
||||
const EmitMergeInputChainsMatcher *MN =
|
||||
cast<EmitMergeInputChainsMatcher>(N);
|
||||
cast<EmitMergeInputChainsMatcher>(N);
|
||||
|
||||
// Handle the specialized forms OPC_EmitMergeInputChains1_0, 1_1, and 1_2.
|
||||
if (MN->getNumNodes() == 1 && MN->getNode(0) < 3) {
|
||||
@@ -855,7 +851,7 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
for (unsigned i = 0, e = MN->getNumNodes(); i != e; ++i)
|
||||
OS << MN->getNode(i) << ", ";
|
||||
OS << '\n';
|
||||
return 2+MN->getNumNodes();
|
||||
return 2 + MN->getNumNodes();
|
||||
}
|
||||
case Matcher::EmitCopyToReg: {
|
||||
const auto *C2RMatcher = cast<EmitCopyToRegMatcher>(N);
|
||||
@@ -884,8 +880,8 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
OS << "OPC_EmitNodeXForm, " << getNodeXFormID(XF->getNodeXForm()) << ", "
|
||||
<< XF->getSlot() << ',';
|
||||
if (!OmitComments)
|
||||
OS << " // "<<XF->getNodeXForm()->getName();
|
||||
OS <<'\n';
|
||||
OS << " // " << XF->getNodeXForm()->getName();
|
||||
OS << '\n';
|
||||
return 3;
|
||||
}
|
||||
|
||||
@@ -955,7 +951,7 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
}
|
||||
OS << ",\n";
|
||||
|
||||
OS.indent(FullIndexWidth + Indent+4);
|
||||
OS.indent(FullIndexWidth + Indent + 4);
|
||||
if (!CompressVTs) {
|
||||
OS << EN->getNumVTs();
|
||||
if (!OmitComments)
|
||||
@@ -980,17 +976,18 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
OS << " // Results =";
|
||||
unsigned First = E->getFirstResultSlot();
|
||||
for (unsigned i = 0; i != NumResults; ++i)
|
||||
OS << " #" << First+i;
|
||||
OS << " #" << First + i;
|
||||
}
|
||||
}
|
||||
OS << '\n';
|
||||
|
||||
if (const MorphNodeToMatcher *SNT = dyn_cast<MorphNodeToMatcher>(N)) {
|
||||
OS.indent(FullIndexWidth + Indent) << "// Src: "
|
||||
<< *SNT->getPattern().getSrcPattern() << " - Complexity = "
|
||||
<< SNT->getPattern().getPatternComplexity(CGP) << '\n';
|
||||
OS.indent(FullIndexWidth + Indent) << "// Dst: "
|
||||
<< *SNT->getPattern().getDstPattern() << '\n';
|
||||
OS.indent(FullIndexWidth + Indent)
|
||||
<< "// Src: " << *SNT->getPattern().getSrcPattern()
|
||||
<< " - Complexity = " << SNT->getPattern().getPatternComplexity(CGP)
|
||||
<< '\n';
|
||||
OS.indent(FullIndexWidth + Indent)
|
||||
<< "// Dst: " << *SNT->getPattern().getDstPattern() << '\n';
|
||||
}
|
||||
} else
|
||||
OS << '\n';
|
||||
@@ -1021,11 +1018,12 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
NumResultBytes += EmitVBRValue(CM->getResult(i), OS);
|
||||
OS << '\n';
|
||||
if (!OmitComments) {
|
||||
OS.indent(FullIndexWidth + Indent) << " // Src: "
|
||||
<< *CM->getPattern().getSrcPattern() << " - Complexity = "
|
||||
<< CM->getPattern().getPatternComplexity(CGP) << '\n';
|
||||
OS.indent(FullIndexWidth + Indent) << " // Dst: "
|
||||
<< *CM->getPattern().getDstPattern();
|
||||
OS.indent(FullIndexWidth + Indent)
|
||||
<< " // Src: " << *CM->getPattern().getSrcPattern()
|
||||
<< " - Complexity = " << CM->getPattern().getPatternComplexity(CGP)
|
||||
<< '\n';
|
||||
OS.indent(FullIndexWidth + Indent)
|
||||
<< " // Dst: " << *CM->getPattern().getDstPattern();
|
||||
}
|
||||
OS << '\n';
|
||||
return 2 + NumResultBytes + NumCoveredBytes;
|
||||
@@ -1036,9 +1034,10 @@ EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
|
||||
/// This function traverses the matcher tree and emits all the nodes.
|
||||
/// The nodes have already been sized.
|
||||
unsigned MatcherTableEmitter::
|
||||
EmitMatcherList(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
|
||||
raw_ostream &OS) {
|
||||
unsigned MatcherTableEmitter::EmitMatcherList(const Matcher *N,
|
||||
const unsigned Indent,
|
||||
unsigned CurrentIdx,
|
||||
raw_ostream &OS) {
|
||||
unsigned Size = 0;
|
||||
while (N) {
|
||||
if (!OmitComments)
|
||||
@@ -1059,7 +1058,7 @@ void MatcherTableEmitter::EmitNodePredicatesFunction(
|
||||
if (Preds.empty())
|
||||
return;
|
||||
|
||||
BeginEmitFunction(OS, "bool", Decl, true/*AddOverride*/);
|
||||
BeginEmitFunction(OS, "bool", Decl, true /*AddOverride*/);
|
||||
OS << "{\n";
|
||||
OS << " switch (PredNo) {\n";
|
||||
OS << " default: llvm_unreachable(\"Invalid predicate in table?\");\n";
|
||||
@@ -1083,12 +1082,13 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) {
|
||||
// Emit pattern predicates.
|
||||
if (!PatternPredicates.empty()) {
|
||||
BeginEmitFunction(OS, "bool",
|
||||
"CheckPatternPredicate(unsigned PredNo) const", true/*AddOverride*/);
|
||||
"CheckPatternPredicate(unsigned PredNo) const",
|
||||
true /*AddOverride*/);
|
||||
OS << "{\n";
|
||||
OS << " switch (PredNo) {\n";
|
||||
OS << " default: llvm_unreachable(\"Invalid predicate in table?\");\n";
|
||||
for (unsigned i = 0, e = PatternPredicates.size(); i != e; ++i)
|
||||
OS << " case " << i << ": return " << PatternPredicates[i] << ";\n";
|
||||
OS << " case " << i << ": return " << PatternPredicates[i] << ";\n";
|
||||
OS << " }\n";
|
||||
OS << "}\n";
|
||||
EndEmitFunction(OS);
|
||||
@@ -1107,11 +1107,12 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) {
|
||||
// Emit CompletePattern matchers.
|
||||
// FIXME: This should be const.
|
||||
if (!ComplexPatterns.empty()) {
|
||||
BeginEmitFunction(OS, "bool",
|
||||
"CheckComplexPattern(SDNode *Root, SDNode *Parent,\n"
|
||||
" SDValue N, unsigned PatternNo,\n"
|
||||
" SmallVectorImpl<std::pair<SDValue, SDNode *>> &Result)",
|
||||
true/*AddOverride*/);
|
||||
BeginEmitFunction(
|
||||
OS, "bool",
|
||||
"CheckComplexPattern(SDNode *Root, SDNode *Parent,\n"
|
||||
" SDValue N, unsigned PatternNo,\n"
|
||||
" SmallVectorImpl<std::pair<SDValue, SDNode *>> &Result)",
|
||||
true /*AddOverride*/);
|
||||
OS << "{\n";
|
||||
OS << " unsigned NextRes = Result.size();\n";
|
||||
OS << " switch (PatternNo) {\n";
|
||||
@@ -1121,7 +1122,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) {
|
||||
unsigned NumOps = P.getNumOperands();
|
||||
|
||||
if (P.hasProperty(SDNPHasChain))
|
||||
++NumOps; // Get the chained node too.
|
||||
++NumOps; // Get the chained node too.
|
||||
|
||||
OS << " case " << i << ":\n";
|
||||
if (InstrumentCoverage)
|
||||
@@ -1160,12 +1161,12 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) {
|
||||
EndEmitFunction(OS);
|
||||
}
|
||||
|
||||
|
||||
// Emit SDNodeXForm handlers.
|
||||
// FIXME: This should be const.
|
||||
if (!NodeXForms.empty()) {
|
||||
BeginEmitFunction(OS, "SDValue",
|
||||
"RunSDNodeXForm(SDValue V, unsigned XFormNo)", true/*AddOverride*/);
|
||||
"RunSDNodeXForm(SDValue V, unsigned XFormNo)",
|
||||
true /*AddOverride*/);
|
||||
OS << "{\n";
|
||||
OS << " switch (XFormNo) {\n";
|
||||
OS << " default: llvm_unreachable(\"Invalid xform # in table?\");\n";
|
||||
@@ -1173,7 +1174,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) {
|
||||
// FIXME: The node xform could take SDValue's instead of SDNode*'s.
|
||||
for (unsigned i = 0, e = NodeXForms.size(); i != e; ++i) {
|
||||
const CodeGenDAGPatterns::NodeXForm &Entry =
|
||||
CGP.getSDNodeTransform(NodeXForms[i]);
|
||||
CGP.getSDNodeTransform(NodeXForms[i]);
|
||||
|
||||
Record *SDNode = Entry.first;
|
||||
const std::string &Code = Entry.second;
|
||||
@@ -1281,8 +1282,7 @@ static StringRef getOpcodeString(Matcher::KindTy Kind) {
|
||||
llvm_unreachable("Unhandled opcode?");
|
||||
}
|
||||
|
||||
void MatcherTableEmitter::EmitHistogram(const Matcher *M,
|
||||
raw_ostream &OS) {
|
||||
void MatcherTableEmitter::EmitHistogram(const Matcher *M, raw_ostream &OS) {
|
||||
if (OmitComments)
|
||||
return;
|
||||
|
||||
@@ -1295,9 +1295,7 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M,
|
||||
OS << '\n';
|
||||
}
|
||||
|
||||
|
||||
void llvm::EmitMatcherTable(Matcher *TheMatcher,
|
||||
const CodeGenDAGPatterns &CGP,
|
||||
void llvm::EmitMatcherTable(Matcher *TheMatcher, const CodeGenDAGPatterns &CGP,
|
||||
raw_ostream &OS) {
|
||||
OS << "#if defined(GET_DAGISEL_DECL) && defined(GET_DAGISEL_BODY)\n";
|
||||
OS << "#error GET_DAGISEL_DECL and GET_DAGISEL_BODY cannot be both defined, ";
|
||||
@@ -1328,7 +1326,7 @@ void llvm::EmitMatcherTable(Matcher *TheMatcher,
|
||||
OS << "#define DAGISEL_CLASS_COLONCOLON\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
BeginEmitFunction(OS, "void", "SelectCode(SDNode *N)", false/*AddOverride*/);
|
||||
BeginEmitFunction(OS, "void", "SelectCode(SDNode *N)", false /*AddOverride*/);
|
||||
MatcherTableEmitter MatcherEmitter(TheMatcher, CGP);
|
||||
|
||||
// First we size all the children of the three kinds of matchers that have
|
||||
@@ -1348,7 +1346,8 @@ void llvm::EmitMatcherTable(Matcher *TheMatcher,
|
||||
OS << " #define TARGET_VAL(X) X & 255, unsigned(X) >> 8\n";
|
||||
OS << " static const unsigned char MatcherTable[] = {\n";
|
||||
TotalSize = MatcherEmitter.EmitMatcherList(TheMatcher, 1, 0, OS);
|
||||
OS << " 0\n }; // Total Array size is " << (TotalSize+1) << " bytes\n\n";
|
||||
OS << " 0\n }; // Total Array size is " << (TotalSize + 1)
|
||||
<< " bytes\n\n";
|
||||
|
||||
MatcherEmitter.EmitHistogram(TheMatcher, OS);
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <utility>
|
||||
using namespace llvm;
|
||||
|
||||
|
||||
/// getRegisterValueType - Look up and return the ValueType of the specified
|
||||
/// register. If the register is a member of multiple register classes, they
|
||||
/// must all have the same type.
|
||||
@@ -52,96 +51,97 @@ static MVT::SimpleValueType getRegisterValueType(Record *R,
|
||||
return VT;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
class MatcherGen {
|
||||
const PatternToMatch &Pattern;
|
||||
const CodeGenDAGPatterns &CGP;
|
||||
class MatcherGen {
|
||||
const PatternToMatch &Pattern;
|
||||
const CodeGenDAGPatterns &CGP;
|
||||
|
||||
/// PatWithNoTypes - This is a clone of Pattern.getSrcPattern() that starts
|
||||
/// out with all of the types removed. This allows us to insert type checks
|
||||
/// as we scan the tree.
|
||||
TreePatternNodePtr PatWithNoTypes;
|
||||
/// PatWithNoTypes - This is a clone of Pattern.getSrcPattern() that starts
|
||||
/// out with all of the types removed. This allows us to insert type checks
|
||||
/// as we scan the tree.
|
||||
TreePatternNodePtr PatWithNoTypes;
|
||||
|
||||
/// VariableMap - A map from variable names ('$dst') to the recorded operand
|
||||
/// number that they were captured as. These are biased by 1 to make
|
||||
/// insertion easier.
|
||||
StringMap<unsigned> VariableMap;
|
||||
/// VariableMap - A map from variable names ('$dst') to the recorded operand
|
||||
/// number that they were captured as. These are biased by 1 to make
|
||||
/// insertion easier.
|
||||
StringMap<unsigned> VariableMap;
|
||||
|
||||
/// This maintains the recorded operand number that OPC_CheckComplexPattern
|
||||
/// drops each sub-operand into. We don't want to insert these into
|
||||
/// VariableMap because that leads to identity checking if they are
|
||||
/// encountered multiple times. Biased by 1 like VariableMap for
|
||||
/// consistency.
|
||||
StringMap<unsigned> NamedComplexPatternOperands;
|
||||
/// This maintains the recorded operand number that OPC_CheckComplexPattern
|
||||
/// drops each sub-operand into. We don't want to insert these into
|
||||
/// VariableMap because that leads to identity checking if they are
|
||||
/// encountered multiple times. Biased by 1 like VariableMap for
|
||||
/// consistency.
|
||||
StringMap<unsigned> NamedComplexPatternOperands;
|
||||
|
||||
/// NextRecordedOperandNo - As we emit opcodes to record matched values in
|
||||
/// the RecordedNodes array, this keeps track of which slot will be next to
|
||||
/// record into.
|
||||
unsigned NextRecordedOperandNo;
|
||||
/// NextRecordedOperandNo - As we emit opcodes to record matched values in
|
||||
/// the RecordedNodes array, this keeps track of which slot will be next to
|
||||
/// record into.
|
||||
unsigned NextRecordedOperandNo;
|
||||
|
||||
/// MatchedChainNodes - This maintains the position in the recorded nodes
|
||||
/// array of all of the recorded input nodes that have chains.
|
||||
SmallVector<unsigned, 2> MatchedChainNodes;
|
||||
/// MatchedChainNodes - This maintains the position in the recorded nodes
|
||||
/// array of all of the recorded input nodes that have chains.
|
||||
SmallVector<unsigned, 2> MatchedChainNodes;
|
||||
|
||||
/// MatchedComplexPatterns - This maintains a list of all of the
|
||||
/// ComplexPatterns that we need to check. The second element of each pair
|
||||
/// is the recorded operand number of the input node.
|
||||
SmallVector<std::pair<const TreePatternNode*,
|
||||
unsigned>, 2> MatchedComplexPatterns;
|
||||
/// MatchedComplexPatterns - This maintains a list of all of the
|
||||
/// ComplexPatterns that we need to check. The second element of each pair
|
||||
/// is the recorded operand number of the input node.
|
||||
SmallVector<std::pair<const TreePatternNode *, unsigned>, 2>
|
||||
MatchedComplexPatterns;
|
||||
|
||||
/// PhysRegInputs - List list has an entry for each explicitly specified
|
||||
/// physreg input to the pattern. The first elt is the Register node, the
|
||||
/// second is the recorded slot number the input pattern match saved it in.
|
||||
SmallVector<std::pair<Record*, unsigned>, 2> PhysRegInputs;
|
||||
/// PhysRegInputs - List list has an entry for each explicitly specified
|
||||
/// physreg input to the pattern. The first elt is the Register node, the
|
||||
/// second is the recorded slot number the input pattern match saved it in.
|
||||
SmallVector<std::pair<Record *, unsigned>, 2> PhysRegInputs;
|
||||
|
||||
/// Matcher - This is the top level of the generated matcher, the result.
|
||||
Matcher *TheMatcher;
|
||||
/// Matcher - This is the top level of the generated matcher, the result.
|
||||
Matcher *TheMatcher;
|
||||
|
||||
/// CurPredicate - As we emit matcher nodes, this points to the latest check
|
||||
/// which should have future checks stuck into its Next position.
|
||||
Matcher *CurPredicate;
|
||||
public:
|
||||
MatcherGen(const PatternToMatch &pattern, const CodeGenDAGPatterns &cgp);
|
||||
/// CurPredicate - As we emit matcher nodes, this points to the latest check
|
||||
/// which should have future checks stuck into its Next position.
|
||||
Matcher *CurPredicate;
|
||||
|
||||
bool EmitMatcherCode(unsigned Variant);
|
||||
void EmitResultCode();
|
||||
public:
|
||||
MatcherGen(const PatternToMatch &pattern, const CodeGenDAGPatterns &cgp);
|
||||
|
||||
Matcher *GetMatcher() const { return TheMatcher; }
|
||||
private:
|
||||
void AddMatcher(Matcher *NewNode);
|
||||
void InferPossibleTypes();
|
||||
bool EmitMatcherCode(unsigned Variant);
|
||||
void EmitResultCode();
|
||||
|
||||
// Matcher Generation.
|
||||
void EmitMatchCode(const TreePatternNode *N, TreePatternNode *NodeNoTypes);
|
||||
void EmitLeafMatchCode(const TreePatternNode *N);
|
||||
void EmitOperatorMatchCode(const TreePatternNode *N,
|
||||
TreePatternNode *NodeNoTypes);
|
||||
Matcher *GetMatcher() const { return TheMatcher; }
|
||||
|
||||
/// If this is the first time a node with unique identifier Name has been
|
||||
/// seen, record it. Otherwise, emit a check to make sure this is the same
|
||||
/// node. Returns true if this is the first encounter.
|
||||
bool recordUniqueNode(ArrayRef<std::string> Names);
|
||||
private:
|
||||
void AddMatcher(Matcher *NewNode);
|
||||
void InferPossibleTypes();
|
||||
|
||||
// Result Code Generation.
|
||||
unsigned getNamedArgumentSlot(StringRef Name) {
|
||||
unsigned VarMapEntry = VariableMap[Name];
|
||||
assert(VarMapEntry != 0 &&
|
||||
"Variable referenced but not defined and not caught earlier!");
|
||||
return VarMapEntry-1;
|
||||
}
|
||||
// Matcher Generation.
|
||||
void EmitMatchCode(const TreePatternNode *N, TreePatternNode *NodeNoTypes);
|
||||
void EmitLeafMatchCode(const TreePatternNode *N);
|
||||
void EmitOperatorMatchCode(const TreePatternNode *N,
|
||||
TreePatternNode *NodeNoTypes);
|
||||
|
||||
void EmitResultOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps);
|
||||
void EmitResultOfNamedOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps);
|
||||
void EmitResultLeafAsOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps);
|
||||
void EmitResultInstructionAsOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps);
|
||||
void EmitResultSDNodeXFormAsOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps);
|
||||
};
|
||||
/// If this is the first time a node with unique identifier Name has been
|
||||
/// seen, record it. Otherwise, emit a check to make sure this is the same
|
||||
/// node. Returns true if this is the first encounter.
|
||||
bool recordUniqueNode(ArrayRef<std::string> Names);
|
||||
|
||||
// Result Code Generation.
|
||||
unsigned getNamedArgumentSlot(StringRef Name) {
|
||||
unsigned VarMapEntry = VariableMap[Name];
|
||||
assert(VarMapEntry != 0 &&
|
||||
"Variable referenced but not defined and not caught earlier!");
|
||||
return VarMapEntry - 1;
|
||||
}
|
||||
|
||||
void EmitResultOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps);
|
||||
void EmitResultOfNamedOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps);
|
||||
void EmitResultLeafAsOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps);
|
||||
void EmitResultInstructionAsOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps);
|
||||
void EmitResultSDNodeXFormAsOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
@@ -180,11 +180,10 @@ void MatcherGen::InferPossibleTypes() {
|
||||
|
||||
bool MadeChange = true;
|
||||
while (MadeChange)
|
||||
MadeChange = PatWithNoTypes->ApplyTypeConstraints(TP,
|
||||
true/*Ignore reg constraints*/);
|
||||
MadeChange = PatWithNoTypes->ApplyTypeConstraints(
|
||||
TP, true /*Ignore reg constraints*/);
|
||||
}
|
||||
|
||||
|
||||
/// AddMatcher - Add a matcher node to the current graph we're building.
|
||||
void MatcherGen::AddMatcher(Matcher *NewNode) {
|
||||
if (CurPredicate)
|
||||
@@ -194,7 +193,6 @@ void MatcherGen::AddMatcher(Matcher *NewNode) {
|
||||
CurPredicate = NewNode;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pattern Match Generation
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -240,7 +238,7 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
|
||||
return AddMatcher(new CheckValueTypeMatcher(LeafRec->getName()));
|
||||
}
|
||||
|
||||
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("RegisterOperand") ||
|
||||
LeafRec->isSubClassOf("PointerLikeRegClass") ||
|
||||
@@ -252,7 +250,7 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
|
||||
// If we have a physreg reference like (mul gpr:$src, EAX) then we need to
|
||||
// record the register
|
||||
if (LeafRec->isSubClassOf("Register")) {
|
||||
AddMatcher(new RecordMatcher("physreg input "+LeafRec->getName().str(),
|
||||
AddMatcher(new RecordMatcher("physreg input " + LeafRec->getName().str(),
|
||||
NextRecordedOperandNo));
|
||||
PhysRegInputs.push_back(std::make_pair(LeafRec, NextRecordedOperandNo++));
|
||||
return;
|
||||
@@ -376,7 +374,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
|
||||
if (N->NodeHasProperty(SDNPHasChain, CGP)) {
|
||||
// Record the node and remember it in our chained nodes list.
|
||||
AddMatcher(new RecordMatcher("'" + N->getOperator()->getName().str() +
|
||||
"' chained node",
|
||||
"' chained node",
|
||||
NextRecordedOperandNo));
|
||||
// Remember all of the input chains our pattern will match.
|
||||
MatchedChainNodes.push_back(NextRecordedOperandNo++);
|
||||
@@ -407,7 +405,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
|
||||
// this to be folded.
|
||||
//
|
||||
const TreePatternNode *Root = Pattern.getSrcPattern();
|
||||
if (N != Root) { // Not the root of the pattern.
|
||||
if (N != Root) { // Not the root of the pattern.
|
||||
// If there is a node between the root and this node, then we definitely
|
||||
// need to emit the check.
|
||||
bool NeedCheck = !Root->hasChild(N);
|
||||
@@ -419,13 +417,11 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
|
||||
if (!NeedCheck) {
|
||||
const SDNodeInfo &PInfo = CGP.getSDNodeInfo(Root->getOperator());
|
||||
NeedCheck =
|
||||
Root->getOperator() == CGP.get_intrinsic_void_sdnode() ||
|
||||
Root->getOperator() == CGP.get_intrinsic_w_chain_sdnode() ||
|
||||
Root->getOperator() == CGP.get_intrinsic_wo_chain_sdnode() ||
|
||||
PInfo.getNumOperands() > 1 ||
|
||||
PInfo.hasProperty(SDNPHasChain) ||
|
||||
PInfo.hasProperty(SDNPInGlue) ||
|
||||
PInfo.hasProperty(SDNPOptInGlue);
|
||||
Root->getOperator() == CGP.get_intrinsic_void_sdnode() ||
|
||||
Root->getOperator() == CGP.get_intrinsic_w_chain_sdnode() ||
|
||||
Root->getOperator() == CGP.get_intrinsic_wo_chain_sdnode() ||
|
||||
PInfo.getNumOperands() > 1 || PInfo.hasProperty(SDNPHasChain) ||
|
||||
PInfo.hasProperty(SDNPInGlue) || PInfo.hasProperty(SDNPOptInGlue);
|
||||
}
|
||||
|
||||
if (NeedCheck)
|
||||
@@ -434,13 +430,12 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
|
||||
}
|
||||
|
||||
// If this node has an output glue and isn't the root, remember it.
|
||||
if (N->NodeHasProperty(SDNPOutGlue, CGP) &&
|
||||
N != Pattern.getSrcPattern()) {
|
||||
if (N->NodeHasProperty(SDNPOutGlue, CGP) && N != Pattern.getSrcPattern()) {
|
||||
// TODO: This redundantly records nodes with both glues and chains.
|
||||
|
||||
// Record the node and remember it in our chained nodes list.
|
||||
AddMatcher(new RecordMatcher("'" + N->getOperator()->getName().str() +
|
||||
"' glue output node",
|
||||
"' glue output node",
|
||||
NextRecordedOperandNo));
|
||||
}
|
||||
|
||||
@@ -485,7 +480,7 @@ bool MatcherGen::recordUniqueNode(ArrayRef<std::string> Names) {
|
||||
// we already have checked that the first reference is valid, we don't
|
||||
// have to recursively match it, just check that it's the same as the
|
||||
// previously named thing.
|
||||
AddMatcher(new CheckSameMatcher(Entry-1));
|
||||
AddMatcher(new CheckSameMatcher(Entry - 1));
|
||||
}
|
||||
|
||||
for (const std::string &Name : Names)
|
||||
@@ -502,7 +497,8 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
|
||||
SmallVector<unsigned, 2> ResultsToTypeCheck;
|
||||
|
||||
for (unsigned i = 0, e = NodeNoTypes->getNumTypes(); i != e; ++i) {
|
||||
if (NodeNoTypes->getExtType(i) == N->getExtType(i)) continue;
|
||||
if (NodeNoTypes->getExtType(i) == N->getExtType(i))
|
||||
continue;
|
||||
NodeNoTypes->setType(i, N->getExtType(i));
|
||||
InferPossibleTypes();
|
||||
ResultsToTypeCheck.push_back(i);
|
||||
@@ -515,7 +511,8 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
|
||||
Names.push_back(N->getName());
|
||||
|
||||
for (const ScopedName &Name : N->getNamesAsPredicateArg()) {
|
||||
Names.push_back(("pred:" + Twine(Name.getScope()) + ":" + Name.getIdentifier()).str());
|
||||
Names.push_back(
|
||||
("pred:" + Twine(Name.getScope()) + ":" + Name.getIdentifier()).str());
|
||||
}
|
||||
|
||||
if (!Names.empty()) {
|
||||
@@ -557,14 +554,17 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) {
|
||||
// Depending on which variant we're generating code for, emit the root opcode
|
||||
// check.
|
||||
if (const ComplexPattern *CP =
|
||||
Pattern.getSrcPattern()->getComplexPatternInfo(CGP)) {
|
||||
const std::vector<Record*> &OpNodes = CP->getRootNodes();
|
||||
assert(!OpNodes.empty() &&"Complex Pattern must specify what it can match");
|
||||
if (Variant >= OpNodes.size()) return true;
|
||||
Pattern.getSrcPattern()->getComplexPatternInfo(CGP)) {
|
||||
const std::vector<Record *> &OpNodes = CP->getRootNodes();
|
||||
assert(!OpNodes.empty() &&
|
||||
"Complex Pattern must specify what it can match");
|
||||
if (Variant >= OpNodes.size())
|
||||
return true;
|
||||
|
||||
AddMatcher(new CheckOpcodeMatcher(CGP.getSDNodeInfo(OpNodes[Variant])));
|
||||
} else {
|
||||
if (Variant != 0) return true;
|
||||
if (Variant != 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Emit the matcher for the pattern structure and types.
|
||||
@@ -616,7 +616,7 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) {
|
||||
// It is the last operand recorded.
|
||||
assert(NextRecordedOperandNo > 1 &&
|
||||
"Should have recorded input/result chains at least!");
|
||||
MatchedChainNodes.push_back(NextRecordedOperandNo-1);
|
||||
MatchedChainNodes.push_back(NextRecordedOperandNo - 1);
|
||||
}
|
||||
|
||||
// TODO: Complex patterns can't have output glues, if they did, we'd want
|
||||
@@ -626,13 +626,12 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Node Result Generation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void MatcherGen::EmitResultOfNamedOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps){
|
||||
void MatcherGen::EmitResultOfNamedOperand(
|
||||
const TreePatternNode *N, SmallVectorImpl<unsigned> &ResultOps) {
|
||||
assert(!N->getName().empty() && "Operand not named!");
|
||||
|
||||
if (unsigned SlotNo = NamedComplexPatternOperands[N->getName()]) {
|
||||
@@ -676,8 +675,7 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
|
||||
if (DefInit *DI = dyn_cast<DefInit>(N->getLeafValue())) {
|
||||
Record *Def = DI->getDef();
|
||||
if (Def->isSubClassOf("Register")) {
|
||||
const CodeGenRegister *Reg =
|
||||
CGP.getTargetInfo().getRegBank().getReg(Def);
|
||||
const CodeGenRegister *Reg = CGP.getTargetInfo().getRegBank().getReg(Def);
|
||||
AddMatcher(new EmitRegisterMatcher(Reg, N->getSimpleType(0)));
|
||||
ResultOps.push_back(NextRecordedOperandNo++);
|
||||
return;
|
||||
@@ -746,18 +744,16 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
|
||||
N->dump();
|
||||
}
|
||||
|
||||
static bool
|
||||
mayInstNodeLoadOrStore(const TreePatternNode *N,
|
||||
const CodeGenDAGPatterns &CGP) {
|
||||
static bool mayInstNodeLoadOrStore(const TreePatternNode *N,
|
||||
const CodeGenDAGPatterns &CGP) {
|
||||
Record *Op = N->getOperator();
|
||||
const CodeGenTarget &CGT = CGP.getTargetInfo();
|
||||
CodeGenInstruction &II = CGT.getInstruction(Op);
|
||||
return II.mayLoad || II.mayStore;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
numNodesThatMayLoadOrStore(const TreePatternNode *N,
|
||||
const CodeGenDAGPatterns &CGP) {
|
||||
static unsigned numNodesThatMayLoadOrStore(const TreePatternNode *N,
|
||||
const CodeGenDAGPatterns &CGP) {
|
||||
if (N->isLeaf())
|
||||
return 0;
|
||||
|
||||
@@ -775,9 +771,8 @@ numNodesThatMayLoadOrStore(const TreePatternNode *N,
|
||||
return Count;
|
||||
}
|
||||
|
||||
void MatcherGen::
|
||||
EmitResultInstructionAsOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &OutputOps) {
|
||||
void MatcherGen::EmitResultInstructionAsOperand(
|
||||
const TreePatternNode *N, SmallVectorImpl<unsigned> &OutputOps) {
|
||||
Record *Op = N->getOperator();
|
||||
const CodeGenTarget &CGT = CGP.getTargetInfo();
|
||||
CodeGenInstruction &II = CGT.getInstruction(Op);
|
||||
@@ -823,11 +818,11 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
|
||||
// filled in with their defaults unconditionally.
|
||||
unsigned NonOverridableOperands = NumFixedOperands;
|
||||
while (NonOverridableOperands > NumResults &&
|
||||
CGP.operandHasDefault(II.Operands[NonOverridableOperands-1].Rec))
|
||||
CGP.operandHasDefault(II.Operands[NonOverridableOperands - 1].Rec))
|
||||
--NonOverridableOperands;
|
||||
|
||||
for (unsigned InstOpNo = NumResults, e = NumFixedOperands;
|
||||
InstOpNo != e; ++InstOpNo) {
|
||||
for (unsigned InstOpNo = NumResults, e = NumFixedOperands; InstOpNo != e;
|
||||
++InstOpNo) {
|
||||
// Determine what to emit for this operand.
|
||||
Record *OperandNode = II.Operands[InstOpNo].Rec;
|
||||
if (CGP.operandHasDefault(OperandNode) &&
|
||||
@@ -835,8 +830,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
|
||||
// This is a predicate or optional def operand which the pattern has not
|
||||
// overridden, or which we aren't letting it override; emit the 'default
|
||||
// ops' operands.
|
||||
const DAGDefaultOperand &DefaultOp
|
||||
= CGP.getDefaultOperand(OperandNode);
|
||||
const DAGDefaultOperand &DefaultOp = CGP.getDefaultOperand(OperandNode);
|
||||
for (unsigned i = 0, e = DefaultOp.DefaultOps.size(); i != e; ++i)
|
||||
EmitResultOperand(DefaultOp.DefaultOps[i].get(), InstOps);
|
||||
continue;
|
||||
@@ -865,7 +859,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
|
||||
// If the operand is an instruction and it produced multiple results, just
|
||||
// take the first one.
|
||||
if (!Child->isLeaf() && Child->getOperator()->isSubClassOf("Instruction"))
|
||||
InstOps.resize(BeforeAddingNumOps+1);
|
||||
InstOps.resize(BeforeAddingNumOps + 1);
|
||||
|
||||
++ChildNo;
|
||||
}
|
||||
@@ -889,9 +883,8 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
|
||||
// occur in patterns like (mul:i8 AL:i8, GR8:i8:$src).
|
||||
for (unsigned i = 0, e = PhysRegInputs.size(); i != e; ++i) {
|
||||
const CodeGenRegister *Reg =
|
||||
CGP.getTargetInfo().getRegBank().getReg(PhysRegInputs[i].first);
|
||||
AddMatcher(new EmitCopyToRegMatcher(PhysRegInputs[i].second,
|
||||
Reg));
|
||||
CGP.getTargetInfo().getRegBank().getReg(PhysRegInputs[i].first);
|
||||
AddMatcher(new EmitCopyToRegMatcher(PhysRegInputs[i].second, Reg));
|
||||
}
|
||||
|
||||
// Even if the node has no other glue inputs, the resultant node must be
|
||||
@@ -919,7 +912,8 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
|
||||
HandledReg = II.ImplicitDefs[0];
|
||||
|
||||
for (Record *Reg : Pattern.getDstRegs()) {
|
||||
if (!Reg->isSubClassOf("Register") || Reg == HandledReg) continue;
|
||||
if (!Reg->isSubClassOf("Register") || Reg == HandledReg)
|
||||
continue;
|
||||
ResultVTs.push_back(getRegisterValueType(Reg, CGT));
|
||||
}
|
||||
}
|
||||
@@ -928,8 +922,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
|
||||
// a node that is variadic, mark the generated node as variadic so that it
|
||||
// gets the excess operands from the input DAG.
|
||||
int NumFixedArityOperands = -1;
|
||||
if (isRoot &&
|
||||
Pattern.getSrcPattern()->NodeHasProperty(SDNPVariadic, CGP))
|
||||
if (isRoot && Pattern.getSrcPattern()->NodeHasProperty(SDNPVariadic, CGP))
|
||||
NumFixedArityOperands = Pattern.getSrcPattern()->getNumChildren();
|
||||
|
||||
// If this is the root node and multiple matched nodes in the input pattern
|
||||
@@ -940,17 +933,17 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
|
||||
// FIXME3: This is actively incorrect for result patterns with multiple
|
||||
// memory-referencing instructions.
|
||||
bool PatternHasMemOperands =
|
||||
Pattern.getSrcPattern()->TreeHasProperty(SDNPMemOperand, CGP);
|
||||
Pattern.getSrcPattern()->TreeHasProperty(SDNPMemOperand, CGP);
|
||||
|
||||
bool NodeHasMemRefs = false;
|
||||
if (PatternHasMemOperands) {
|
||||
unsigned NumNodesThatLoadOrStore =
|
||||
numNodesThatMayLoadOrStore(Pattern.getDstPattern(), CGP);
|
||||
bool NodeIsUniqueLoadOrStore = mayInstNodeLoadOrStore(N, CGP) &&
|
||||
NumNodesThatLoadOrStore == 1;
|
||||
numNodesThatMayLoadOrStore(Pattern.getDstPattern(), CGP);
|
||||
bool NodeIsUniqueLoadOrStore =
|
||||
mayInstNodeLoadOrStore(N, CGP) && NumNodesThatLoadOrStore == 1;
|
||||
NodeHasMemRefs =
|
||||
NodeIsUniqueLoadOrStore || (isRoot && (mayInstNodeLoadOrStore(N, CGP) ||
|
||||
NumNodesThatLoadOrStore != 1));
|
||||
NodeIsUniqueLoadOrStore || (isRoot && (mayInstNodeLoadOrStore(N, CGP) ||
|
||||
NumNodesThatLoadOrStore != 1));
|
||||
}
|
||||
|
||||
// Determine whether we need to attach a chain to this node.
|
||||
@@ -982,14 +975,14 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
|
||||
|
||||
// The non-chain and non-glue results of the newly emitted node get recorded.
|
||||
for (unsigned i = 0, e = ResultVTs.size(); i != e; ++i) {
|
||||
if (ResultVTs[i] == MVT::Other || ResultVTs[i] == MVT::Glue) break;
|
||||
if (ResultVTs[i] == MVT::Other || ResultVTs[i] == MVT::Glue)
|
||||
break;
|
||||
OutputOps.push_back(NextRecordedOperandNo++);
|
||||
}
|
||||
}
|
||||
|
||||
void MatcherGen::
|
||||
EmitResultSDNodeXFormAsOperand(const TreePatternNode *N,
|
||||
SmallVectorImpl<unsigned> &ResultOps) {
|
||||
void MatcherGen::EmitResultSDNodeXFormAsOperand(
|
||||
const TreePatternNode *N, SmallVectorImpl<unsigned> &ResultOps) {
|
||||
assert(N->getOperator()->isSubClassOf("SDNodeXForm") && "Not SDNodeXForm?");
|
||||
|
||||
// Emit the operand.
|
||||
@@ -1051,7 +1044,8 @@ void MatcherGen::EmitResultCode() {
|
||||
// don't re-add it.
|
||||
Record *HandledReg = nullptr;
|
||||
const TreePatternNode *DstPat = Pattern.getDstPattern();
|
||||
if (!DstPat->isLeaf() &&DstPat->getOperator()->isSubClassOf("Instruction")){
|
||||
if (!DstPat->isLeaf() &&
|
||||
DstPat->getOperator()->isSubClassOf("Instruction")) {
|
||||
const CodeGenTarget &CGT = CGP.getTargetInfo();
|
||||
CodeGenInstruction &II = CGT.getInstruction(DstPat->getOperator());
|
||||
|
||||
@@ -1060,7 +1054,8 @@ void MatcherGen::EmitResultCode() {
|
||||
}
|
||||
|
||||
for (Record *Reg : Pattern.getDstRegs()) {
|
||||
if (!Reg->isSubClassOf("Register") || Reg == HandledReg) continue;
|
||||
if (!Reg->isSubClassOf("Register") || Reg == HandledReg)
|
||||
continue;
|
||||
++NumSrcResults;
|
||||
}
|
||||
}
|
||||
@@ -1077,7 +1072,6 @@ void MatcherGen::EmitResultCode() {
|
||||
AddMatcher(new CompleteMatchMatcher(Results, Pattern));
|
||||
}
|
||||
|
||||
|
||||
/// ConvertPatternToMatcher - Create the matcher for the specified pattern with
|
||||
/// the specified variant. If the variant number is invalid, this returns null.
|
||||
Matcher *llvm::ConvertPatternToMatcher(const PatternToMatch &Pattern,
|
||||
|
||||
@@ -311,10 +311,9 @@ static void FactorNodes(std::unique_ptr<Matcher> &InputMatcherPtr) {
|
||||
// Don't print if it's obvious nothing extract could be merged anyway.
|
||||
std::next(J) != E) {
|
||||
LLVM_DEBUG(errs() << "Couldn't merge this:\n"; Optn->print(errs(), 4);
|
||||
errs() << "into this:\n";
|
||||
(*J)->print(errs(), 4);
|
||||
errs() << "into this:\n"; (*J)->print(errs(), 4);
|
||||
(*std::next(J))->printOne(errs());
|
||||
if (std::next(J, 2) != E) (*std::next(J, 2))->printOne(errs());
|
||||
if (std::next(J, 2) != E)(*std::next(J, 2))->printOne(errs());
|
||||
errs() << "\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -147,8 +147,8 @@ void DfaEmitter::emit(StringRef Name, raw_ostream &OS) {
|
||||
|
||||
OS << "// A table of DFA transitions, ordered by {FromDfaState, Action}.\n";
|
||||
OS << "// The initial state is 1, not zero.\n";
|
||||
OS << "const std::array<" << Name << "Transition, "
|
||||
<< DfaTransitions.size() << "> " << Name << "Transitions = {{\n";
|
||||
OS << "const std::array<" << Name << "Transition, " << DfaTransitions.size()
|
||||
<< "> " << Name << "Transitions = {{\n";
|
||||
for (auto &KV : DfaTransitions) {
|
||||
dfa_state_type From = KV.first.first;
|
||||
dfa_state_type To = KV.second.first;
|
||||
@@ -284,7 +284,7 @@ void Automaton::emit(raw_ostream &OS) {
|
||||
}
|
||||
LLVM_DEBUG(dbgs() << " NFA automaton has " << SeenStates.size()
|
||||
<< " states with " << NumTransitions << " transitions.\n");
|
||||
(void) NumTransitions;
|
||||
(void)NumTransitions;
|
||||
|
||||
const auto &ActionTypes = Transitions.back().getTypes();
|
||||
OS << "// The type of an action in the " << Name << " automaton.\n";
|
||||
@@ -346,9 +346,7 @@ bool Transition::canTransitionFrom(uint64_t State) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t Transition::transitionFrom(uint64_t State) {
|
||||
return State | NewState;
|
||||
}
|
||||
uint64_t Transition::transitionFrom(uint64_t State) { return State | NewState; }
|
||||
|
||||
void CustomDfaEmitter::printActionType(raw_ostream &OS) { OS << TypeName; }
|
||||
|
||||
|
||||
@@ -72,8 +72,7 @@ public:
|
||||
DFAPacketizerEmitter(RecordKeeper &R);
|
||||
|
||||
// Construct a map of function unit names to bits.
|
||||
int collectAllFuncUnits(
|
||||
ArrayRef<const CodeGenProcModel *> ProcModels);
|
||||
int collectAllFuncUnits(ArrayRef<const CodeGenProcModel *> ProcModels);
|
||||
|
||||
// Construct a map from a combo function unit bit to the bits of all included
|
||||
// functional units.
|
||||
@@ -129,7 +128,8 @@ int DFAPacketizerEmitter::collectAllFuncUnits(
|
||||
return totalFUs;
|
||||
}
|
||||
|
||||
int DFAPacketizerEmitter::collectAllComboFuncs(ArrayRef<Record *> ComboFuncList) {
|
||||
int DFAPacketizerEmitter::collectAllComboFuncs(
|
||||
ArrayRef<Record *> ComboFuncList) {
|
||||
LLVM_DEBUG(dbgs() << "-------------------------------------------------------"
|
||||
"----------------------\n");
|
||||
LLVM_DEBUG(dbgs() << "collectAllComboFuncs");
|
||||
|
||||
@@ -42,22 +42,23 @@ struct DXILParameter {
|
||||
};
|
||||
|
||||
struct DXILOperationDesc {
|
||||
StringRef OpName; // name of DXIL operation
|
||||
int OpCode; // ID of DXIL operation
|
||||
StringRef OpClass; // name of the opcode class
|
||||
StringRef Category; // classification for this instruction
|
||||
StringRef Doc; // the documentation description of this instruction
|
||||
StringRef OpName; // name of DXIL operation
|
||||
int OpCode; // ID of DXIL operation
|
||||
StringRef OpClass; // name of the opcode class
|
||||
StringRef Category; // classification for this instruction
|
||||
StringRef Doc; // the documentation description of this instruction
|
||||
|
||||
SmallVector<DXILParameter> Params; // the operands that this instruction takes
|
||||
StringRef OverloadTypes; // overload types if applicable
|
||||
StringRef FnAttr; // attribute shorthands: rn=does not access
|
||||
// memory,ro=only reads from memory
|
||||
StringRef Intrinsic; // The llvm intrinsic map to OpName. Default is "" which
|
||||
// means no map exist
|
||||
bool IsDeriv = false; // whether this is some kind of derivative
|
||||
StringRef OverloadTypes; // overload types if applicable
|
||||
StringRef FnAttr; // attribute shorthands: rn=does not access
|
||||
// memory,ro=only reads from memory
|
||||
StringRef Intrinsic; // The llvm intrinsic map to OpName. Default is "" which
|
||||
// means no map exist
|
||||
bool IsDeriv = false; // whether this is some kind of derivative
|
||||
bool IsGradient = false; // whether this requires a gradient calculation
|
||||
bool IsFeedback = false; // whether this is a sampler feedback op
|
||||
bool IsWave = false; // whether this requires in-wave, cross-lane functionality
|
||||
bool IsWave =
|
||||
false; // whether this requires in-wave, cross-lane functionality
|
||||
bool RequiresUniformInputs = false; // whether this operation requires that
|
||||
// all of its inputs are uniform across
|
||||
// the wave
|
||||
|
||||
@@ -53,7 +53,8 @@ using namespace llvm;
|
||||
namespace {
|
||||
|
||||
STATISTIC(NumEncodings, "Number of encodings considered");
|
||||
STATISTIC(NumEncodingsLackingDisasm, "Number of encodings without disassembler info");
|
||||
STATISTIC(NumEncodingsLackingDisasm,
|
||||
"Number of encodings without disassembler info");
|
||||
STATISTIC(NumInstructions, "Number of instructions considered");
|
||||
STATISTIC(NumEncodingsSupported, "Number of encodings supported");
|
||||
STATISTIC(NumEncodingsOmitted, "Number of encodings omitted");
|
||||
@@ -61,7 +62,7 @@ STATISTIC(NumEncodingsOmitted, "Number of encodings omitted");
|
||||
struct EncodingField {
|
||||
unsigned Base, Width, Offset;
|
||||
EncodingField(unsigned B, unsigned W, unsigned O)
|
||||
: Base(B), Width(W), Offset(O) { }
|
||||
: Base(B), Width(W), Offset(O) {}
|
||||
};
|
||||
|
||||
struct OperandInfo {
|
||||
@@ -82,7 +83,7 @@ struct OperandInfo {
|
||||
typedef std::vector<EncodingField>::const_iterator const_iterator;
|
||||
|
||||
const_iterator begin() const { return Fields.begin(); }
|
||||
const_iterator end() const { return Fields.end(); }
|
||||
const_iterator end() const { return Fields.end(); }
|
||||
};
|
||||
|
||||
typedef std::vector<uint8_t> DecoderTable;
|
||||
@@ -141,8 +142,7 @@ public:
|
||||
void emitPredicateFunction(formatted_raw_ostream &OS,
|
||||
PredicateSet &Predicates,
|
||||
unsigned Indentation) const;
|
||||
void emitDecoderFunction(formatted_raw_ostream &OS,
|
||||
DecoderSet &Decoders,
|
||||
void emitDecoderFunction(formatted_raw_ostream &OS, DecoderSet &Decoders,
|
||||
unsigned Indentation) const;
|
||||
|
||||
// run - Output the code emitter
|
||||
@@ -173,9 +173,7 @@ static bool ValueSet(bit_value_t V) {
|
||||
return (V == BIT_TRUE || V == BIT_FALSE);
|
||||
}
|
||||
|
||||
static bool ValueNotSet(bit_value_t V) {
|
||||
return (V == BIT_UNSET);
|
||||
}
|
||||
static bool ValueNotSet(bit_value_t V) { return (V == BIT_UNSET); }
|
||||
|
||||
static int Value(bit_value_t V) {
|
||||
return ValueNotSet(V) ? -1 : (V == BIT_FALSE ? 0 : 1);
|
||||
@@ -280,14 +278,14 @@ class FilterChooser;
|
||||
/// version and return the Opcode since the two have the same Asm format string.
|
||||
class Filter {
|
||||
protected:
|
||||
const FilterChooser *Owner;// points to the FilterChooser who owns this filter
|
||||
const FilterChooser
|
||||
*Owner; // points to the FilterChooser who owns this filter
|
||||
unsigned StartBit; // the starting bit position
|
||||
unsigned NumBits; // number of bits to filter
|
||||
bool Mixed; // a mixed region contains both set and unset bits
|
||||
unsigned NumBits; // number of bits to filter
|
||||
bool Mixed; // a mixed region contains both set and unset bits
|
||||
|
||||
// Map of well-known segment value to the set of uid's with that value.
|
||||
std::map<uint64_t, std::vector<EncodingIDAndOpcode>>
|
||||
FilteredInstructions;
|
||||
std::map<uint64_t, std::vector<EncodingIDAndOpcode>> FilteredInstructions;
|
||||
|
||||
// Set of uid's with non-constant segment values.
|
||||
std::vector<EncodingIDAndOpcode> VariableInstructions;
|
||||
@@ -471,7 +469,7 @@ protected:
|
||||
/// dumpFilterArray - dumpFilterArray prints out debugging info for the given
|
||||
/// filter array as a series of chars.
|
||||
void dumpFilterArray(raw_ostream &o,
|
||||
const std::vector<bit_value_t> & filter) const;
|
||||
const std::vector<bit_value_t> &filter) const;
|
||||
|
||||
/// dumpStack - dumpStack traverses the filter chooser chain and calls
|
||||
/// dumpFilterArray on each filter chooser up to the top level one.
|
||||
@@ -504,11 +502,9 @@ protected:
|
||||
|
||||
bool doesOpcodeNeedPredicate(unsigned Opc) const;
|
||||
unsigned getPredicateIndex(DecoderTableInfo &TableInfo, StringRef P) const;
|
||||
void emitPredicateTableEntry(DecoderTableInfo &TableInfo,
|
||||
unsigned Opc) const;
|
||||
void emitPredicateTableEntry(DecoderTableInfo &TableInfo, unsigned Opc) const;
|
||||
|
||||
void emitSoftFailTableEntry(DecoderTableInfo &TableInfo,
|
||||
unsigned Opc) const;
|
||||
void emitSoftFailTableEntry(DecoderTableInfo &TableInfo, unsigned Opc) const;
|
||||
|
||||
// Emits table entries to decode the singleton.
|
||||
void emitSingletonTableEntry(DecoderTableInfo &TableInfo,
|
||||
@@ -560,16 +556,15 @@ public:
|
||||
///////////////////////////
|
||||
|
||||
Filter::Filter(Filter &&f)
|
||||
: Owner(f.Owner), StartBit(f.StartBit), NumBits(f.NumBits), Mixed(f.Mixed),
|
||||
FilteredInstructions(std::move(f.FilteredInstructions)),
|
||||
VariableInstructions(std::move(f.VariableInstructions)),
|
||||
FilterChooserMap(std::move(f.FilterChooserMap)), NumFiltered(f.NumFiltered),
|
||||
LastOpcFiltered(f.LastOpcFiltered) {
|
||||
}
|
||||
: Owner(f.Owner), StartBit(f.StartBit), NumBits(f.NumBits), Mixed(f.Mixed),
|
||||
FilteredInstructions(std::move(f.FilteredInstructions)),
|
||||
VariableInstructions(std::move(f.VariableInstructions)),
|
||||
FilterChooserMap(std::move(f.FilterChooserMap)),
|
||||
NumFiltered(f.NumFiltered), LastOpcFiltered(f.LastOpcFiltered) {}
|
||||
|
||||
Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits,
|
||||
bool mixed)
|
||||
: Owner(&owner), StartBit(startBit), NumBits(numBits), Mixed(mixed) {
|
||||
: Owner(&owner), StartBit(startBit), NumBits(numBits), Mixed(mixed) {
|
||||
assert(StartBit + NumBits - 1 < Owner->BitWidth);
|
||||
|
||||
NumFiltered = 0;
|
||||
@@ -598,8 +593,8 @@ Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits,
|
||||
}
|
||||
}
|
||||
|
||||
assert((FilteredInstructions.size() + VariableInstructions.size() > 0)
|
||||
&& "Filter returns no instruction categories");
|
||||
assert((FilteredInstructions.size() + VariableInstructions.size() > 0) &&
|
||||
"Filter returns no instruction categories");
|
||||
}
|
||||
|
||||
// Divides the decoding task into sub tasks and delegates them to the
|
||||
@@ -619,9 +614,11 @@ void Filter::recurse() {
|
||||
|
||||
// Delegates to an inferior filter chooser for further processing on this
|
||||
// group of instructions whose segment values are variable.
|
||||
FilterChooserMap.insert(std::make_pair(NO_FIXED_SEGMENTS_SENTINEL,
|
||||
FilterChooserMap.insert(std::make_pair(
|
||||
NO_FIXED_SEGMENTS_SENTINEL,
|
||||
std::make_unique<FilterChooser>(Owner->AllInstructions,
|
||||
VariableInstructions, Owner->Operands, BitValueArray, *Owner)));
|
||||
VariableInstructions, Owner->Operands,
|
||||
BitValueArray, *Owner)));
|
||||
}
|
||||
|
||||
// No need to recurse for a singleton filtered instruction.
|
||||
@@ -646,8 +643,8 @@ void Filter::recurse() {
|
||||
// category of instructions.
|
||||
FilterChooserMap.insert(std::make_pair(
|
||||
Inst.first, std::make_unique<FilterChooser>(
|
||||
Owner->AllInstructions, Inst.second,
|
||||
Owner->Operands, BitValueArray, *Owner)));
|
||||
Owner->AllInstructions, Inst.second, Owner->Operands,
|
||||
BitValueArray, *Owner)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,8 +652,7 @@ static void resolveTableFixups(DecoderTable &Table, const FixupList &Fixups,
|
||||
uint32_t DestIdx) {
|
||||
// Any NumToSkip fixups in the current scope can resolve to the
|
||||
// current location.
|
||||
for (FixupList::const_reverse_iterator I = Fixups.rbegin(),
|
||||
E = Fixups.rend();
|
||||
for (FixupList::const_reverse_iterator I = Fixups.rbegin(), E = Fixups.rend();
|
||||
I != E; ++I) {
|
||||
// Calculate the distance from the byte following the fixup entry byte
|
||||
// to the destination. The Target is calculated from after the 16-bit
|
||||
@@ -705,7 +701,7 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
|
||||
// Resolve any NumToSkip fixups in the current scope.
|
||||
resolveTableFixups(Table, CurScope, Table.size());
|
||||
CurScope.clear();
|
||||
PrevFilter = 0; // Don't re-process the filter's fallthrough.
|
||||
PrevFilter = 0; // Don't re-process the filter's fallthrough.
|
||||
} else {
|
||||
Table.push_back(MCD::OPC_FilterValue);
|
||||
// Encode and emit the value to filter against.
|
||||
@@ -731,7 +727,8 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
|
||||
// two as to account for the width of the NumToSkip field itself.
|
||||
if (PrevFilter) {
|
||||
uint32_t NumToSkip = Table.size() - PrevFilter - 3;
|
||||
assert(NumToSkip < (1u << 24) && "disassembler decoding table too large!");
|
||||
assert(NumToSkip < (1u << 24) &&
|
||||
"disassembler decoding table too large!");
|
||||
Table[PrevFilter] = (uint8_t)NumToSkip;
|
||||
Table[PrevFilter + 1] = (uint8_t)(NumToSkip >> 8);
|
||||
Table[PrevFilter + 2] = (uint8_t)(NumToSkip >> 16);
|
||||
@@ -771,7 +768,7 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
|
||||
unsigned Indentation, unsigned BitWidth,
|
||||
StringRef Namespace) const {
|
||||
OS.indent(Indentation) << "static const uint8_t DecoderTable" << Namespace
|
||||
<< BitWidth << "[] = {\n";
|
||||
<< BitWidth << "[] = {\n";
|
||||
|
||||
Indentation += 2;
|
||||
|
||||
@@ -807,7 +804,7 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
|
||||
DecoderTable::const_iterator I = Table.begin();
|
||||
DecoderTable::const_iterator E = Table.end();
|
||||
while (I != E) {
|
||||
assert (I < E && "incomplete decode table entry!");
|
||||
assert(I < E && "incomplete decode table entry!");
|
||||
|
||||
uint64_t Pos = I - Table.begin();
|
||||
OS << "/* " << Pos << " */";
|
||||
@@ -884,8 +881,8 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
|
||||
Table.data() + Table.size(), &ErrMsg);
|
||||
assert(ErrMsg == nullptr && "ULEB128 value too large!");
|
||||
|
||||
OS.indent(Indentation) << "MCD::OPC_" << (IsTry ? "Try" : "")
|
||||
<< "Decode, ";
|
||||
OS.indent(Indentation)
|
||||
<< "MCD::OPC_" << (IsTry ? "Try" : "") << "Decode, ";
|
||||
I += emitULEB128(I, OS);
|
||||
|
||||
// Decoder index.
|
||||
@@ -967,15 +964,16 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS,
|
||||
// The predicate function is just a big switch statement based on the
|
||||
// input predicate index.
|
||||
OS.indent(Indentation) << "static bool checkDecoderPredicate(unsigned Idx, "
|
||||
<< "const FeatureBitset &Bits) {\n";
|
||||
<< "const FeatureBitset &Bits) {\n";
|
||||
Indentation += 2;
|
||||
if (!Predicates.empty()) {
|
||||
OS.indent(Indentation) << "switch (Idx) {\n";
|
||||
OS.indent(Indentation) << "default: llvm_unreachable(\"Invalid index!\");\n";
|
||||
OS.indent(Indentation)
|
||||
<< "default: llvm_unreachable(\"Invalid index!\");\n";
|
||||
unsigned Index = 0;
|
||||
for (const auto &Predicate : Predicates) {
|
||||
OS.indent(Indentation) << "case " << Index++ << ":\n";
|
||||
OS.indent(Indentation+2) << "return (" << Predicate << ");\n";
|
||||
OS.indent(Indentation + 2) << "return (" << Predicate << ");\n";
|
||||
}
|
||||
OS.indent(Indentation) << "}\n";
|
||||
} else {
|
||||
@@ -993,7 +991,7 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
|
||||
// input decoder index.
|
||||
OS.indent(Indentation) << "template <typename InsnType>\n";
|
||||
OS.indent(Indentation) << "static DecodeStatus decodeToMCInst(DecodeStatus S,"
|
||||
<< " unsigned Idx, InsnType insn, MCInst &MI,\n";
|
||||
<< " unsigned Idx, InsnType insn, MCInst &MI,\n";
|
||||
OS.indent(Indentation)
|
||||
<< " uint64_t "
|
||||
<< "Address, const MCDisassembler *Decoder, bool &DecodeComplete) {\n";
|
||||
@@ -1012,7 +1010,7 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
|
||||
for (const auto &Decoder : Decoders) {
|
||||
OS.indent(Indentation) << "case " << Index++ << ":\n";
|
||||
OS << Decoder;
|
||||
OS.indent(Indentation+2) << "return S;\n";
|
||||
OS.indent(Indentation + 2) << "return S;\n";
|
||||
}
|
||||
OS.indent(Indentation) << "}\n";
|
||||
Indentation -= 2;
|
||||
@@ -1041,8 +1039,8 @@ bool FilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn,
|
||||
|
||||
/// dumpFilterArray - dumpFilterArray prints out debugging info for the given
|
||||
/// filter array as a series of chars.
|
||||
void FilterChooser::dumpFilterArray(raw_ostream &o,
|
||||
const std::vector<bit_value_t> &filter) const {
|
||||
void FilterChooser::dumpFilterArray(
|
||||
raw_ostream &o, const std::vector<bit_value_t> &filter) const {
|
||||
for (unsigned bitIndex = BitWidth; bitIndex > 0; bitIndex--) {
|
||||
switch (filter[bitIndex - 1]) {
|
||||
case BIT_UNFILTERED:
|
||||
@@ -1096,7 +1094,8 @@ unsigned FilterChooser::getIslands(std::vector<unsigned> &StartBits,
|
||||
int64_t Val = Value(Insn[i]);
|
||||
bool Filtered = PositionFiltered(i);
|
||||
switch (State) {
|
||||
default: llvm_unreachable("Unreachable code!");
|
||||
default:
|
||||
llvm_unreachable("Unreachable code!");
|
||||
case 0:
|
||||
case 1:
|
||||
if (Filtered || Val == -1)
|
||||
@@ -1197,8 +1196,7 @@ void FilterChooser::emitDecoder(raw_ostream &OS, unsigned Indentation,
|
||||
}
|
||||
}
|
||||
|
||||
unsigned FilterChooser::getDecoderIndex(DecoderSet &Decoders,
|
||||
unsigned Opc,
|
||||
unsigned FilterChooser::getDecoderIndex(DecoderSet &Decoders, unsigned Opc,
|
||||
bool &HasCompleteDecoder) const {
|
||||
// Build up the predicate string.
|
||||
SmallString<256> Decoder;
|
||||
@@ -1343,7 +1341,8 @@ void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo,
|
||||
const RecordVal *RV = AllInstructions[Opc].EncodingDef->getValue("SoftFail");
|
||||
BitsInit *SFBits = RV ? dyn_cast<BitsInit>(RV->getValue()) : nullptr;
|
||||
|
||||
if (!SFBits) return;
|
||||
if (!SFBits)
|
||||
return;
|
||||
BitsInit *InstBits =
|
||||
AllInstructions[Opc].EncodingDef->getValueAsBitsInit("Inst");
|
||||
|
||||
@@ -1353,7 +1352,8 @@ void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo,
|
||||
bit_value_t B = bitFromBits(*SFBits, i);
|
||||
bit_value_t IB = bitFromBits(*InstBits, i);
|
||||
|
||||
if (B != BIT_TRUE) continue;
|
||||
if (B != BIT_TRUE)
|
||||
continue;
|
||||
|
||||
switch (IB) {
|
||||
case BIT_FALSE:
|
||||
@@ -1458,12 +1458,12 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
|
||||
// decoder method indicates that additional processing should be done to see
|
||||
// if there is any other instruction that also matches the bitpattern and
|
||||
// can decode it.
|
||||
TableInfo.Table.push_back(HasCompleteDecoder ? MCD::OPC_Decode :
|
||||
MCD::OPC_TryDecode);
|
||||
TableInfo.Table.push_back(HasCompleteDecoder ? MCD::OPC_Decode
|
||||
: MCD::OPC_TryDecode);
|
||||
NumEncodingsSupported++;
|
||||
uint8_t Buffer[16], *p;
|
||||
encodeULEB128(Opc.Opcode, Buffer);
|
||||
for (p = Buffer; *p >= 128 ; ++p)
|
||||
for (p = Buffer; *p >= 128; ++p)
|
||||
TableInfo.Table.push_back(*p);
|
||||
TableInfo.Table.push_back(*p);
|
||||
|
||||
@@ -1825,8 +1825,8 @@ static std::string findOperandDecoderMethod(Record *Record) {
|
||||
std::string Decoder;
|
||||
|
||||
RecordVal *DecoderString = Record->getValue("DecoderMethod");
|
||||
StringInit *String = DecoderString ?
|
||||
dyn_cast<StringInit>(DecoderString->getValue()) : nullptr;
|
||||
StringInit *String =
|
||||
DecoderString ? dyn_cast<StringInit>(DecoderString->getValue()) : nullptr;
|
||||
if (String) {
|
||||
Decoder = std::string(String->getValue());
|
||||
if (!Decoder.empty())
|
||||
@@ -1840,7 +1840,7 @@ static std::string findOperandDecoderMethod(Record *Record) {
|
||||
Decoder = "Decode" + Record->getName().str() + "RegisterClass";
|
||||
} else if (Record->isSubClassOf("PointerLikeRegClass")) {
|
||||
Decoder = "DecodePointerLikeRegClass" +
|
||||
utostr(Record->getValueAsInt("RegClassKind"));
|
||||
utostr(Record->getValueAsInt("RegClassKind"));
|
||||
}
|
||||
|
||||
return Decoder;
|
||||
@@ -1986,7 +1986,8 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
|
||||
// of trying to auto-generate the decoder.
|
||||
StringRef InstDecoder = EncodingDef.getValueAsString("DecoderMethod");
|
||||
if (InstDecoder != "") {
|
||||
bool HasCompleteInstDecoder = EncodingDef.getValueAsBit("hasCompleteDecoder");
|
||||
bool HasCompleteInstDecoder =
|
||||
EncodingDef.getValueAsBit("hasCompleteDecoder");
|
||||
InsnOperands.push_back(
|
||||
OperandInfo(std::string(InstDecoder), HasCompleteInstDecoder));
|
||||
Operands[Opc] = InsnOperands;
|
||||
@@ -2000,9 +2001,9 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
|
||||
// Gather the outputs/inputs of the instruction, so we can find their
|
||||
// positions in the encoding. This assumes for now that they appear in the
|
||||
// MCInst in the order that they're listed.
|
||||
std::vector<std::pair<Init*, StringRef>> InOutOperands;
|
||||
DagInit *Out = Def.getValueAsDag("OutOperandList");
|
||||
DagInit *In = Def.getValueAsDag("InOperandList");
|
||||
std::vector<std::pair<Init *, StringRef>> InOutOperands;
|
||||
DagInit *Out = Def.getValueAsDag("OutOperandList");
|
||||
DagInit *In = Def.getValueAsDag("InOperandList");
|
||||
for (unsigned i = 0; i < Out->getNumArgs(); ++i)
|
||||
InOutOperands.push_back(
|
||||
std::make_pair(Out->getArg(i), Out->getArgNameStr(i)));
|
||||
@@ -2042,7 +2043,8 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
|
||||
Init *OpInit = Op.first;
|
||||
StringRef OpName = Op.second;
|
||||
|
||||
// We're ready to find the instruction encoding locations for this operand.
|
||||
// We're ready to find the instruction encoding locations for this
|
||||
// operand.
|
||||
|
||||
// First, find the operand type ("OpInit"), and sub-op names
|
||||
// ("SubArgDag") if present.
|
||||
@@ -2056,7 +2058,8 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
|
||||
? OpTypeRec->getValueAsDag("MIOperandInfo")
|
||||
: nullptr;
|
||||
|
||||
// Lookup the decoder method and construct a new OperandInfo to hold our result.
|
||||
// Lookup the decoder method and construct a new OperandInfo to hold our
|
||||
// result.
|
||||
OperandInfo OpInfo = getOpInfo(OpTypeRec);
|
||||
|
||||
// If we have named sub-operands...
|
||||
@@ -2490,7 +2493,8 @@ void DecoderEmitter::run(raw_ostream &o) {
|
||||
NumberedEncodings.emplace_back(NumberedInstruction->TheDef,
|
||||
NumberedInstruction, HwModeName);
|
||||
}
|
||||
for (const auto &NumberedAlias : RK.getAllDerivedDefinitions("AdditionalEncoding"))
|
||||
for (const auto &NumberedAlias :
|
||||
RK.getAllDerivedDefinitions("AdditionalEncoding"))
|
||||
NumberedEncodings.emplace_back(
|
||||
NumberedAlias,
|
||||
&Target.getInstruction(NumberedAlias->getValueAsDef("AliasOf")));
|
||||
@@ -2551,8 +2555,8 @@ void DecoderEmitter::run(raw_ostream &o) {
|
||||
DecoderTableInfo TableInfo;
|
||||
for (const auto &Opc : OpcMap) {
|
||||
// Emit the decoder for this namespace+width combination.
|
||||
ArrayRef<EncodingAndInst> NumberedEncodingsRef(
|
||||
NumberedEncodings.data(), NumberedEncodings.size());
|
||||
ArrayRef<EncodingAndInst> NumberedEncodingsRef(NumberedEncodings.data(),
|
||||
NumberedEncodings.size());
|
||||
FilterChooser FC(NumberedEncodingsRef, Opc.second, Operands,
|
||||
IsVarLenInst ? MaxInstLen : 8 * Opc.first.second, this);
|
||||
|
||||
|
||||
@@ -102,8 +102,8 @@ static void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
|
||||
if (Target.getName() == "X86") {
|
||||
DisassemblerTables Tables;
|
||||
|
||||
ArrayRef<const CodeGenInstruction*> numberedInstructions =
|
||||
Target.getInstructionsByEnumValue();
|
||||
ArrayRef<const CodeGenInstruction *> numberedInstructions =
|
||||
Target.getInstructionsByEnumValue();
|
||||
|
||||
for (unsigned i = 0, e = numberedInstructions.size(); i != e; ++i)
|
||||
RecognizableInstr::processInstr(Tables, *numberedInstructions[i], i);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///===- FastISelEmitter.cpp - Generate an instruction selector -------------===//
|
||||
///===- FastISelEmitter.cpp - Generate an instruction selector ------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <utility>
|
||||
using namespace llvm;
|
||||
|
||||
|
||||
/// InstructionMemo - This class holds additional information about an
|
||||
/// instruction needed to emit code for it.
|
||||
///
|
||||
@@ -61,15 +60,15 @@ namespace {
|
||||
class ImmPredicateSet {
|
||||
DenseMap<TreePattern *, unsigned> ImmIDs;
|
||||
std::vector<TreePredicateFn> PredsByName;
|
||||
public:
|
||||
|
||||
public:
|
||||
unsigned getIDFor(TreePredicateFn Pred) {
|
||||
unsigned &Entry = ImmIDs[Pred.getOrigPatFragRecord()];
|
||||
if (Entry == 0) {
|
||||
PredsByName.push_back(Pred);
|
||||
Entry = PredsByName.size();
|
||||
}
|
||||
return Entry-1;
|
||||
return Entry - 1;
|
||||
}
|
||||
|
||||
const TreePredicateFn &getPredicate(unsigned i) {
|
||||
@@ -80,7 +79,6 @@ public:
|
||||
typedef std::vector<TreePredicateFn>::const_iterator iterator;
|
||||
iterator begin() const { return PredsByName.begin(); }
|
||||
iterator end() const { return PredsByName.end(); }
|
||||
|
||||
};
|
||||
} // End anonymous namespace
|
||||
|
||||
@@ -92,26 +90,39 @@ struct OperandsSignature {
|
||||
class OpKind {
|
||||
enum { OK_Reg, OK_FP, OK_Imm, OK_Invalid = -1 };
|
||||
char Repr;
|
||||
public:
|
||||
|
||||
public:
|
||||
OpKind() : Repr(OK_Invalid) {}
|
||||
|
||||
bool operator<(OpKind RHS) const { return Repr < RHS.Repr; }
|
||||
bool operator==(OpKind RHS) const { return Repr == RHS.Repr; }
|
||||
|
||||
static OpKind getReg() { OpKind K; K.Repr = OK_Reg; return K; }
|
||||
static OpKind getFP() { OpKind K; K.Repr = OK_FP; return K; }
|
||||
static OpKind getReg() {
|
||||
OpKind K;
|
||||
K.Repr = OK_Reg;
|
||||
return K;
|
||||
}
|
||||
static OpKind getFP() {
|
||||
OpKind K;
|
||||
K.Repr = OK_FP;
|
||||
return K;
|
||||
}
|
||||
static OpKind getImm(unsigned V) {
|
||||
assert((unsigned)OK_Imm+V < 128 &&
|
||||
assert((unsigned)OK_Imm + V < 128 &&
|
||||
"Too many integer predicates for the 'Repr' char");
|
||||
OpKind K; K.Repr = OK_Imm+V; return K;
|
||||
OpKind K;
|
||||
K.Repr = OK_Imm + V;
|
||||
return K;
|
||||
}
|
||||
|
||||
bool isReg() const { return Repr == OK_Reg; }
|
||||
bool isFP() const { return Repr == OK_FP; }
|
||||
bool isFP() const { return Repr == OK_FP; }
|
||||
bool isImm() const { return Repr >= OK_Imm; }
|
||||
|
||||
unsigned getImmCode() const { assert(isImm()); return Repr-OK_Imm; }
|
||||
unsigned getImmCode() const {
|
||||
assert(isImm());
|
||||
return Repr - OK_Imm;
|
||||
}
|
||||
|
||||
void printManglingSuffix(raw_ostream &OS, ImmPredicateSet &ImmPredicates,
|
||||
bool StripImmCodes) const {
|
||||
@@ -123,12 +134,11 @@ struct OperandsSignature {
|
||||
OS << 'i';
|
||||
if (!StripImmCodes)
|
||||
if (unsigned Code = getImmCode())
|
||||
OS << "_" << ImmPredicates.getPredicate(Code-1).getFnName();
|
||||
OS << "_" << ImmPredicates.getPredicate(Code - 1).getFnName();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
SmallVector<OpKind, 3> Operands;
|
||||
|
||||
bool operator<(const OperandsSignature &O) const {
|
||||
@@ -162,15 +172,17 @@ struct OperandsSignature {
|
||||
void emitImmediatePredicate(raw_ostream &OS, ImmPredicateSet &ImmPredicates) {
|
||||
bool EmittedAnything = false;
|
||||
for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
|
||||
if (!Operands[i].isImm()) continue;
|
||||
if (!Operands[i].isImm())
|
||||
continue;
|
||||
|
||||
unsigned Code = Operands[i].getImmCode();
|
||||
if (Code == 0) continue;
|
||||
if (Code == 0)
|
||||
continue;
|
||||
|
||||
if (EmittedAnything)
|
||||
OS << " &&\n ";
|
||||
|
||||
TreePredicateFn PredFn = ImmPredicates.getPredicate(Code-1);
|
||||
TreePredicateFn PredFn = ImmPredicates.getPredicate(Code - 1);
|
||||
|
||||
// Emit the type check.
|
||||
TreePattern *TP = PredFn.getOrigPatFragRecord();
|
||||
@@ -179,7 +191,7 @@ struct OperandsSignature {
|
||||
"Cannot use variable value types with fast isel");
|
||||
OS << "VT == " << getEnumName(VVT.getSimple().SimpleTy) << " && ";
|
||||
|
||||
OS << PredFn.getFnName() << "(imm" << i <<')';
|
||||
OS << PredFn.getFnName() << "(imm" << i << ')';
|
||||
EmittedAnything = true;
|
||||
}
|
||||
}
|
||||
@@ -189,8 +201,7 @@ struct OperandsSignature {
|
||||
/// are supported, false otherwise.
|
||||
///
|
||||
bool initialize(TreePatternNode *InstPatNode, const CodeGenTarget &Target,
|
||||
MVT::SimpleValueType VT,
|
||||
ImmPredicateSet &ImmediatePredicates,
|
||||
MVT::SimpleValueType VT, ImmPredicateSet &ImmediatePredicates,
|
||||
const CodeGenRegisterClass *OrigDstRC) {
|
||||
if (InstPatNode->isLeaf())
|
||||
return false;
|
||||
@@ -229,21 +240,20 @@ struct OperandsSignature {
|
||||
if (Rec->getValueAsBit("FastIselShouldIgnore"))
|
||||
return false;
|
||||
|
||||
PredNo = ImmediatePredicates.getIDFor(PredFn)+1;
|
||||
PredNo = ImmediatePredicates.getIDFor(PredFn) + 1;
|
||||
}
|
||||
|
||||
Operands.push_back(OpKind::getImm(PredNo));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// For now, filter out any operand with a predicate.
|
||||
// For now, filter out any operand with multiple values.
|
||||
if (!Op->getPredicateCalls().empty() || Op->getNumTypes() != 1)
|
||||
return false;
|
||||
|
||||
if (!Op->isLeaf()) {
|
||||
if (Op->getOperator()->getName() == "fpimm") {
|
||||
if (Op->getOperator()->getName() == "fpimm") {
|
||||
Operands.push_back(OpKind::getFP());
|
||||
continue;
|
||||
}
|
||||
@@ -347,7 +357,6 @@ struct OperandsSignature {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PrintManglingSuffix(raw_ostream &OS, const std::vector<std::string> &PR,
|
||||
ImmPredicateSet &ImmPredicates,
|
||||
bool StripImmCodes = false) const {
|
||||
@@ -380,7 +389,7 @@ class FastISelMap {
|
||||
typedef std::map<MVT::SimpleValueType, RetPredMap> TypeRetPredMap;
|
||||
typedef std::map<std::string, TypeRetPredMap> OpcodeTypeRetPredMap;
|
||||
typedef std::map<OperandsSignature, OpcodeTypeRetPredMap>
|
||||
OperandsOpcodeTypeRetPredMap;
|
||||
OperandsOpcodeTypeRetPredMap;
|
||||
|
||||
OperandsOpcodeTypeRetPredMap SimplePatterns;
|
||||
|
||||
@@ -389,22 +398,22 @@ class FastISelMap {
|
||||
MVT::SimpleValueType, std::string>>
|
||||
SimplePatternsCheck;
|
||||
|
||||
std::map<OperandsSignature, std::vector<OperandsSignature> >
|
||||
SignaturesWithConstantForms;
|
||||
std::map<OperandsSignature, std::vector<OperandsSignature>>
|
||||
SignaturesWithConstantForms;
|
||||
|
||||
StringRef InstNS;
|
||||
ImmPredicateSet ImmediatePredicates;
|
||||
|
||||
public:
|
||||
explicit FastISelMap(StringRef InstNS);
|
||||
|
||||
void collectPatterns(CodeGenDAGPatterns &CGP);
|
||||
void printImmediatePredicates(raw_ostream &OS);
|
||||
void printFunctionDefinitions(raw_ostream &OS);
|
||||
|
||||
private:
|
||||
void emitInstructionCode(raw_ostream &OS,
|
||||
const OperandsSignature &Operands,
|
||||
const PredMap &PM,
|
||||
const std::string &RetVTName);
|
||||
void emitInstructionCode(raw_ostream &OS, const OperandsSignature &Operands,
|
||||
const PredMap &PM, const std::string &RetVTName);
|
||||
};
|
||||
} // End anonymous namespace
|
||||
|
||||
@@ -433,7 +442,7 @@ static std::string PhyRegForNode(TreePatternNode *Op,
|
||||
return PhysReg;
|
||||
|
||||
PhysReg += cast<StringInit>(OpLeafRec->getValue("Namespace")->getValue())
|
||||
->getValue();
|
||||
->getValue();
|
||||
PhysReg += "::";
|
||||
PhysReg += Target.getRegBank().getReg(OpLeafRec)->getName();
|
||||
return PhysReg;
|
||||
@@ -443,14 +452,15 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
|
||||
const CodeGenTarget &Target = CGP.getTargetInfo();
|
||||
|
||||
// Scan through all the patterns and record the simple ones.
|
||||
for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(),
|
||||
E = CGP.ptm_end(); I != E; ++I) {
|
||||
for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), E = CGP.ptm_end();
|
||||
I != E; ++I) {
|
||||
const PatternToMatch &Pattern = *I;
|
||||
|
||||
// For now, just look at Instructions, so that we don't have to worry
|
||||
// about emitting multiple instructions for a pattern.
|
||||
TreePatternNode *Dst = Pattern.getDstPattern();
|
||||
if (Dst->isLeaf()) continue;
|
||||
if (Dst->isLeaf())
|
||||
continue;
|
||||
Record *Op = Dst->getOperator();
|
||||
if (!Op->isSubClassOf("Instruction"))
|
||||
continue;
|
||||
@@ -495,7 +505,8 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
|
||||
} else {
|
||||
// If this isn't a leaf, then continue since the register classes are
|
||||
// a bit too complicated for now.
|
||||
if (!Dst->getChild(1)->isLeaf()) continue;
|
||||
if (!Dst->getChild(1)->isLeaf())
|
||||
continue;
|
||||
|
||||
DefInit *SR = dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue());
|
||||
if (SR)
|
||||
@@ -506,16 +517,20 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
|
||||
|
||||
// Inspect the pattern.
|
||||
TreePatternNode *InstPatNode = Pattern.getSrcPattern();
|
||||
if (!InstPatNode) continue;
|
||||
if (InstPatNode->isLeaf()) continue;
|
||||
if (!InstPatNode)
|
||||
continue;
|
||||
if (InstPatNode->isLeaf())
|
||||
continue;
|
||||
|
||||
// Ignore multiple result nodes for now.
|
||||
if (InstPatNode->getNumTypes() > 1) continue;
|
||||
if (InstPatNode->getNumTypes() > 1)
|
||||
continue;
|
||||
|
||||
Record *InstPatOp = InstPatNode->getOperator();
|
||||
std::string OpcodeName = getOpcodeName(InstPatOp, CGP);
|
||||
MVT::SimpleValueType RetVT = MVT::isVoid;
|
||||
if (InstPatNode->getNumTypes()) RetVT = InstPatNode->getSimpleType(0);
|
||||
if (InstPatNode->getNumTypes())
|
||||
RetVT = InstPatNode->getSimpleType(0);
|
||||
MVT::SimpleValueType VT = RetVT;
|
||||
if (InstPatNode->getNumChildren()) {
|
||||
assert(InstPatNode->getChild(0)->getNumTypes() == 1);
|
||||
@@ -546,7 +561,7 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
|
||||
if (PhysReg.empty()) {
|
||||
if (DstIndex >= Dst->getNumChildren() ||
|
||||
Dst->getChild(DstIndex)->getName() !=
|
||||
InstPatNode->getChild(i)->getName()) {
|
||||
InstPatNode->getChild(i)->getName()) {
|
||||
FoundNonSimplePattern = true;
|
||||
break;
|
||||
}
|
||||
@@ -568,21 +583,16 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
|
||||
raw_string_ostream SuffixOS(ManglingSuffix);
|
||||
Operands.PrintManglingSuffix(SuffixOS, ImmediatePredicates, true);
|
||||
if (!StringSwitch<bool>(ManglingSuffix)
|
||||
.Cases("", "r", "rr", "ri", "i", "f", true)
|
||||
.Default(false))
|
||||
.Cases("", "r", "rr", "ri", "i", "f", true)
|
||||
.Default(false))
|
||||
continue;
|
||||
|
||||
// Get the predicate that guards this pattern.
|
||||
std::string PredicateCheck = Pattern.getPredicateCheck();
|
||||
|
||||
// Ok, we found a pattern that we can handle. Remember it.
|
||||
InstructionMemo Memo(
|
||||
Pattern.getDstPattern()->getOperator()->getName(),
|
||||
DstRC,
|
||||
SubRegNo,
|
||||
PhysRegInputs,
|
||||
PredicateCheck
|
||||
);
|
||||
InstructionMemo Memo(Pattern.getDstPattern()->getOperator()->getName(),
|
||||
DstRC, SubRegNo, PhysRegInputs, PredicateCheck);
|
||||
|
||||
int complexity = Pattern.getPatternComplexity(CGP);
|
||||
|
||||
@@ -590,7 +600,7 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
|
||||
std::make_tuple(Operands, OpcodeName, VT, RetVT, PredicateCheck));
|
||||
if (!inserted_simple_pattern.second) {
|
||||
PrintFatalError(Pattern.getSrcRecord()->getLoc(),
|
||||
"Duplicate predicate in FastISel table!");
|
||||
"Duplicate predicate in FastISel table!");
|
||||
}
|
||||
|
||||
// Note: Instructions with the same complexity will appear in the order
|
||||
@@ -602,8 +612,8 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
|
||||
// them down to a signature that doesn't have predicates so that we can
|
||||
// associate them with the stripped predicate version.
|
||||
if (Operands.hasAnyImmediateCodes()) {
|
||||
SignaturesWithConstantForms[Operands.getWithoutImmCodes()]
|
||||
.push_back(Operands);
|
||||
SignaturesWithConstantForms[Operands.getWithoutImmCodes()].push_back(
|
||||
Operands);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -645,7 +655,8 @@ void FastISelMap::emitInstructionCode(raw_ostream &OS,
|
||||
if (OneHadNoPredicate) {
|
||||
PrintFatalError("Multiple instructions match and one with no "
|
||||
"predicate came before one with a predicate! "
|
||||
"name:" + Memo.Name + " predicate: " + PredicateCheck);
|
||||
"name:" +
|
||||
Memo.Name + " predicate: " + PredicateCheck);
|
||||
}
|
||||
OS << " if (" + PredicateCheck + ") {\n";
|
||||
OS << " ";
|
||||
@@ -669,8 +680,8 @@ void FastISelMap::emitInstructionCode(raw_ostream &OS,
|
||||
Operands.PrintArguments(OS, Memo.PhysRegs);
|
||||
OS << ");\n";
|
||||
} else {
|
||||
OS << "extractsubreg(" << RetVTName
|
||||
<< ", Op0, " << Memo.SubRegNo << ");\n";
|
||||
OS << "extractsubreg(" << RetVTName << ", Op0, " << Memo.SubRegNo
|
||||
<< ");\n";
|
||||
}
|
||||
|
||||
if (!PredicateCheck.empty()) {
|
||||
@@ -685,7 +696,6 @@ void FastISelMap::emitInstructionCode(raw_ostream &OS,
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
|
||||
void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
|
||||
// Now emit code for all the patterns that we collected.
|
||||
for (const auto &SimplePattern : SimplePatterns) {
|
||||
@@ -762,8 +772,7 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
|
||||
}
|
||||
|
||||
// Emit one function for the opcode that demultiplexes based on the type.
|
||||
OS << "unsigned fastEmit_"
|
||||
<< getLegalCName(Opcode) << "_";
|
||||
OS << "unsigned fastEmit_" << getLegalCName(Opcode) << "_";
|
||||
Operands.PrintManglingSuffix(OS, ImmediatePredicates);
|
||||
OS << "(MVT VT, MVT RetVT";
|
||||
if (!Operands.empty())
|
||||
@@ -809,8 +818,8 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
|
||||
// constrained forms of the immediate (e.g., 32-bit sext immediate in a
|
||||
// 64-bit operand), check them first.
|
||||
|
||||
std::map<OperandsSignature, std::vector<OperandsSignature> >::iterator MI
|
||||
= SignaturesWithConstantForms.find(Operands);
|
||||
std::map<OperandsSignature, std::vector<OperandsSignature>>::iterator MI =
|
||||
SignaturesWithConstantForms.find(Operands);
|
||||
if (MI != SignaturesWithConstantForms.end()) {
|
||||
// Unique any duplicates out of the list.
|
||||
llvm::sort(MI->second);
|
||||
@@ -840,8 +849,8 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
|
||||
for (const auto &I : OTM) {
|
||||
const std::string &Opcode = I.first;
|
||||
|
||||
OS << " case " << Opcode << ": return fastEmit_"
|
||||
<< getLegalCName(Opcode) << "_";
|
||||
OS << " case " << Opcode << ": return fastEmit_" << getLegalCName(Opcode)
|
||||
<< "_";
|
||||
Operands.PrintManglingSuffix(OS, ImmediatePredicates);
|
||||
OS << "(VT, RetVT";
|
||||
if (!Operands.empty())
|
||||
@@ -862,7 +871,8 @@ static void EmitFastISel(RecordKeeper &RK, raw_ostream &OS) {
|
||||
CodeGenDAGPatterns CGP(RK);
|
||||
const CodeGenTarget &Target = CGP.getTargetInfo();
|
||||
emitSourceFileHeader("\"Fast\" Instruction Selector for the " +
|
||||
Target.getName().str() + " target", OS);
|
||||
Target.getName().str() + " target",
|
||||
OS);
|
||||
|
||||
// Determine the target's namespace name.
|
||||
StringRef InstNS = Target.getInstNamespace();
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
// data).
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CodeGenTarget.h"
|
||||
#include "InfoByHwMode.h"
|
||||
#include "CodeGenTarget.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
@@ -44,7 +44,7 @@ ValueTypeByHwMode::ValueTypeByHwMode(Record *R, MVT T) : ValueTypeByHwMode(T) {
|
||||
PtrAddrSpace = R->getValueAsInt("AddrSpace");
|
||||
}
|
||||
|
||||
bool ValueTypeByHwMode::operator== (const ValueTypeByHwMode &T) const {
|
||||
bool ValueTypeByHwMode::operator==(const ValueTypeByHwMode &T) const {
|
||||
assert(isValid() && T.isValid() && "Invalid type in assignment");
|
||||
bool Simple = isSimple();
|
||||
if (Simple != T.isSimple())
|
||||
@@ -55,7 +55,7 @@ bool ValueTypeByHwMode::operator== (const ValueTypeByHwMode &T) const {
|
||||
return Map == T.Map;
|
||||
}
|
||||
|
||||
bool ValueTypeByHwMode::operator< (const ValueTypeByHwMode &T) const {
|
||||
bool ValueTypeByHwMode::operator<(const ValueTypeByHwMode &T) const {
|
||||
assert(isValid() && T.isValid() && "Invalid type in comparison");
|
||||
// Default order for maps.
|
||||
return Map < T.Map;
|
||||
@@ -86,7 +86,7 @@ void ValueTypeByHwMode::writeToStream(raw_ostream &OS) const {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<const PairType*> Pairs;
|
||||
std::vector<const PairType *> Pairs;
|
||||
for (const auto &P : Map)
|
||||
Pairs.push_back(&P);
|
||||
llvm::sort(Pairs, deref<std::less<PairType>>());
|
||||
@@ -100,9 +100,7 @@ void ValueTypeByHwMode::writeToStream(raw_ostream &OS) const {
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD
|
||||
void ValueTypeByHwMode::dump() const {
|
||||
dbgs() << *this << '\n';
|
||||
}
|
||||
void ValueTypeByHwMode::dump() const { dbgs() << *this << '\n'; }
|
||||
|
||||
ValueTypeByHwMode llvm::getValueTypeByHwMode(Record *Rec,
|
||||
const CodeGenHwModes &CGH) {
|
||||
@@ -123,24 +121,22 @@ RegSizeInfo::RegSizeInfo(Record *R, const CodeGenHwModes &CGH) {
|
||||
SpillAlignment = R->getValueAsInt("SpillAlignment");
|
||||
}
|
||||
|
||||
bool RegSizeInfo::operator< (const RegSizeInfo &I) const {
|
||||
bool RegSizeInfo::operator<(const RegSizeInfo &I) const {
|
||||
return std::tie(RegSize, SpillSize, SpillAlignment) <
|
||||
std::tie(I.RegSize, I.SpillSize, I.SpillAlignment);
|
||||
}
|
||||
|
||||
bool RegSizeInfo::isSubClassOf(const RegSizeInfo &I) const {
|
||||
return RegSize <= I.RegSize &&
|
||||
SpillAlignment && I.SpillAlignment % SpillAlignment == 0 &&
|
||||
SpillSize <= I.SpillSize;
|
||||
return RegSize <= I.RegSize && SpillAlignment &&
|
||||
I.SpillAlignment % SpillAlignment == 0 && SpillSize <= I.SpillSize;
|
||||
}
|
||||
|
||||
void RegSizeInfo::writeToStream(raw_ostream &OS) const {
|
||||
OS << "[R=" << RegSize << ",S=" << SpillSize
|
||||
<< ",A=" << SpillAlignment << ']';
|
||||
OS << "[R=" << RegSize << ",S=" << SpillSize << ",A=" << SpillAlignment
|
||||
<< ']';
|
||||
}
|
||||
|
||||
RegSizeInfoByHwMode::RegSizeInfoByHwMode(Record *R,
|
||||
const CodeGenHwModes &CGH) {
|
||||
RegSizeInfoByHwMode::RegSizeInfoByHwMode(Record *R, const CodeGenHwModes &CGH) {
|
||||
const HwModeSelect &MS = CGH.getHwModeSelect(R);
|
||||
for (const HwModeSelect::PairType &P : MS.Items) {
|
||||
auto I = Map.insert({P.first, RegSizeInfo(P.second, CGH)});
|
||||
@@ -149,12 +145,12 @@ RegSizeInfoByHwMode::RegSizeInfoByHwMode(Record *R,
|
||||
}
|
||||
}
|
||||
|
||||
bool RegSizeInfoByHwMode::operator< (const RegSizeInfoByHwMode &I) const {
|
||||
bool RegSizeInfoByHwMode::operator<(const RegSizeInfoByHwMode &I) const {
|
||||
unsigned M0 = Map.begin()->first;
|
||||
return get(M0) < I.get(M0);
|
||||
}
|
||||
|
||||
bool RegSizeInfoByHwMode::operator== (const RegSizeInfoByHwMode &I) const {
|
||||
bool RegSizeInfoByHwMode::operator==(const RegSizeInfoByHwMode &I) const {
|
||||
unsigned M0 = Map.begin()->first;
|
||||
return get(M0) == I.get(M0);
|
||||
}
|
||||
@@ -164,8 +160,8 @@ bool RegSizeInfoByHwMode::isSubClassOf(const RegSizeInfoByHwMode &I) const {
|
||||
return get(M0).isSubClassOf(I.get(M0));
|
||||
}
|
||||
|
||||
bool RegSizeInfoByHwMode::hasStricterSpillThan(const RegSizeInfoByHwMode &I)
|
||||
const {
|
||||
bool RegSizeInfoByHwMode::hasStricterSpillThan(
|
||||
const RegSizeInfoByHwMode &I) const {
|
||||
unsigned M0 = Map.begin()->first;
|
||||
const RegSizeInfo &A0 = get(M0);
|
||||
const RegSizeInfo &B0 = I.get(M0);
|
||||
@@ -175,7 +171,7 @@ bool RegSizeInfoByHwMode::hasStricterSpillThan(const RegSizeInfoByHwMode &I)
|
||||
|
||||
void RegSizeInfoByHwMode::writeToStream(raw_ostream &OS) const {
|
||||
typedef typename decltype(Map)::value_type PairType;
|
||||
std::vector<const PairType*> Pairs;
|
||||
std::vector<const PairType *> Pairs;
|
||||
for (const auto &P : Map)
|
||||
Pairs.push_back(&P);
|
||||
llvm::sort(Pairs, deref<std::less<PairType>>());
|
||||
@@ -187,7 +183,8 @@ void RegSizeInfoByHwMode::writeToStream(raw_ostream &OS) const {
|
||||
OS << '}';
|
||||
}
|
||||
|
||||
EncodingInfoByHwMode::EncodingInfoByHwMode(Record *R, const CodeGenHwModes &CGH) {
|
||||
EncodingInfoByHwMode::EncodingInfoByHwMode(Record *R,
|
||||
const CodeGenHwModes &CGH) {
|
||||
const HwModeSelect &MS = CGH.getHwModeSelect(R);
|
||||
for (const HwModeSelect::PairType &P : MS.Items) {
|
||||
assert(P.second && P.second->isSubClassOf("InstructionEncoding") &&
|
||||
@@ -199,18 +196,18 @@ EncodingInfoByHwMode::EncodingInfoByHwMode(Record *R, const CodeGenHwModes &CGH)
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
raw_ostream &operator<<(raw_ostream &OS, const ValueTypeByHwMode &T) {
|
||||
T.writeToStream(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfo &T) {
|
||||
T.writeToStream(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfoByHwMode &T) {
|
||||
T.writeToStream(OS);
|
||||
return OS;
|
||||
}
|
||||
raw_ostream &operator<<(raw_ostream &OS, const ValueTypeByHwMode &T) {
|
||||
T.writeToStream(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfo &T) {
|
||||
T.writeToStream(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfoByHwMode &T) {
|
||||
T.writeToStream(OS);
|
||||
return OS;
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
@@ -40,8 +40,7 @@ enum : unsigned {
|
||||
};
|
||||
|
||||
template <typename InfoT>
|
||||
void union_modes(const InfoByHwMode<InfoT> &A,
|
||||
const InfoByHwMode<InfoT> &B,
|
||||
void union_modes(const InfoByHwMode<InfoT> &A, const InfoByHwMode<InfoT> &B,
|
||||
SmallVectorImpl<unsigned> &Modes) {
|
||||
auto AI = A.begin();
|
||||
auto BI = B.begin();
|
||||
@@ -85,9 +84,8 @@ void union_modes(const InfoByHwMode<InfoT> &A,
|
||||
Modes.push_back(DefaultMode);
|
||||
}
|
||||
|
||||
template <typename InfoT>
|
||||
struct InfoByHwMode {
|
||||
typedef std::map<unsigned,InfoT> MapType;
|
||||
template <typename InfoT> struct InfoByHwMode {
|
||||
typedef std::map<unsigned, InfoT> MapType;
|
||||
typedef typename MapType::value_type PairType;
|
||||
typedef typename MapType::iterator iterator;
|
||||
typedef typename MapType::const_iterator const_iterator;
|
||||
@@ -98,11 +96,11 @@ struct InfoByHwMode {
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
iterator begin() { return Map.begin(); }
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
iterator end() { return Map.end(); }
|
||||
iterator end() { return Map.end(); }
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
const_iterator begin() const { return Map.begin(); }
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
const_iterator end() const { return Map.end(); }
|
||||
const_iterator end() const { return Map.end(); }
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool empty() const { return Map.empty(); }
|
||||
|
||||
@@ -156,15 +154,13 @@ protected:
|
||||
struct ValueTypeByHwMode : public InfoByHwMode<MVT> {
|
||||
ValueTypeByHwMode(Record *R, const CodeGenHwModes &CGH);
|
||||
ValueTypeByHwMode(Record *R, MVT T);
|
||||
ValueTypeByHwMode(MVT T) { Map.insert({DefaultMode,T}); }
|
||||
ValueTypeByHwMode(MVT T) { Map.insert({DefaultMode, T}); }
|
||||
ValueTypeByHwMode() = default;
|
||||
|
||||
bool operator== (const ValueTypeByHwMode &T) const;
|
||||
bool operator< (const ValueTypeByHwMode &T) const;
|
||||
bool operator==(const ValueTypeByHwMode &T) const;
|
||||
bool operator<(const ValueTypeByHwMode &T) const;
|
||||
|
||||
bool isValid() const {
|
||||
return !Map.empty();
|
||||
}
|
||||
bool isValid() const { return !Map.empty(); }
|
||||
MVT getType(unsigned Mode) const { return get(Mode); }
|
||||
MVT &getOrCreateTypeForMode(unsigned Mode, MVT Type);
|
||||
|
||||
@@ -178,8 +174,7 @@ struct ValueTypeByHwMode : public InfoByHwMode<MVT> {
|
||||
}
|
||||
};
|
||||
|
||||
ValueTypeByHwMode getValueTypeByHwMode(Record *Rec,
|
||||
const CodeGenHwModes &CGH);
|
||||
ValueTypeByHwMode getValueTypeByHwMode(Record *Rec, const CodeGenHwModes &CGH);
|
||||
|
||||
struct RegSizeInfo {
|
||||
unsigned RegSize;
|
||||
@@ -188,14 +183,12 @@ struct RegSizeInfo {
|
||||
|
||||
RegSizeInfo(Record *R, const CodeGenHwModes &CGH);
|
||||
RegSizeInfo() = default;
|
||||
bool operator< (const RegSizeInfo &I) const;
|
||||
bool operator== (const RegSizeInfo &I) const {
|
||||
bool operator<(const RegSizeInfo &I) const;
|
||||
bool operator==(const RegSizeInfo &I) const {
|
||||
return std::tie(RegSize, SpillSize, SpillAlignment) ==
|
||||
std::tie(I.RegSize, I.SpillSize, I.SpillAlignment);
|
||||
}
|
||||
bool operator!= (const RegSizeInfo &I) const {
|
||||
return !(*this == I);
|
||||
}
|
||||
bool operator!=(const RegSizeInfo &I) const { return !(*this == I); }
|
||||
|
||||
bool isSubClassOf(const RegSizeInfo &I) const;
|
||||
void writeToStream(raw_ostream &OS) const;
|
||||
@@ -204,9 +197,9 @@ struct RegSizeInfo {
|
||||
struct RegSizeInfoByHwMode : public InfoByHwMode<RegSizeInfo> {
|
||||
RegSizeInfoByHwMode(Record *R, const CodeGenHwModes &CGH);
|
||||
RegSizeInfoByHwMode() = default;
|
||||
bool operator< (const RegSizeInfoByHwMode &VI) const;
|
||||
bool operator== (const RegSizeInfoByHwMode &VI) const;
|
||||
bool operator!= (const RegSizeInfoByHwMode &VI) const {
|
||||
bool operator<(const RegSizeInfoByHwMode &VI) const;
|
||||
bool operator==(const RegSizeInfoByHwMode &VI) const;
|
||||
bool operator!=(const RegSizeInfoByHwMode &VI) const {
|
||||
return !(*this == VI);
|
||||
}
|
||||
|
||||
@@ -224,7 +217,7 @@ raw_ostream &operator<<(raw_ostream &OS, const ValueTypeByHwMode &T);
|
||||
raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfo &T);
|
||||
raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfoByHwMode &T);
|
||||
|
||||
struct EncodingInfoByHwMode : public InfoByHwMode<Record*> {
|
||||
struct EncodingInfoByHwMode : public InfoByHwMode<Record *> {
|
||||
EncodingInfoByHwMode(Record *R, const CodeGenHwModes &CGH);
|
||||
EncodingInfoByHwMode() = default;
|
||||
};
|
||||
|
||||
@@ -44,11 +44,18 @@ static std::string escapeForRST(StringRef Str) {
|
||||
for (char C : Str) {
|
||||
switch (C) {
|
||||
// We want special characters to be shown as their C escape codes.
|
||||
case '\n': Result += "\\n"; break;
|
||||
case '\t': Result += "\\t"; break;
|
||||
case '\n':
|
||||
Result += "\\n";
|
||||
break;
|
||||
case '\t':
|
||||
Result += "\\t";
|
||||
break;
|
||||
// Underscore at the end of a line has a special meaning in rst.
|
||||
case '_': Result += "\\_"; break;
|
||||
default: Result += C;
|
||||
case '_':
|
||||
Result += "\\_";
|
||||
break;
|
||||
default:
|
||||
Result += C;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
@@ -96,7 +103,10 @@ static void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
|
||||
std::vector<const char *> FlagStrings;
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
#define FLAG(f) if (II->f) { FlagStrings.push_back(str(f)); }
|
||||
#define FLAG(f) \
|
||||
if (II->f) { \
|
||||
FlagStrings.push_back(str(f)); \
|
||||
}
|
||||
FLAG(isReturn)
|
||||
FLAG(isEHScopeReturn)
|
||||
FLAG(isBranch)
|
||||
@@ -111,9 +121,9 @@ static void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
|
||||
FLAG(isTrap)
|
||||
FLAG(canFoldAsLoad)
|
||||
FLAG(mayLoad)
|
||||
//FLAG(mayLoad_Unset) // Deliberately omitted.
|
||||
// FLAG(mayLoad_Unset) // Deliberately omitted.
|
||||
FLAG(mayStore)
|
||||
//FLAG(mayStore_Unset) // Deliberately omitted.
|
||||
// FLAG(mayStore_Unset) // Deliberately omitted.
|
||||
FLAG(isPredicable)
|
||||
FLAG(isConvertibleToThreeAddress)
|
||||
FLAG(isCommutable)
|
||||
@@ -125,7 +135,7 @@ static void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
|
||||
FLAG(hasCtrlDep)
|
||||
FLAG(isNotDuplicable)
|
||||
FLAG(hasSideEffects)
|
||||
//FLAG(hasSideEffects_Unset) // Deliberately omitted.
|
||||
// FLAG(hasSideEffects_Unset) // Deliberately omitted.
|
||||
FLAG(isAsCheapAsAMove)
|
||||
FLAG(hasExtraSrcRegAllocReq)
|
||||
FLAG(hasExtraDefRegAllocReq)
|
||||
|
||||
@@ -53,8 +53,8 @@ class InstrInfoEmitter {
|
||||
const CodeGenSchedModels &SchedModels;
|
||||
|
||||
public:
|
||||
InstrInfoEmitter(RecordKeeper &R):
|
||||
Records(R), CDP(R), SchedModels(CDP.getTargetInfo().getSchedModels()) {}
|
||||
InstrInfoEmitter(RecordKeeper &R)
|
||||
: Records(R), CDP(R), SchedModels(CDP.getTargetInfo().getSchedModels()) {}
|
||||
|
||||
// run - Output the instruction set description.
|
||||
void run(raw_ostream &OS);
|
||||
@@ -69,8 +69,8 @@ private:
|
||||
/// The keys of this map are maps which have OpName enum values as their keys
|
||||
/// and instruction operand indices as their values. The values of this map
|
||||
/// are lists of instruction names.
|
||||
typedef std::map<std::map<unsigned, unsigned>,
|
||||
std::vector<std::string>> OpNameMapTy;
|
||||
typedef std::map<std::map<unsigned, unsigned>, std::vector<std::string>>
|
||||
OpNameMapTy;
|
||||
typedef std::map<std::string, unsigned>::iterator StrUintMapIter;
|
||||
|
||||
/// Generate member functions in the target-specific GenInstrInfo class.
|
||||
@@ -94,13 +94,14 @@ private:
|
||||
void emitOperandTypeMappings(
|
||||
raw_ostream &OS, const CodeGenTarget &Target,
|
||||
ArrayRef<const CodeGenInstruction *> NumberedInstructions);
|
||||
void initOperandMapData(
|
||||
ArrayRef<const CodeGenInstruction *> NumberedInstructions,
|
||||
StringRef Namespace,
|
||||
std::map<std::string, unsigned> &Operands,
|
||||
OpNameMapTy &OperandMap);
|
||||
void emitOperandNameMappings(raw_ostream &OS, const CodeGenTarget &Target,
|
||||
ArrayRef<const CodeGenInstruction*> NumberedInstructions);
|
||||
void
|
||||
initOperandMapData(ArrayRef<const CodeGenInstruction *> NumberedInstructions,
|
||||
StringRef Namespace,
|
||||
std::map<std::string, unsigned> &Operands,
|
||||
OpNameMapTy &OperandMap);
|
||||
void emitOperandNameMappings(
|
||||
raw_ostream &OS, const CodeGenTarget &Target,
|
||||
ArrayRef<const CodeGenInstruction *> NumberedInstructions);
|
||||
|
||||
void emitLogicalOperandSizeMappings(
|
||||
raw_ostream &OS, StringRef Namespace,
|
||||
@@ -193,8 +194,7 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
||||
// Fill in constraint info.
|
||||
Res += ", ";
|
||||
|
||||
const CGIOperandList::ConstraintInfo &Constraint =
|
||||
Op.Constraints[j];
|
||||
const CGIOperandList::ConstraintInfo &Constraint = Op.Constraints[j];
|
||||
if (Constraint.isNone())
|
||||
Res += "0";
|
||||
else if (Constraint.isEarlyClobber())
|
||||
@@ -246,10 +246,9 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
|
||||
/// each instructions. This is used to generate the OperandMap table as
|
||||
/// well as the getNamedOperandIdx() function.
|
||||
void InstrInfoEmitter::initOperandMapData(
|
||||
ArrayRef<const CodeGenInstruction *> NumberedInstructions,
|
||||
StringRef Namespace,
|
||||
std::map<std::string, unsigned> &Operands,
|
||||
OpNameMapTy &OperandMap) {
|
||||
ArrayRef<const CodeGenInstruction *> NumberedInstructions,
|
||||
StringRef Namespace, std::map<std::string, unsigned> &Operands,
|
||||
OpNameMapTy &OperandMap) {
|
||||
unsigned NumOperands = 0;
|
||||
for (const CodeGenInstruction *Inst : NumberedInstructions) {
|
||||
if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable"))
|
||||
@@ -259,13 +258,13 @@ void InstrInfoEmitter::initOperandMapData(
|
||||
StrUintMapIter I = Operands.find(Info.Name);
|
||||
|
||||
if (I == Operands.end()) {
|
||||
I = Operands.insert(Operands.begin(),
|
||||
std::pair<std::string, unsigned>(Info.Name, NumOperands++));
|
||||
I = Operands.insert(Operands.begin(), std::pair<std::string, unsigned>(
|
||||
Info.Name, NumOperands++));
|
||||
}
|
||||
OpList[I->second] = Info.MIOperandNo;
|
||||
}
|
||||
OperandMap[OpList].push_back(Namespace.str() + "::" +
|
||||
Inst->TheDef->getName().str());
|
||||
OperandMap[OpList].push_back(Namespace.str() +
|
||||
"::" + Inst->TheDef->getName().str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,9 +279,9 @@ void InstrInfoEmitter::initOperandMapData(
|
||||
/// - A function called getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx)
|
||||
/// for looking up the operand index for an instruction, given a value from
|
||||
/// OpName enum
|
||||
void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,
|
||||
const CodeGenTarget &Target,
|
||||
ArrayRef<const CodeGenInstruction*> NumberedInstructions) {
|
||||
void InstrInfoEmitter::emitOperandNameMappings(
|
||||
raw_ostream &OS, const CodeGenTarget &Target,
|
||||
ArrayRef<const CodeGenInstruction *> NumberedInstructions) {
|
||||
StringRef Namespace = Target.getInstNamespace();
|
||||
std::string OpNameNS = "OpName";
|
||||
// Map of operand names to their enumeration value. This will be used to
|
||||
@@ -380,7 +379,8 @@ void InstrInfoEmitter::emitOperandTypeMappings(
|
||||
}
|
||||
}
|
||||
|
||||
OS << " OPERAND_TYPE_LIST_END" << "\n};\n";
|
||||
OS << " OPERAND_TYPE_LIST_END"
|
||||
<< "\n};\n";
|
||||
OS << "} // end namespace OpTypes\n";
|
||||
OS << "} // end namespace " << Namespace << "\n";
|
||||
OS << "} // end namespace llvm\n";
|
||||
@@ -685,7 +685,7 @@ void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS,
|
||||
|
||||
for (const Record *Rec : TIIPredicates) {
|
||||
OS << "bool " << Rec->getValueAsString("FunctionName")
|
||||
<< "(const MCInst &MI);\n";
|
||||
<< "(const MCInst &MI);\n";
|
||||
}
|
||||
|
||||
OS << "void verifyInstructionPredicates(unsigned Opcode, const FeatureBitset "
|
||||
@@ -939,7 +939,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
|
||||
|
||||
// Collect all of the instruction's implicit uses and defs.
|
||||
Records.startTimer("Collect uses/defs");
|
||||
std::map<std::vector<Record*>, unsigned> EmittedLists;
|
||||
std::map<std::vector<Record *>, unsigned> EmittedLists;
|
||||
std::vector<std::vector<Record *>> ImplicitLists;
|
||||
unsigned ImplicitListSize = 0;
|
||||
for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
|
||||
@@ -1017,7 +1017,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
|
||||
InstrNames.emitStringLiteralDef(OS, Twine("extern const char ") + TargetName +
|
||||
"InstrNameData[]");
|
||||
|
||||
OS << "extern const unsigned " << TargetName <<"InstrNameIndices[] = {";
|
||||
OS << "extern const unsigned " << TargetName << "InstrNameIndices[] = {";
|
||||
Num = 0;
|
||||
for (const CodeGenInstruction *Inst : NumberedInstructions) {
|
||||
// Newline every eight entries.
|
||||
@@ -1104,7 +1104,6 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
|
||||
"unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u);\n"
|
||||
<< " ~" << ClassName << "() override = default;\n";
|
||||
|
||||
|
||||
OS << "\n};\n} // end namespace llvm\n";
|
||||
|
||||
OS << "#endif // GET_INSTRINFO_HEADER\n\n";
|
||||
@@ -1180,8 +1179,8 @@ void InstrInfoEmitter::emitRecord(
|
||||
int MinOperands = 0;
|
||||
if (!Inst.Operands.empty())
|
||||
// Each logical operand can be multiple MI operands.
|
||||
MinOperands = Inst.Operands.back().MIOperandNo +
|
||||
Inst.Operands.back().MINumOperands;
|
||||
MinOperands =
|
||||
Inst.Operands.back().MIOperandNo + Inst.Operands.back().MINumOperands;
|
||||
|
||||
OS << " { ";
|
||||
OS << Num << ",\t" << MinOperands << ",\t" << Inst.Operands.NumDefs << ",\t"
|
||||
@@ -1202,49 +1201,88 @@ void InstrInfoEmitter::emitRecord(
|
||||
OS << OperandInfoMap.find(OperandInfo)->second << ",\t0";
|
||||
|
||||
// Emit all of the target independent flags...
|
||||
if (Inst.isPreISelOpcode) OS << "|(1ULL<<MCID::PreISelOpcode)";
|
||||
if (Inst.isPseudo) OS << "|(1ULL<<MCID::Pseudo)";
|
||||
if (Inst.isMeta) OS << "|(1ULL<<MCID::Meta)";
|
||||
if (Inst.isReturn) OS << "|(1ULL<<MCID::Return)";
|
||||
if (Inst.isEHScopeReturn) OS << "|(1ULL<<MCID::EHScopeReturn)";
|
||||
if (Inst.isBranch) OS << "|(1ULL<<MCID::Branch)";
|
||||
if (Inst.isIndirectBranch) OS << "|(1ULL<<MCID::IndirectBranch)";
|
||||
if (Inst.isCompare) OS << "|(1ULL<<MCID::Compare)";
|
||||
if (Inst.isMoveImm) OS << "|(1ULL<<MCID::MoveImm)";
|
||||
if (Inst.isMoveReg) OS << "|(1ULL<<MCID::MoveReg)";
|
||||
if (Inst.isBitcast) OS << "|(1ULL<<MCID::Bitcast)";
|
||||
if (Inst.isAdd) OS << "|(1ULL<<MCID::Add)";
|
||||
if (Inst.isTrap) OS << "|(1ULL<<MCID::Trap)";
|
||||
if (Inst.isSelect) OS << "|(1ULL<<MCID::Select)";
|
||||
if (Inst.isBarrier) OS << "|(1ULL<<MCID::Barrier)";
|
||||
if (Inst.hasDelaySlot) OS << "|(1ULL<<MCID::DelaySlot)";
|
||||
if (Inst.isCall) OS << "|(1ULL<<MCID::Call)";
|
||||
if (Inst.canFoldAsLoad) OS << "|(1ULL<<MCID::FoldableAsLoad)";
|
||||
if (Inst.mayLoad) OS << "|(1ULL<<MCID::MayLoad)";
|
||||
if (Inst.mayStore) OS << "|(1ULL<<MCID::MayStore)";
|
||||
if (Inst.mayRaiseFPException) OS << "|(1ULL<<MCID::MayRaiseFPException)";
|
||||
if (Inst.isPredicable) OS << "|(1ULL<<MCID::Predicable)";
|
||||
if (Inst.isConvertibleToThreeAddress) OS << "|(1ULL<<MCID::ConvertibleTo3Addr)";
|
||||
if (Inst.isCommutable) OS << "|(1ULL<<MCID::Commutable)";
|
||||
if (Inst.isTerminator) OS << "|(1ULL<<MCID::Terminator)";
|
||||
if (Inst.isReMaterializable) OS << "|(1ULL<<MCID::Rematerializable)";
|
||||
if (Inst.isNotDuplicable) OS << "|(1ULL<<MCID::NotDuplicable)";
|
||||
if (Inst.Operands.hasOptionalDef) OS << "|(1ULL<<MCID::HasOptionalDef)";
|
||||
if (Inst.usesCustomInserter) OS << "|(1ULL<<MCID::UsesCustomInserter)";
|
||||
if (Inst.hasPostISelHook) OS << "|(1ULL<<MCID::HasPostISelHook)";
|
||||
if (Inst.Operands.isVariadic)OS << "|(1ULL<<MCID::Variadic)";
|
||||
if (Inst.hasSideEffects) OS << "|(1ULL<<MCID::UnmodeledSideEffects)";
|
||||
if (Inst.isAsCheapAsAMove) OS << "|(1ULL<<MCID::CheapAsAMove)";
|
||||
if (Inst.isPreISelOpcode)
|
||||
OS << "|(1ULL<<MCID::PreISelOpcode)";
|
||||
if (Inst.isPseudo)
|
||||
OS << "|(1ULL<<MCID::Pseudo)";
|
||||
if (Inst.isMeta)
|
||||
OS << "|(1ULL<<MCID::Meta)";
|
||||
if (Inst.isReturn)
|
||||
OS << "|(1ULL<<MCID::Return)";
|
||||
if (Inst.isEHScopeReturn)
|
||||
OS << "|(1ULL<<MCID::EHScopeReturn)";
|
||||
if (Inst.isBranch)
|
||||
OS << "|(1ULL<<MCID::Branch)";
|
||||
if (Inst.isIndirectBranch)
|
||||
OS << "|(1ULL<<MCID::IndirectBranch)";
|
||||
if (Inst.isCompare)
|
||||
OS << "|(1ULL<<MCID::Compare)";
|
||||
if (Inst.isMoveImm)
|
||||
OS << "|(1ULL<<MCID::MoveImm)";
|
||||
if (Inst.isMoveReg)
|
||||
OS << "|(1ULL<<MCID::MoveReg)";
|
||||
if (Inst.isBitcast)
|
||||
OS << "|(1ULL<<MCID::Bitcast)";
|
||||
if (Inst.isAdd)
|
||||
OS << "|(1ULL<<MCID::Add)";
|
||||
if (Inst.isTrap)
|
||||
OS << "|(1ULL<<MCID::Trap)";
|
||||
if (Inst.isSelect)
|
||||
OS << "|(1ULL<<MCID::Select)";
|
||||
if (Inst.isBarrier)
|
||||
OS << "|(1ULL<<MCID::Barrier)";
|
||||
if (Inst.hasDelaySlot)
|
||||
OS << "|(1ULL<<MCID::DelaySlot)";
|
||||
if (Inst.isCall)
|
||||
OS << "|(1ULL<<MCID::Call)";
|
||||
if (Inst.canFoldAsLoad)
|
||||
OS << "|(1ULL<<MCID::FoldableAsLoad)";
|
||||
if (Inst.mayLoad)
|
||||
OS << "|(1ULL<<MCID::MayLoad)";
|
||||
if (Inst.mayStore)
|
||||
OS << "|(1ULL<<MCID::MayStore)";
|
||||
if (Inst.mayRaiseFPException)
|
||||
OS << "|(1ULL<<MCID::MayRaiseFPException)";
|
||||
if (Inst.isPredicable)
|
||||
OS << "|(1ULL<<MCID::Predicable)";
|
||||
if (Inst.isConvertibleToThreeAddress)
|
||||
OS << "|(1ULL<<MCID::ConvertibleTo3Addr)";
|
||||
if (Inst.isCommutable)
|
||||
OS << "|(1ULL<<MCID::Commutable)";
|
||||
if (Inst.isTerminator)
|
||||
OS << "|(1ULL<<MCID::Terminator)";
|
||||
if (Inst.isReMaterializable)
|
||||
OS << "|(1ULL<<MCID::Rematerializable)";
|
||||
if (Inst.isNotDuplicable)
|
||||
OS << "|(1ULL<<MCID::NotDuplicable)";
|
||||
if (Inst.Operands.hasOptionalDef)
|
||||
OS << "|(1ULL<<MCID::HasOptionalDef)";
|
||||
if (Inst.usesCustomInserter)
|
||||
OS << "|(1ULL<<MCID::UsesCustomInserter)";
|
||||
if (Inst.hasPostISelHook)
|
||||
OS << "|(1ULL<<MCID::HasPostISelHook)";
|
||||
if (Inst.Operands.isVariadic)
|
||||
OS << "|(1ULL<<MCID::Variadic)";
|
||||
if (Inst.hasSideEffects)
|
||||
OS << "|(1ULL<<MCID::UnmodeledSideEffects)";
|
||||
if (Inst.isAsCheapAsAMove)
|
||||
OS << "|(1ULL<<MCID::CheapAsAMove)";
|
||||
if (!Target.getAllowRegisterRenaming() || Inst.hasExtraSrcRegAllocReq)
|
||||
OS << "|(1ULL<<MCID::ExtraSrcRegAllocReq)";
|
||||
if (!Target.getAllowRegisterRenaming() || Inst.hasExtraDefRegAllocReq)
|
||||
OS << "|(1ULL<<MCID::ExtraDefRegAllocReq)";
|
||||
if (Inst.isRegSequence) OS << "|(1ULL<<MCID::RegSequence)";
|
||||
if (Inst.isExtractSubreg) OS << "|(1ULL<<MCID::ExtractSubreg)";
|
||||
if (Inst.isInsertSubreg) OS << "|(1ULL<<MCID::InsertSubreg)";
|
||||
if (Inst.isConvergent) OS << "|(1ULL<<MCID::Convergent)";
|
||||
if (Inst.variadicOpsAreDefs) OS << "|(1ULL<<MCID::VariadicOpsAreDefs)";
|
||||
if (Inst.isAuthenticated) OS << "|(1ULL<<MCID::Authenticated)";
|
||||
if (Inst.isRegSequence)
|
||||
OS << "|(1ULL<<MCID::RegSequence)";
|
||||
if (Inst.isExtractSubreg)
|
||||
OS << "|(1ULL<<MCID::ExtractSubreg)";
|
||||
if (Inst.isInsertSubreg)
|
||||
OS << "|(1ULL<<MCID::InsertSubreg)";
|
||||
if (Inst.isConvergent)
|
||||
OS << "|(1ULL<<MCID::Convergent)";
|
||||
if (Inst.variadicOpsAreDefs)
|
||||
OS << "|(1ULL<<MCID::VariadicOpsAreDefs)";
|
||||
if (Inst.isAuthenticated)
|
||||
OS << "|(1ULL<<MCID::Authenticated)";
|
||||
|
||||
// Emit all of the target-specific flags...
|
||||
BitsInit *TSF = Inst.TheDef->getValueAsBitsInit("TSFlags");
|
||||
|
||||
@@ -60,8 +60,8 @@ public:
|
||||
raw_ostream &OS);
|
||||
void EmitGenerator(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
|
||||
void EmitAttributes(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
|
||||
void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints, bool IsClang,
|
||||
raw_ostream &OS);
|
||||
void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints,
|
||||
bool IsClang, raw_ostream &OS);
|
||||
};
|
||||
} // End anonymous namespace
|
||||
|
||||
@@ -204,7 +204,7 @@ void IntrinsicEmitter::EmitIITInfo(raw_ostream &OS) {
|
||||
}
|
||||
|
||||
void IntrinsicEmitter::EmitTargetInfo(const CodeGenIntrinsicTable &Ints,
|
||||
raw_ostream &OS) {
|
||||
raw_ostream &OS) {
|
||||
OS << "// Target mapping\n";
|
||||
OS << "#ifdef GET_INTRINSIC_TARGET_DATA\n";
|
||||
OS << "struct IntrinsicTargetInfo {\n"
|
||||
@@ -238,10 +238,10 @@ void IntrinsicEmitter::EmitIntrinsicToOverloadTable(
|
||||
OS << " 0";
|
||||
for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
|
||||
// Add one to the index so we emit a null bit for the invalid #0 intrinsic.
|
||||
if ((i+1)%8 == 0)
|
||||
if ((i + 1) % 8 == 0)
|
||||
OS << ",\n 0";
|
||||
if (Ints[i].isOverloaded)
|
||||
OS << " | (1<<" << (i+1)%8 << ')';
|
||||
OS << " | (1<<" << (i + 1) % 8 << ')';
|
||||
}
|
||||
OS << "\n};\n\n";
|
||||
// OTable contains a true bit at the position if the intrinsic is overloaded.
|
||||
@@ -271,7 +271,7 @@ void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints,
|
||||
// capture it in this vector, otherwise store a ~0U.
|
||||
std::vector<unsigned> FixedEncodings;
|
||||
|
||||
SequenceToOffsetTable<std::vector<unsigned char> > LongEncodingTable;
|
||||
SequenceToOffsetTable<std::vector<unsigned char>> LongEncodingTable;
|
||||
|
||||
std::vector<unsigned char> TypeSig;
|
||||
|
||||
@@ -292,7 +292,7 @@ void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints,
|
||||
Failed = true;
|
||||
break;
|
||||
}
|
||||
Result = (Result << 4) | TypeSig[e-i-1];
|
||||
Result = (Result << 4) | TypeSig[e - i - 1];
|
||||
}
|
||||
|
||||
// If this could be encoded into a 31-bit word, return it.
|
||||
@@ -330,7 +330,6 @@ void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints,
|
||||
TypeSig.clear();
|
||||
ComputeFixedEncoding(Ints[i], TypeSig);
|
||||
|
||||
|
||||
// Otherwise, emit the offset into the long encoding table. We emit it this
|
||||
// way so that it is easier to read the offset in the .def file.
|
||||
OS << "(1U<<31) | " << LongEncodingTable.get(TypeSig) << ", ";
|
||||
@@ -344,7 +343,7 @@ void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints,
|
||||
LongEncodingTable.emit(OS, printIITEntry);
|
||||
OS << " 255\n};\n\n";
|
||||
|
||||
OS << "#endif\n\n"; // End of GET_INTRINSIC_GENERATOR_GLOBAL
|
||||
OS << "#endif\n\n"; // End of GET_INTRINSIC_GENERATOR_GLOBAL
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -393,7 +392,8 @@ std::optional<bool> compareFnAttributes(const CodeGenIntrinsic *L,
|
||||
// Try to order by readonly/readnone attribute.
|
||||
uint32_t LK = L->ME.toIntValue();
|
||||
uint32_t RK = R->ME.toIntValue();
|
||||
if (LK != RK) return (LK > RK);
|
||||
if (LK != RK)
|
||||
return (LK > RK);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -438,8 +438,7 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
|
||||
if (!UniqArgAttributes.try_emplace(Attrs, ID).second)
|
||||
continue;
|
||||
|
||||
assert(is_sorted(Attrs) &&
|
||||
"Argument attributes are not sorted");
|
||||
assert(is_sorted(Attrs) && "Argument attributes are not sorted");
|
||||
|
||||
OS << " case " << ID << ":\n";
|
||||
OS << " return AttributeSet::get(C, {\n";
|
||||
@@ -473,8 +472,8 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
|
||||
OS << " Attribute::get(C, Attribute::ImmArg),\n";
|
||||
break;
|
||||
case CodeGenIntrinsic::Alignment:
|
||||
OS << " Attribute::get(C, Attribute::Alignment, "
|
||||
<< Attr.Value << "),\n";
|
||||
OS << " Attribute::get(C, Attribute::Alignment, " << Attr.Value
|
||||
<< "),\n";
|
||||
break;
|
||||
case CodeGenIntrinsic::Dereferenceable:
|
||||
OS << " Attribute::get(C, Attribute::Dereferenceable, "
|
||||
@@ -489,7 +488,7 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
|
||||
OS << "}\n\n";
|
||||
|
||||
// Compute unique function attribute sets.
|
||||
std::map<const CodeGenIntrinsic*, unsigned, FnAttributeComparator>
|
||||
std::map<const CodeGenIntrinsic *, unsigned, FnAttributeComparator>
|
||||
UniqFnAttributes;
|
||||
OS << "static AttributeSet getIntrinsicFnAttributeSet("
|
||||
<< "LLVMContext &C, unsigned ID) {\n"
|
||||
@@ -542,17 +541,18 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
|
||||
OS << "AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id) {\n";
|
||||
|
||||
// Compute the maximum number of attribute arguments and the map
|
||||
typedef std::map<const CodeGenIntrinsic*, unsigned,
|
||||
AttributeComparator> UniqAttrMapTy;
|
||||
typedef std::map<const CodeGenIntrinsic *, unsigned, AttributeComparator>
|
||||
UniqAttrMapTy;
|
||||
UniqAttrMapTy UniqAttributes;
|
||||
unsigned maxArgAttrs = 0;
|
||||
unsigned AttrNum = 0;
|
||||
for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
|
||||
const CodeGenIntrinsic &intrinsic = Ints[i];
|
||||
maxArgAttrs =
|
||||
std::max(maxArgAttrs, unsigned(intrinsic.ArgumentAttributes.size()));
|
||||
std::max(maxArgAttrs, unsigned(intrinsic.ArgumentAttributes.size()));
|
||||
unsigned &N = UniqAttributes[&intrinsic];
|
||||
if (N) continue;
|
||||
if (N)
|
||||
continue;
|
||||
N = ++AttrNum;
|
||||
assert(N < 65536 && "Too many unique attributes for table!");
|
||||
}
|
||||
@@ -564,8 +564,8 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
|
||||
for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
|
||||
const CodeGenIntrinsic &intrinsic = Ints[i];
|
||||
|
||||
OS << " " << UniqAttributes[&intrinsic] << ", // "
|
||||
<< intrinsic.Name << "\n";
|
||||
OS << " " << UniqAttributes[&intrinsic] << ", // " << intrinsic.Name
|
||||
<< "\n";
|
||||
}
|
||||
OS << " };\n\n";
|
||||
|
||||
|
||||
@@ -196,9 +196,9 @@ static MarshallingInfo createMarshallingInfo(const Record &R) {
|
||||
/// working with those options when given an input command line.
|
||||
static void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
|
||||
// Get the option groups and options.
|
||||
const std::vector<Record*> &Groups =
|
||||
Records.getAllDerivedDefinitions("OptionGroup");
|
||||
std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option");
|
||||
const std::vector<Record *> &Groups =
|
||||
Records.getAllDerivedDefinitions("OptionGroup");
|
||||
std::vector<Record *> Opts = Records.getAllDerivedDefinitions("Option");
|
||||
|
||||
emitSourceFileHeader("Option Parsing Definitions", OS);
|
||||
|
||||
@@ -423,8 +423,7 @@ static void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
|
||||
write_cstring(OS, R.getValueAsString("Values"));
|
||||
else if (!isa<UnsetInit>(R.getValueInit("ValuesCode"))) {
|
||||
OS << getOptionName(R) << "_Values";
|
||||
}
|
||||
else
|
||||
} else
|
||||
OS << "nullptr";
|
||||
};
|
||||
|
||||
|
||||
@@ -101,7 +101,6 @@ void PredicateExpander::expandCheckRegOperand(raw_ostream &OS, int OpIndex,
|
||||
OS << Reg->getName();
|
||||
}
|
||||
|
||||
|
||||
void PredicateExpander::expandCheckRegOperandSimple(raw_ostream &OS,
|
||||
int OpIndex,
|
||||
StringRef FunctionMapper) {
|
||||
@@ -487,7 +486,8 @@ void STIPredicateExpander::expandPrologue(raw_ostream &OS,
|
||||
OS << "unsigned ProcessorID = getSchedModel().getProcessorID();\n";
|
||||
}
|
||||
|
||||
void STIPredicateExpander::expandOpcodeGroup(raw_ostream &OS, const OpcodeGroup &Group,
|
||||
void STIPredicateExpander::expandOpcodeGroup(raw_ostream &OS,
|
||||
const OpcodeGroup &Group,
|
||||
bool ShouldUpdateOpcodeMask) {
|
||||
const OpcodeInfo &OI = Group.getOpcodeInfo();
|
||||
for (const PredicateInfo &PI : OI.getPredicates()) {
|
||||
|
||||
@@ -27,19 +27,19 @@ class PseudoLoweringEmitter {
|
||||
enum MapKind { Operand, Imm, Reg };
|
||||
MapKind Kind;
|
||||
union {
|
||||
unsigned Operand; // Operand number mapped to.
|
||||
uint64_t Imm; // Integer immedate value.
|
||||
Record *Reg; // Physical register.
|
||||
unsigned Operand; // Operand number mapped to.
|
||||
uint64_t Imm; // Integer immedate value.
|
||||
Record *Reg; // Physical register.
|
||||
} Data;
|
||||
};
|
||||
struct PseudoExpansion {
|
||||
CodeGenInstruction Source; // The source pseudo instruction definition.
|
||||
CodeGenInstruction Dest; // The destination instruction to lower to.
|
||||
CodeGenInstruction Source; // The source pseudo instruction definition.
|
||||
CodeGenInstruction Dest; // The destination instruction to lower to.
|
||||
IndexedMap<OpData> OperandMap;
|
||||
|
||||
PseudoExpansion(CodeGenInstruction &s, CodeGenInstruction &d,
|
||||
IndexedMap<OpData> &m) :
|
||||
Source(s), Dest(d), OperandMap(m) {}
|
||||
IndexedMap<OpData> &m)
|
||||
: Source(s), Dest(d), OperandMap(m) {}
|
||||
};
|
||||
|
||||
RecordKeeper &Records;
|
||||
@@ -57,6 +57,7 @@ class PseudoLoweringEmitter {
|
||||
unsigned BaseIdx);
|
||||
void evaluateExpansion(Record *Pseudo);
|
||||
void emitLoweringEmitter(raw_ostream &o);
|
||||
|
||||
public:
|
||||
PseudoLoweringEmitter(RecordKeeper &R) : Records(R), Target(R) {}
|
||||
|
||||
@@ -69,9 +70,9 @@ public:
|
||||
// The pseudo expansion really should take a list of dags, not just
|
||||
// a single dag, so we can do fancier things.
|
||||
|
||||
unsigned PseudoLoweringEmitter::
|
||||
addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn,
|
||||
IndexedMap<OpData> &OperandMap, unsigned BaseIdx) {
|
||||
unsigned PseudoLoweringEmitter::addDagOperandMapping(
|
||||
Record *Rec, DagInit *Dag, CodeGenInstruction &Insn,
|
||||
IndexedMap<OpData> &OperandMap, unsigned BaseIdx) {
|
||||
unsigned OpsAdded = 0;
|
||||
for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) {
|
||||
if (DefInit *DI = dyn_cast<DefInit>(Dag->getArg(i))) {
|
||||
@@ -92,9 +93,9 @@ addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn,
|
||||
// FIXME: Are the message operand types backward?
|
||||
if (DI->getDef() != Insn.Operands[BaseIdx + i].Rec) {
|
||||
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
|
||||
"', operand type '" + DI->getDef()->getName() +
|
||||
"' does not match expansion operand type '" +
|
||||
Insn.Operands[BaseIdx + i].Rec->getName() + "'");
|
||||
"', operand type '" + DI->getDef()->getName() +
|
||||
"' does not match expansion operand type '" +
|
||||
Insn.Operands[BaseIdx + i].Rec->getName() + "'");
|
||||
PrintFatalNote(DI->getDef(),
|
||||
"Value was assigned at the following location:");
|
||||
}
|
||||
@@ -118,7 +119,7 @@ addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn,
|
||||
// Just add the operands recursively. This is almost certainly
|
||||
// a constant value for a complex operand (> 1 MI operand).
|
||||
unsigned NewOps =
|
||||
addDagOperandMapping(Rec, SubDag, Insn, OperandMap, BaseIdx + i);
|
||||
addDagOperandMapping(Rec, SubDag, Insn, OperandMap, BaseIdx + i);
|
||||
OpsAdded += NewOps;
|
||||
// Since we added more than one, we also need to adjust the base.
|
||||
BaseIdx += NewOps - 1;
|
||||
@@ -140,15 +141,15 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) {
|
||||
DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator());
|
||||
if (!OpDef) {
|
||||
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
|
||||
"', result operator is not a record");
|
||||
"', result operator is not a record");
|
||||
PrintFatalNote(Rec->getValue("ResultInst"),
|
||||
"Result was assigned at the following location:");
|
||||
}
|
||||
Record *Operator = OpDef->getDef();
|
||||
if (!Operator->isSubClassOf("Instruction")) {
|
||||
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
|
||||
"', result operator '" + Operator->getName() +
|
||||
"' is not an instruction");
|
||||
"', result operator '" + Operator->getName() +
|
||||
"' is not an instruction");
|
||||
PrintFatalNote(Rec->getValue("ResultInst"),
|
||||
"Result was assigned at the following location:");
|
||||
}
|
||||
@@ -157,16 +158,16 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) {
|
||||
|
||||
if (Insn.isCodeGenOnly || Insn.isPseudo) {
|
||||
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
|
||||
"', result operator '" + Operator->getName() +
|
||||
"' cannot be a pseudo instruction");
|
||||
"', result operator '" + Operator->getName() +
|
||||
"' cannot be a pseudo instruction");
|
||||
PrintFatalNote(Rec->getValue("ResultInst"),
|
||||
"Result was assigned at the following location:");
|
||||
}
|
||||
|
||||
if (Insn.Operands.size() != Dag->getNumArgs()) {
|
||||
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
|
||||
"', result operator '" + Operator->getName() +
|
||||
"' has the wrong number of operands");
|
||||
"', result operator '" + Operator->getName() +
|
||||
"' has the wrong number of operands");
|
||||
PrintFatalNote(Rec->getValue("ResultInst"),
|
||||
"Result was assigned at the following location:");
|
||||
}
|
||||
@@ -201,11 +202,11 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) {
|
||||
if (OperandMap[Insn.Operands[i].MIOperandNo].Kind != OpData::Operand)
|
||||
continue;
|
||||
StringMap<unsigned>::iterator SourceOp =
|
||||
SourceOperands.find(Dag->getArgNameStr(i));
|
||||
SourceOperands.find(Dag->getArgNameStr(i));
|
||||
if (SourceOp == SourceOperands.end()) {
|
||||
PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
|
||||
"', output operand '" + Dag->getArgNameStr(i) +
|
||||
"' has no matching source operand");
|
||||
"', output operand '" + Dag->getArgNameStr(i) +
|
||||
"' has no matching source operand");
|
||||
PrintFatalNote(Rec->getValue("ResultInst"),
|
||||
"Value was assigned at the following location:");
|
||||
}
|
||||
@@ -213,7 +214,7 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) {
|
||||
// MachineInstr operand.
|
||||
for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I)
|
||||
OperandMap[Insn.Operands[i].MIOperandNo + I].Data.Operand =
|
||||
SourceOp->getValue();
|
||||
SourceOp->getValue();
|
||||
|
||||
LLVM_DEBUG(dbgs() << " " << SourceOp->getValue() << " ==> " << i
|
||||
<< "\n");
|
||||
@@ -226,7 +227,8 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
|
||||
// Emit file header.
|
||||
emitSourceFileHeader("Pseudo-instruction MC lowering Source Fragment", o);
|
||||
|
||||
o << "bool " << Target.getName() + "AsmPrinter" << "::\n"
|
||||
o << "bool " << Target.getName() + "AsmPrinter"
|
||||
<< "::\n"
|
||||
<< "emitPseudoExpansionLowering(MCStreamer &OutStreamer,\n"
|
||||
<< " const MachineInstr *MI) {\n";
|
||||
|
||||
@@ -236,12 +238,12 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
|
||||
for (auto &Expansion : Expansions) {
|
||||
CodeGenInstruction &Source = Expansion.Source;
|
||||
CodeGenInstruction &Dest = Expansion.Dest;
|
||||
o << " case " << Source.Namespace << "::"
|
||||
<< Source.TheDef->getName() << ": {\n"
|
||||
o << " case " << Source.Namespace << "::" << Source.TheDef->getName()
|
||||
<< ": {\n"
|
||||
<< " MCInst TmpInst;\n"
|
||||
<< " MCOperand MCOp;\n"
|
||||
<< " TmpInst.setOpcode(" << Dest.Namespace << "::"
|
||||
<< Dest.TheDef->getName() << ");\n";
|
||||
<< " TmpInst.setOpcode(" << Dest.Namespace
|
||||
<< "::" << Dest.TheDef->getName() << ");\n";
|
||||
|
||||
// Copy the operands from the source instruction.
|
||||
// FIXME: Instruction operands with defaults values (predicates and cc_out
|
||||
@@ -252,29 +254,29 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
|
||||
o << " // Operand: " << DestOperand.Name << "\n";
|
||||
for (unsigned i = 0, e = DestOperand.MINumOperands; i != e; ++i) {
|
||||
switch (Expansion.OperandMap[MIOpNo + i].Kind) {
|
||||
case OpData::Operand:
|
||||
case OpData::Operand:
|
||||
o << " lowerOperand(MI->getOperand("
|
||||
<< Source.Operands[Expansion.OperandMap[MIOpNo].Data
|
||||
.Operand].MIOperandNo + i
|
||||
<< Source.Operands[Expansion.OperandMap[MIOpNo].Data.Operand]
|
||||
.MIOperandNo +
|
||||
i
|
||||
<< "), MCOp);\n"
|
||||
<< " TmpInst.addOperand(MCOp);\n";
|
||||
break;
|
||||
case OpData::Imm:
|
||||
case OpData::Imm:
|
||||
o << " TmpInst.addOperand(MCOperand::createImm("
|
||||
<< Expansion.OperandMap[MIOpNo + i].Data.Imm << "));\n";
|
||||
break;
|
||||
case OpData::Reg: {
|
||||
Record *Reg = Expansion.OperandMap[MIOpNo + i].Data.Reg;
|
||||
o << " TmpInst.addOperand(MCOperand::createReg(";
|
||||
// "zero_reg" is special.
|
||||
if (Reg->getName() == "zero_reg")
|
||||
o << "0";
|
||||
else
|
||||
o << Reg->getValueAsString("Namespace") << "::"
|
||||
<< Reg->getName();
|
||||
o << "));\n";
|
||||
break;
|
||||
}
|
||||
case OpData::Reg: {
|
||||
Record *Reg = Expansion.OperandMap[MIOpNo + i].Data.Reg;
|
||||
o << " TmpInst.addOperand(MCOperand::createReg(";
|
||||
// "zero_reg" is special.
|
||||
if (Reg->getName() == "zero_reg")
|
||||
o << "0";
|
||||
else
|
||||
o << Reg->getValueAsString("Namespace") << "::" << Reg->getName();
|
||||
o << "));\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
MIOpNo += DestOperand.MINumOperands;
|
||||
|
||||
@@ -46,7 +46,9 @@ public:
|
||||
/// Get the human-readable name for the bank.
|
||||
StringRef getName() const { return TheDef.getValueAsString("Name"); }
|
||||
/// Get the name of the enumerator in the ID enumeration.
|
||||
std::string getEnumeratorName() const { return (TheDef.getName() + "ID").str(); }
|
||||
std::string getEnumeratorName() const {
|
||||
return (TheDef.getName() + "ID").str();
|
||||
}
|
||||
|
||||
/// Get the name of the array holding the register class coverage data;
|
||||
std::string getCoverageArrayName() const {
|
||||
@@ -212,8 +214,7 @@ static void visitRegisterBankClasses(
|
||||
}
|
||||
|
||||
void RegisterBankEmitter::emitBaseClassImplementation(
|
||||
raw_ostream &OS, StringRef TargetName,
|
||||
std::vector<RegisterBank> &Banks) {
|
||||
raw_ostream &OS, StringRef TargetName, std::vector<RegisterBank> &Banks) {
|
||||
const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank();
|
||||
const CodeGenHwModes &CGH = Target.getHwModes();
|
||||
|
||||
@@ -229,7 +230,8 @@ void RegisterBankEmitter::emitBaseClassImplementation(
|
||||
OS << "const uint32_t " << Bank.getCoverageArrayName() << "[] = {\n";
|
||||
unsigned LowestIdxInWord = 0;
|
||||
for (const auto &RCs : RCsGroupedByWord) {
|
||||
OS << " // " << LowestIdxInWord << "-" << (LowestIdxInWord + 31) << "\n";
|
||||
OS << " // " << LowestIdxInWord << "-" << (LowestIdxInWord + 31)
|
||||
<< "\n";
|
||||
for (const auto &RC : RCs) {
|
||||
OS << " (1u << (" << RC->getQualifiedIdName() << " - "
|
||||
<< LowestIdxInWord << ")) |\n";
|
||||
|
||||
@@ -101,8 +101,8 @@ private:
|
||||
} // end anonymous namespace
|
||||
|
||||
// runEnums - Print out enum values for all of the registers.
|
||||
void RegisterInfoEmitter::runEnums(raw_ostream &OS,
|
||||
CodeGenTarget &Target, CodeGenRegBank &Bank) {
|
||||
void RegisterInfoEmitter::runEnums(raw_ostream &OS, CodeGenTarget &Target,
|
||||
CodeGenRegBank &Bank) {
|
||||
const auto &Registers = Bank.getRegisters();
|
||||
|
||||
// Register enums are stored as uint16_t in the tables. Make sure we'll fit.
|
||||
@@ -129,7 +129,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
|
||||
OS << " " << Reg.getName() << " = " << Reg.EnumValue << ",\n";
|
||||
assert(Registers.size() == Registers.back().EnumValue &&
|
||||
"Register enum value mismatch!");
|
||||
OS << " NUM_TARGET_REGS // " << Registers.size()+1 << "\n";
|
||||
OS << " NUM_TARGET_REGS // " << Registers.size() + 1 << "\n";
|
||||
OS << "};\n";
|
||||
if (!Namespace.empty())
|
||||
OS << "} // end namespace " << Namespace << "\n";
|
||||
@@ -152,7 +152,8 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
|
||||
OS << "} // end namespace " << Namespace << "\n\n";
|
||||
}
|
||||
|
||||
const std::vector<Record*> &RegAltNameIndices = Target.getRegAltNameIndices();
|
||||
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) {
|
||||
@@ -188,7 +189,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
|
||||
OS << "namespace " << Namespace << " {\n";
|
||||
OS << "enum RegisterPressureSets {\n";
|
||||
unsigned NumSets = Bank.getNumRegPressureSets();
|
||||
for (unsigned i = 0; i < NumSets; ++i ) {
|
||||
for (unsigned i = 0; i < NumSets; ++i) {
|
||||
const RegUnitSet &RegUnits = Bank.getRegSetAt(i);
|
||||
OS << " " << RegUnits.Name << " = " << i << ",\n";
|
||||
}
|
||||
@@ -201,13 +202,11 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
|
||||
OS << "#endif // GET_REGINFO_ENUM\n\n";
|
||||
}
|
||||
|
||||
static void printInt(raw_ostream &OS, int Val) {
|
||||
OS << Val;
|
||||
}
|
||||
static void printInt(raw_ostream &OS, int Val) { OS << Val; }
|
||||
|
||||
void RegisterInfoEmitter::
|
||||
EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
|
||||
const std::string &ClassName) {
|
||||
void RegisterInfoEmitter::EmitRegUnitPressure(raw_ostream &OS,
|
||||
const CodeGenRegBank &RegBank,
|
||||
const std::string &ClassName) {
|
||||
unsigned NumRCs = RegBank.getRegClasses().size();
|
||||
unsigned NumSets = RegBank.getNumRegPressureSets();
|
||||
|
||||
@@ -254,8 +253,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
|
||||
}
|
||||
OS << "};\n"
|
||||
<< " return RUWeightTable[RegUnit];\n";
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
OS << " // All register units have unit weight.\n"
|
||||
<< " return 1;\n";
|
||||
}
|
||||
@@ -271,7 +269,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
|
||||
<< "getRegPressureSetName(unsigned Idx) const {\n"
|
||||
<< " static const char *PressureNameTable[] = {\n";
|
||||
unsigned MaxRegUnitWeight = 0;
|
||||
for (unsigned i = 0; i < NumSets; ++i ) {
|
||||
for (unsigned i = 0; i < NumSets; ++i) {
|
||||
const RegUnitSet &RegUnits = RegBank.getRegSetAt(i);
|
||||
MaxRegUnitWeight = std::max(MaxRegUnitWeight, RegUnits.Weight);
|
||||
OS << " \"" << RegUnits.Name << "\",\n";
|
||||
@@ -287,10 +285,10 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
|
||||
"{\n"
|
||||
<< " static const " << getMinimalTypeForRange(MaxRegUnitWeight, 32)
|
||||
<< " PressureLimitTable[] = {\n";
|
||||
for (unsigned i = 0; i < NumSets; ++i ) {
|
||||
for (unsigned i = 0; i < NumSets; ++i) {
|
||||
const RegUnitSet &RegUnits = RegBank.getRegSetAt(i);
|
||||
OS << " " << RegUnits.Weight << ", \t// " << i << ": "
|
||||
<< RegUnits.Name << "\n";
|
||||
OS << " " << RegUnits.Weight << ", \t// " << i << ": " << RegUnits.Name
|
||||
<< "\n";
|
||||
}
|
||||
OS << " };\n"
|
||||
<< " return PressureLimitTable[Idx];\n"
|
||||
@@ -353,7 +351,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
|
||||
<< "}\n\n";
|
||||
}
|
||||
|
||||
using DwarfRegNumsMapPair = std::pair<Record*, std::vector<int64_t>>;
|
||||
using DwarfRegNumsMapPair = std::pair<Record *, std::vector<int64_t>>;
|
||||
using DwarfRegNumsVecTy = std::vector<DwarfRegNumsMapPair>;
|
||||
|
||||
static void finalizeDwarfRegNumsKeys(DwarfRegNumsVecTy &DwarfRegNums) {
|
||||
@@ -419,7 +417,7 @@ void RegisterInfoEmitter::EmitRegMappingTables(
|
||||
|
||||
// Store the mapping sorted by the LLVM reg num so lookup can be done
|
||||
// with a binary search.
|
||||
std::map<uint64_t, Record*> Dwarf2LMap;
|
||||
std::map<uint64_t, Record *> Dwarf2LMap;
|
||||
for (auto &DwarfRegNum : DwarfRegNums) {
|
||||
int DwarfRegNo = DwarfRegNum.second[I];
|
||||
if (DwarfRegNo < 0)
|
||||
@@ -531,8 +529,8 @@ void RegisterInfoEmitter::EmitRegMapping(
|
||||
else
|
||||
OS << "EHFlavour";
|
||||
OS << ") {\n"
|
||||
<< " default:\n"
|
||||
<< " llvm_unreachable(\"Unknown DWARF flavour\");\n";
|
||||
<< " default:\n"
|
||||
<< " llvm_unreachable(\"Unknown DWARF flavour\");\n";
|
||||
|
||||
for (unsigned i = 0, e = maxLength; i != e; ++i) {
|
||||
OS << " case " << i << ":\n";
|
||||
@@ -540,14 +538,14 @@ void RegisterInfoEmitter::EmitRegMapping(
|
||||
if (!isCtor)
|
||||
OS << "RI->";
|
||||
std::string Tmp;
|
||||
raw_string_ostream(Tmp) << Namespace
|
||||
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << i
|
||||
<< "Dwarf2L";
|
||||
raw_string_ostream(Tmp)
|
||||
<< Namespace << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i
|
||||
<< "Dwarf2L";
|
||||
OS << "mapDwarfRegsToLLVMRegs(" << Tmp << ", " << Tmp << "Size, ";
|
||||
if (j == 0)
|
||||
OS << "false";
|
||||
else
|
||||
OS << "true";
|
||||
OS << "false";
|
||||
else
|
||||
OS << "true";
|
||||
OS << ");\n";
|
||||
OS << " break;\n";
|
||||
}
|
||||
@@ -571,14 +569,14 @@ void RegisterInfoEmitter::EmitRegMapping(
|
||||
if (!isCtor)
|
||||
OS << "RI->";
|
||||
std::string Tmp;
|
||||
raw_string_ostream(Tmp) << Namespace
|
||||
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << i
|
||||
<< "L2Dwarf";
|
||||
raw_string_ostream(Tmp)
|
||||
<< Namespace << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i
|
||||
<< "L2Dwarf";
|
||||
OS << "mapLLVMRegsToDwarfRegs(" << Tmp << ", " << Tmp << "Size, ";
|
||||
if (j == 0)
|
||||
OS << "false";
|
||||
else
|
||||
OS << "true";
|
||||
OS << "false";
|
||||
else
|
||||
OS << "true";
|
||||
OS << ");\n";
|
||||
OS << " break;\n";
|
||||
}
|
||||
@@ -588,8 +586,7 @@ void RegisterInfoEmitter::EmitRegMapping(
|
||||
|
||||
// Print a BitVector as a sequence of hex numbers using a little-endian mapping.
|
||||
// Width is the number of bits per hex number.
|
||||
static void printBitVectorAsHex(raw_ostream &OS,
|
||||
const BitVector &Bits,
|
||||
static void printBitVectorAsHex(raw_ostream &OS, const BitVector &Bits,
|
||||
unsigned Width) {
|
||||
assert(Width <= 32 && "Width too large");
|
||||
unsigned Digits = (Width + 3) / 4;
|
||||
@@ -604,16 +601,15 @@ static void printBitVectorAsHex(raw_ostream &OS,
|
||||
// Helper to emit a set of bits into a constant byte array.
|
||||
class BitVectorEmitter {
|
||||
BitVector Values;
|
||||
|
||||
public:
|
||||
void add(unsigned v) {
|
||||
if (v >= Values.size())
|
||||
Values.resize(((v/8)+1)*8); // Round up to the next byte.
|
||||
Values.resize(((v / 8) + 1) * 8); // Round up to the next byte.
|
||||
Values[v] = true;
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) {
|
||||
printBitVectorAsHex(OS, Values, 8);
|
||||
}
|
||||
void print(raw_ostream &OS) { printBitVectorAsHex(OS, Values, 8); }
|
||||
};
|
||||
|
||||
static void printSimpleValueType(raw_ostream &OS, MVT::SimpleValueType VT) {
|
||||
@@ -650,9 +646,8 @@ static DiffVec &diffEncode(DiffVec &V, SparseBitVector<> List) {
|
||||
return V;
|
||||
}
|
||||
|
||||
template<typename Iter>
|
||||
static
|
||||
DiffVec &diffEncode(DiffVec &V, unsigned InitVal, Iter Begin, Iter End) {
|
||||
template <typename Iter>
|
||||
static DiffVec &diffEncode(DiffVec &V, unsigned InitVal, Iter Begin, Iter End) {
|
||||
assert(V.empty() && "Clear DiffVec before diffEncode.");
|
||||
unsigned Val = InitVal;
|
||||
for (Iter I = Begin; I != End; ++I) {
|
||||
@@ -672,7 +667,7 @@ static void printMask(raw_ostream &OS, LaneBitmask Val) {
|
||||
// Try to combine Idx's compose map into Vec if it is compatible.
|
||||
// Return false if it's not possible.
|
||||
static bool combine(const CodeGenSubRegIndex *Idx,
|
||||
SmallVectorImpl<CodeGenSubRegIndex*> &Vec) {
|
||||
SmallVectorImpl<CodeGenSubRegIndex *> &Vec) {
|
||||
const CodeGenSubRegIndex::CompMap &Map = Idx->getComposites();
|
||||
for (const auto &I : Map) {
|
||||
CodeGenSubRegIndex *&Entry = Vec[I.first->EnumValue - 1];
|
||||
@@ -683,17 +678,15 @@ static bool combine(const CodeGenSubRegIndex *Idx,
|
||||
// All entries are compatible. Make it so.
|
||||
for (const auto &I : Map) {
|
||||
auto *&Entry = Vec[I.first->EnumValue - 1];
|
||||
assert((!Entry || Entry == I.second) &&
|
||||
"Expected EnumValue to be unique");
|
||||
assert((!Entry || Entry == I.second) && "Expected EnumValue to be unique");
|
||||
Entry = I.second;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
RegisterInfoEmitter::emitComposeSubRegIndices(raw_ostream &OS,
|
||||
CodeGenRegBank &RegBank,
|
||||
const std::string &ClName) {
|
||||
void RegisterInfoEmitter::emitComposeSubRegIndices(raw_ostream &OS,
|
||||
CodeGenRegBank &RegBank,
|
||||
const std::string &ClName) {
|
||||
const auto &SubRegIndices = RegBank.getSubRegIndices();
|
||||
OS << "unsigned " << ClName
|
||||
<< "::composeSubRegIndicesImpl(unsigned IdxA, unsigned IdxB) const {\n";
|
||||
@@ -707,7 +700,7 @@ RegisterInfoEmitter::emitComposeSubRegIndices(raw_ostream &OS,
|
||||
|
||||
// Map each Sub-register index to a compatible table row.
|
||||
SmallVector<unsigned, 4> RowMap;
|
||||
SmallVector<SmallVector<CodeGenSubRegIndex*, 4>, 4> Rows;
|
||||
SmallVector<SmallVector<CodeGenSubRegIndex *, 4>, 4> Rows;
|
||||
|
||||
auto SubRegIndicesSize =
|
||||
std::distance(SubRegIndices.begin(), SubRegIndices.end());
|
||||
@@ -760,10 +753,8 @@ RegisterInfoEmitter::emitComposeSubRegIndices(raw_ostream &OS,
|
||||
OS << "}\n\n";
|
||||
}
|
||||
|
||||
void
|
||||
RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS,
|
||||
CodeGenRegBank &RegBank,
|
||||
const std::string &ClName) {
|
||||
void RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(
|
||||
raw_ostream &OS, CodeGenRegBank &RegBank, const std::string &ClName) {
|
||||
// See the comments in computeSubRegLaneMasks() for our goal here.
|
||||
const auto &SubRegIndices = RegBank.getSubRegIndices();
|
||||
|
||||
@@ -771,8 +762,8 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS,
|
||||
SmallVector<unsigned, 4> SubReg2SequenceIndexMap;
|
||||
SmallVector<SmallVector<MaskRolPair, 1>, 4> Sequences;
|
||||
for (const auto &Idx : SubRegIndices) {
|
||||
const SmallVector<MaskRolPair, 1> &IdxSequence
|
||||
= Idx.CompositionLaneMaskTransform;
|
||||
const SmallVector<MaskRolPair, 1> &IdxSequence =
|
||||
Idx.CompositionLaneMaskTransform;
|
||||
|
||||
unsigned Found = ~0u;
|
||||
unsigned SIdx = 0;
|
||||
@@ -807,7 +798,7 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS,
|
||||
OS << format(", %2u }, ", P.RotateLeft);
|
||||
}
|
||||
OS << "{ LaneBitmask::getNone(), 0 }";
|
||||
if (s+1 != se)
|
||||
if (s + 1 != se)
|
||||
OS << ", ";
|
||||
OS << " // Sequence " << Idx << "\n";
|
||||
Idx += Sequence.size() + 1;
|
||||
@@ -820,7 +811,7 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS,
|
||||
for (size_t i = 0, e = SubRegIndices.size(); i != e; ++i) {
|
||||
OS << " ";
|
||||
OS << SubReg2SequenceIndexMap[i];
|
||||
if (i+1 != e)
|
||||
if (i + 1 != e)
|
||||
OS << ",";
|
||||
OS << " // to " << SubRegIndices[i].getName() << "\n";
|
||||
}
|
||||
@@ -829,15 +820,18 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS,
|
||||
OS << "LaneBitmask " << ClName
|
||||
<< "::composeSubRegIndexLaneMaskImpl(unsigned IdxA, LaneBitmask LaneMask)"
|
||||
" const {\n"
|
||||
" --IdxA; assert(IdxA < " << SubRegIndices.size()
|
||||
" --IdxA; assert(IdxA < "
|
||||
<< SubRegIndices.size()
|
||||
<< " && \"Subregister index out of bounds\");\n"
|
||||
" LaneBitmask Result;\n"
|
||||
" for (const MaskRolOp *Ops =\n"
|
||||
" &LaneMaskComposeSequences[CompositeSequences[IdxA]];\n"
|
||||
" Ops->Mask.any(); ++Ops) {\n"
|
||||
" LaneBitmask::Type M = LaneMask.getAsInteger() & Ops->Mask.getAsInteger();\n"
|
||||
" LaneBitmask::Type M = LaneMask.getAsInteger() & "
|
||||
"Ops->Mask.getAsInteger();\n"
|
||||
" if (unsigned S = Ops->RotateLeft)\n"
|
||||
" Result |= LaneBitmask((M << S) | (M >> (LaneBitmask::BitWidth - S)));\n"
|
||||
" Result |= LaneBitmask((M << S) | (M >> (LaneBitmask::BitWidth - "
|
||||
"S)));\n"
|
||||
" else\n"
|
||||
" Result |= LaneBitmask(M);\n"
|
||||
" }\n"
|
||||
@@ -848,7 +842,8 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS,
|
||||
<< "::reverseComposeSubRegIndexLaneMaskImpl(unsigned IdxA, "
|
||||
" LaneBitmask LaneMask) const {\n"
|
||||
" LaneMask &= getSubRegIndexLaneMask(IdxA);\n"
|
||||
" --IdxA; assert(IdxA < " << SubRegIndices.size()
|
||||
" --IdxA; assert(IdxA < "
|
||||
<< SubRegIndices.size()
|
||||
<< " && \"Subregister index out of bounds\");\n"
|
||||
" LaneBitmask Result;\n"
|
||||
" for (const MaskRolOp *Ops =\n"
|
||||
@@ -856,7 +851,8 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS,
|
||||
" Ops->Mask.any(); ++Ops) {\n"
|
||||
" LaneBitmask::Type M = LaneMask.getAsInteger();\n"
|
||||
" if (unsigned S = Ops->RotateLeft)\n"
|
||||
" Result |= LaneBitmask((M >> S) | (M << (LaneBitmask::BitWidth - S)));\n"
|
||||
" Result |= LaneBitmask((M >> S) | (M << (LaneBitmask::BitWidth - "
|
||||
"S)));\n"
|
||||
" else\n"
|
||||
" Result |= LaneBitmask(M);\n"
|
||||
" }\n"
|
||||
@@ -867,9 +863,8 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS,
|
||||
//
|
||||
// runMCDesc - Print out MC register descriptions.
|
||||
//
|
||||
void
|
||||
RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
CodeGenRegBank &RegBank) {
|
||||
void RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
CodeGenRegBank &RegBank) {
|
||||
emitSourceFileHeader("MC Register Information", OS);
|
||||
|
||||
OS << "\n#ifdef GET_REGINFO_MC_DESC\n";
|
||||
@@ -880,7 +875,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
auto &SubRegIndices = RegBank.getSubRegIndices();
|
||||
// The lists of sub-registers and super-registers go in the same array. That
|
||||
// allows us to share suffixes.
|
||||
typedef std::vector<const CodeGenRegister*> RegVec;
|
||||
typedef std::vector<const CodeGenRegister *> RegVec;
|
||||
|
||||
// Differentially encoded lists.
|
||||
SequenceToOffsetTable<DiffVec> DiffSeqs;
|
||||
@@ -894,7 +889,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
|
||||
// Keep track of sub-register names as well. These are not differentially
|
||||
// encoded.
|
||||
typedef SmallVector<const CodeGenSubRegIndex*, 4> SubRegIdxVec;
|
||||
typedef SmallVector<const CodeGenSubRegIndex *, 4> SubRegIdxVec;
|
||||
SequenceToOffsetTable<SubRegIdxVec, deref<std::less<>>> SubRegIdxSeqs;
|
||||
SmallVector<SubRegIdxVec, 4> SubRegIdxLists(Regs.size());
|
||||
|
||||
@@ -907,7 +902,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
RegStrings.add(std::string(Reg.getName()));
|
||||
|
||||
// Compute the ordered sub-register list.
|
||||
SetVector<const CodeGenRegister*> SR;
|
||||
SetVector<const CodeGenRegister *> SR;
|
||||
Reg.addSubRegsPreOrder(SR, RegBank);
|
||||
diffEncode(SubRegLists[i], Reg.EnumValue, SR.begin(), SR.end());
|
||||
DiffSeqs.add(SubRegLists[i]);
|
||||
@@ -961,8 +956,8 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
OS << "};\n\n";
|
||||
|
||||
// Emit the table of sub-register index sizes.
|
||||
OS << "extern const MCRegisterInfo::SubRegCoveredBits "
|
||||
<< TargetName << "SubRegIdxRanges[] = {\n";
|
||||
OS << "extern const MCRegisterInfo::SubRegCoveredBits " << TargetName
|
||||
<< "SubRegIdxRanges[] = {\n";
|
||||
OS << " { " << (uint16_t)-1 << ", " << (uint16_t)-1 << " },\n";
|
||||
for (const auto &Idx : SubRegIndices) {
|
||||
OS << " { " << Idx.Offset << ", " << Idx.Size << " },\t// "
|
||||
@@ -995,13 +990,13 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
<< LaneMaskSeqs.get(RegUnitLaneMasks[i]) << " },\n";
|
||||
++i;
|
||||
}
|
||||
OS << "};\n\n"; // End of register descriptors...
|
||||
OS << "};\n\n"; // End of register descriptors...
|
||||
|
||||
// Emit the table of register unit roots. Each regunit has one or two root
|
||||
// registers.
|
||||
OS << "extern const MCPhysReg " << TargetName << "RegUnitRoots[][2] = {\n";
|
||||
for (unsigned i = 0, e = RegBank.getNumNativeRegUnits(); i != e; ++i) {
|
||||
ArrayRef<const CodeGenRegister*> Roots = RegBank.getRegUnit(i).getRoots();
|
||||
ArrayRef<const CodeGenRegister *> Roots = RegBank.getRegUnit(i).getRoots();
|
||||
assert(!Roots.empty() && "All regunits must have a root register.");
|
||||
assert(Roots.size() <= 2 && "More than two roots not supported yet.");
|
||||
OS << " { ";
|
||||
@@ -1021,7 +1016,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
|
||||
// Emit the register enum value arrays for each RegisterClass
|
||||
for (const auto &RC : RegisterClasses) {
|
||||
ArrayRef<Record*> Order = RC.getOrder();
|
||||
ArrayRef<Record *> Order = RC.getOrder();
|
||||
|
||||
// Give the register class a legal C name if it's anonymous.
|
||||
const std::string &Name = RC.getName();
|
||||
@@ -1092,7 +1087,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
}
|
||||
OS << " " << Value << ",\n";
|
||||
}
|
||||
OS << "};\n"; // End of HW encoding table
|
||||
OS << "};\n"; // End of HW encoding table
|
||||
|
||||
// MCRegisterInfo initialization routine.
|
||||
OS << "static inline void Init" << TargetName
|
||||
@@ -1117,9 +1112,9 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
OS << "#endif // GET_REGINFO_MC_DESC\n\n";
|
||||
}
|
||||
|
||||
void
|
||||
RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
|
||||
CodeGenRegBank &RegBank) {
|
||||
void RegisterInfoEmitter::runTargetHeader(raw_ostream &OS,
|
||||
CodeGenTarget &Target,
|
||||
CodeGenRegBank &RegBank) {
|
||||
emitSourceFileHeader("Register Information Header Fragment", OS);
|
||||
|
||||
OS << "\n#ifdef GET_REGINFO_HEADER\n";
|
||||
@@ -1175,8 +1170,10 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
|
||||
<< " const MachineFunction &MF);\n";
|
||||
|
||||
const auto &RegisterClasses = RegBank.getRegClasses();
|
||||
if (llvm::any_of(RegisterClasses, [](const auto &RC) { return RC.getBaseClassOrder(); })) {
|
||||
OS << " const TargetRegisterClass *getPhysRegBaseClass(MCRegister Reg) const override;\n";
|
||||
if (llvm::any_of(RegisterClasses,
|
||||
[](const auto &RC) { return RC.getBaseClassOrder(); })) {
|
||||
OS << " const TargetRegisterClass *getPhysRegBaseClass(MCRegister Reg) "
|
||||
"const override;\n";
|
||||
}
|
||||
|
||||
OS << "};\n\n";
|
||||
@@ -1200,9 +1197,8 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
|
||||
//
|
||||
// runTargetDesc - Output the target register and register file descriptions.
|
||||
//
|
||||
void
|
||||
RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
CodeGenRegBank &RegBank){
|
||||
void RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
CodeGenRegBank &RegBank) {
|
||||
emitSourceFileHeader("Target Register and Register Classes Information", OS);
|
||||
|
||||
OS << "\n#ifdef GET_REGINFO_TARGET_DESC\n";
|
||||
@@ -1219,11 +1215,11 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
const auto &SubRegIndices = RegBank.getSubRegIndices();
|
||||
|
||||
// Collect all registers belonging to any allocatable class.
|
||||
std::set<Record*> AllocatableRegs;
|
||||
std::set<Record *> AllocatableRegs;
|
||||
|
||||
// Collect allocatable registers.
|
||||
for (const auto &RC : RegisterClasses) {
|
||||
ArrayRef<Record*> Order = RC.getOrder();
|
||||
ArrayRef<Record *> Order = RC.getOrder();
|
||||
|
||||
if (RC.Allocatable)
|
||||
AllocatableRegs.insert(Order.begin(), Order.end());
|
||||
@@ -1297,7 +1293,6 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
}
|
||||
OS << "};\n";
|
||||
|
||||
|
||||
OS << "\nstatic const TargetRegisterClass *const "
|
||||
<< "NullRegClasses[] = { nullptr };\n\n";
|
||||
|
||||
@@ -1320,7 +1315,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
// Every bit mask present in the list has at least one bit set.
|
||||
|
||||
// Compress the sub-reg index lists.
|
||||
typedef std::vector<const CodeGenSubRegIndex*> IdxList;
|
||||
typedef std::vector<const CodeGenSubRegIndex *> IdxList;
|
||||
SmallVector<IdxList, 8> SuperRegIdxLists(RegisterClasses.size());
|
||||
SequenceToOffsetTable<IdxList, deref<std::less<>>> SuperRegIdxSeqs;
|
||||
BitVector MaskBV(RegisterClasses.size());
|
||||
@@ -1354,14 +1349,14 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
|
||||
// Emit NULL terminated super-class lists.
|
||||
for (const auto &RC : RegisterClasses) {
|
||||
ArrayRef<CodeGenRegisterClass*> Supers = RC.getSuperClasses();
|
||||
ArrayRef<CodeGenRegisterClass *> Supers = RC.getSuperClasses();
|
||||
|
||||
// Skip classes without supers. We can reuse NullRegClasses.
|
||||
if (Supers.empty())
|
||||
continue;
|
||||
|
||||
OS << "static const TargetRegisterClass *const "
|
||||
<< RC.getName() << "Superclasses[] = {\n";
|
||||
OS << "static const TargetRegisterClass *const " << RC.getName()
|
||||
<< "Superclasses[] = {\n";
|
||||
for (const auto *Super : Supers)
|
||||
OS << " &" << Super->getQualifiedName() << "RegClass,\n";
|
||||
OS << " nullptr\n};\n\n";
|
||||
@@ -1371,12 +1366,12 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
for (const auto &RC : RegisterClasses) {
|
||||
if (!RC.AltOrderSelect.empty()) {
|
||||
OS << "\nstatic inline unsigned " << RC.getName()
|
||||
<< "AltOrderSelect(const MachineFunction &MF) {"
|
||||
<< RC.AltOrderSelect << "}\n\n"
|
||||
<< "AltOrderSelect(const MachineFunction &MF) {" << RC.AltOrderSelect
|
||||
<< "}\n\n"
|
||||
<< "static ArrayRef<MCPhysReg> " << RC.getName()
|
||||
<< "GetRawAllocationOrder(const MachineFunction &MF) {\n";
|
||||
for (unsigned oi = 1 , oe = RC.getNumOrders(); oi != oe; ++oi) {
|
||||
ArrayRef<Record*> Elems = RC.getOrder(oi);
|
||||
for (unsigned oi = 1, oe = RC.getNumOrders(); oi != oe; ++oi) {
|
||||
ArrayRef<Record *> Elems = RC.getOrder(oi);
|
||||
if (!Elems.empty()) {
|
||||
OS << " static const MCPhysReg AltOrder" << oi << "[] = {";
|
||||
for (unsigned elem = 0; elem != Elems.size(); ++elem)
|
||||
@@ -1556,8 +1551,8 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
EnumValue = SubRegClass->EnumValue + 1;
|
||||
}
|
||||
|
||||
OS << " " << EnumValue << ",\t// "
|
||||
<< RC.getName() << ':' << Idx.getName();
|
||||
OS << " " << EnumValue << ",\t// " << RC.getName() << ':'
|
||||
<< Idx.getName();
|
||||
|
||||
if (MatchingSubClass) {
|
||||
CodeGenRegisterClass *SubRegClass = MatchingSubClass->second;
|
||||
@@ -1581,7 +1576,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
// Emit register base class mapper
|
||||
if (!RegisterClasses.empty()) {
|
||||
// Collect base classes
|
||||
SmallVector<const CodeGenRegisterClass*> BaseClasses;
|
||||
SmallVector<const CodeGenRegisterClass *> BaseClasses;
|
||||
for (const auto &RC : RegisterClasses) {
|
||||
if (RC.getBaseClassOrder())
|
||||
BaseClasses.push_back(&RC);
|
||||
@@ -1592,9 +1587,10 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
|
||||
// Apply order
|
||||
struct BaseClassOrdering {
|
||||
bool operator()(const CodeGenRegisterClass *LHS, const CodeGenRegisterClass *RHS) const {
|
||||
return std::pair(*LHS->getBaseClassOrder(), LHS->EnumValue)
|
||||
< std::pair(*RHS->getBaseClassOrder(), RHS->EnumValue);
|
||||
bool operator()(const CodeGenRegisterClass *LHS,
|
||||
const CodeGenRegisterClass *RHS) const {
|
||||
return std::pair(*LHS->getBaseClassOrder(), LHS->EnumValue) <
|
||||
std::pair(*RHS->getBaseClassOrder(), RHS->EnumValue);
|
||||
}
|
||||
};
|
||||
llvm::stable_sort(BaseClasses, BaseClassOrdering());
|
||||
@@ -1638,8 +1634,8 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
OS << "extern const char " << TargetName << "RegClassStrings[];\n";
|
||||
OS << "extern const MCPhysReg " << TargetName << "RegUnitRoots[][2];\n";
|
||||
OS << "extern const uint16_t " << TargetName << "SubRegIdxLists[];\n";
|
||||
OS << "extern const MCRegisterInfo::SubRegCoveredBits "
|
||||
<< TargetName << "SubRegIdxRanges[];\n";
|
||||
OS << "extern const MCRegisterInfo::SubRegCoveredBits " << TargetName
|
||||
<< "SubRegIdxRanges[];\n";
|
||||
OS << "extern const uint16_t " << TargetName << "RegEncodingTable[];\n";
|
||||
|
||||
EmitRegMappingTables(OS, Regs, true);
|
||||
@@ -1673,16 +1669,15 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
OS << "}\n\n";
|
||||
|
||||
// Emit CalleeSavedRegs information.
|
||||
std::vector<Record*> CSRSets =
|
||||
Records.getAllDerivedDefinitions("CalleeSavedRegs");
|
||||
std::vector<Record *> CSRSets =
|
||||
Records.getAllDerivedDefinitions("CalleeSavedRegs");
|
||||
for (unsigned i = 0, e = CSRSets.size(); i != e; ++i) {
|
||||
Record *CSRSet = CSRSets[i];
|
||||
const SetTheory::RecVec *Regs = RegBank.getSets().expand(CSRSet);
|
||||
assert(Regs && "Cannot expand CalleeSavedRegs instance");
|
||||
|
||||
// Emit the *_SaveList list of callee-saved registers.
|
||||
OS << "static const MCPhysReg " << CSRSet->getName()
|
||||
<< "_SaveList[] = { ";
|
||||
OS << "static const MCPhysReg " << CSRSet->getName() << "_SaveList[] = { ";
|
||||
for (unsigned r = 0, re = Regs->size(); r != re; ++r)
|
||||
OS << getQualifiedName((*Regs)[r]) << ", ";
|
||||
OS << "0 };\n";
|
||||
@@ -1693,11 +1688,11 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
// Check for an optional OtherPreserved set.
|
||||
// Add those registers to RegMask, but not to SaveList.
|
||||
if (DagInit *OPDag =
|
||||
dyn_cast<DagInit>(CSRSet->getValueInit("OtherPreserved"))) {
|
||||
dyn_cast<DagInit>(CSRSet->getValueInit("OtherPreserved"))) {
|
||||
SetTheory::RecSet OPSet;
|
||||
RegBank.getSets().evaluate(OPDag, OPSet, CSRSet->getLoc());
|
||||
Covered |= RegBank.computeCoveredRegisters(
|
||||
ArrayRef<Record*>(OPSet.begin(), OPSet.end()));
|
||||
ArrayRef<Record *>(OPSet.begin(), OPSet.end()));
|
||||
}
|
||||
|
||||
// Add all constant physical registers to the preserved mask:
|
||||
@@ -1709,8 +1704,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
Covered |= RegBank.computeCoveredRegisters(
|
||||
ArrayRef<Record *>(ConstantSet.begin(), ConstantSet.end()));
|
||||
|
||||
OS << "static const uint32_t " << CSRSet->getName()
|
||||
<< "_RegMask[] = { ";
|
||||
OS << "static const uint32_t " << CSRSet->getName() << "_RegMask[] = { ";
|
||||
printBitVectorAsHex(OS, Covered, 32);
|
||||
OS << "};\n";
|
||||
}
|
||||
@@ -1795,7 +1789,8 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
|
||||
}
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "const " << TargetName << "FrameLowering *\n" << TargetName
|
||||
OS << "const " << TargetName << "FrameLowering *\n"
|
||||
<< TargetName
|
||||
<< "GenRegisterInfo::getFrameLowering(const MachineFunction &MF) {\n"
|
||||
<< " return static_cast<const " << TargetName << "FrameLowering *>(\n"
|
||||
<< " MF.getSubtarget().getFrameLowering());\n"
|
||||
@@ -1827,7 +1822,7 @@ void RegisterInfoEmitter::debugDump(raw_ostream &OS) {
|
||||
CodeGenRegBank &RegBank = Target.getRegBank();
|
||||
const CodeGenHwModes &CGH = Target.getHwModes();
|
||||
unsigned NumModes = CGH.getNumModeIds();
|
||||
auto getModeName = [CGH] (unsigned M) -> StringRef {
|
||||
auto getModeName = [CGH](unsigned M) -> StringRef {
|
||||
if (M == 0)
|
||||
return "Default";
|
||||
return CGH.getMode(M).Name;
|
||||
@@ -1883,9 +1878,10 @@ void RegisterInfoEmitter::debugDump(raw_ostream &OS) {
|
||||
OS << '\n';
|
||||
OS << "\tCoveredBySubregs: " << R.CoveredBySubRegs << '\n';
|
||||
OS << "\tHasDisjunctSubRegs: " << R.HasDisjunctSubRegs << '\n';
|
||||
for (std::pair<CodeGenSubRegIndex*,CodeGenRegister*> P : R.getSubRegs()) {
|
||||
OS << "\tSubReg " << P.first->getName()
|
||||
<< " = " << P.second->getName() << '\n';
|
||||
for (std::pair<CodeGenSubRegIndex *, CodeGenRegister *> P :
|
||||
R.getSubRegs()) {
|
||||
OS << "\tSubReg " << P.first->getName() << " = " << P.second->getName()
|
||||
<< '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,6 @@ enum SDNP {
|
||||
|
||||
unsigned parseSDPatternOperatorProperties(Record *R);
|
||||
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
||||
@@ -134,7 +134,7 @@ private:
|
||||
Twine("Entry for field '") + Field.Name + "' is null");
|
||||
return std::string(Entry->first);
|
||||
}
|
||||
PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name +
|
||||
PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name +
|
||||
"'; expected: bit, bits, string, or code");
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ private:
|
||||
return "uint32_t";
|
||||
if (NumBits <= 64)
|
||||
return "uint64_t";
|
||||
PrintFatalError(Index.Loc, Twine("In table '") + Table.Name +
|
||||
PrintFatalError(Index.Loc, Twine("In table '") + Table.Name +
|
||||
"' lookup method '" + Index.Name +
|
||||
"', key field '" + Field.Name +
|
||||
"' of type bits is too large");
|
||||
@@ -425,7 +425,7 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
|
||||
|
||||
OS << " struct KeyType {\n";
|
||||
for (const auto &Field : Index.Fields) {
|
||||
OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
|
||||
OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
|
||||
<< " " << Field.Name << ";\n";
|
||||
}
|
||||
OS << " };\n";
|
||||
@@ -436,7 +436,7 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
|
||||
if (isa<StringRecTy>(Field.RecType)) {
|
||||
OS << ".upper()";
|
||||
if (IsPrimary)
|
||||
PrintFatalError(Index.Loc,
|
||||
PrintFatalError(Index.Loc,
|
||||
Twine("In table '") + Table.Name +
|
||||
"', use a secondary lookup method for "
|
||||
"case-insensitive comparison of field '" +
|
||||
@@ -580,7 +580,7 @@ std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
|
||||
Twine("In table '") + Table.Name +
|
||||
"', 'PrimaryKey' or 'Key' refers to nonexistent field '" +
|
||||
FieldName + "'");
|
||||
|
||||
|
||||
Index->Fields.push_back(*Field);
|
||||
}
|
||||
|
||||
@@ -643,11 +643,11 @@ void SearchableTableEmitter::collectTableEntries(
|
||||
} else {
|
||||
RecTy *Ty = resolveTypes(Field.RecType, TI->getType());
|
||||
if (!Ty)
|
||||
PrintFatalError(EntryRec->getValue(Field.Name),
|
||||
PrintFatalError(EntryRec->getValue(Field.Name),
|
||||
Twine("Field '") + Field.Name + "' of table '" +
|
||||
Table.Name + "' entry has incompatible type: " +
|
||||
TI->getType()->getAsString() + " vs. " +
|
||||
Field.RecType->getAsString());
|
||||
Table.Name + "' entry has incompatible type: " +
|
||||
TI->getType()->getAsString() + " vs. " +
|
||||
Field.RecType->getAsString());
|
||||
Field.RecType = Ty;
|
||||
}
|
||||
}
|
||||
@@ -702,7 +702,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
|
||||
StringRef FilterClass = EnumRec->getValueAsString("FilterClass");
|
||||
Enum->Class = Records.getClass(FilterClass);
|
||||
if (!Enum->Class)
|
||||
PrintFatalError(EnumRec->getValue("FilterClass"),
|
||||
PrintFatalError(EnumRec->getValue("FilterClass"),
|
||||
Twine("Enum FilterClass '") + FilterClass +
|
||||
"' does not exist");
|
||||
|
||||
@@ -723,11 +723,13 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
|
||||
for (const auto &FieldName : Fields) {
|
||||
Table->Fields.emplace_back(FieldName); // Construct a GenericField.
|
||||
|
||||
if (auto TypeOfRecordVal = TableRec->getValue(("TypeOf_" + FieldName).str())) {
|
||||
if (!parseFieldType(Table->Fields.back(), TypeOfRecordVal->getValue())) {
|
||||
PrintError(TypeOfRecordVal,
|
||||
Twine("Table '") + Table->Name +
|
||||
"' has invalid 'TypeOf_" + FieldName +
|
||||
if (auto TypeOfRecordVal =
|
||||
TableRec->getValue(("TypeOf_" + FieldName).str())) {
|
||||
if (!parseFieldType(Table->Fields.back(),
|
||||
TypeOfRecordVal->getValue())) {
|
||||
PrintError(TypeOfRecordVal,
|
||||
Twine("Table '") + Table->Name + "' has invalid 'TypeOf_" +
|
||||
FieldName +
|
||||
"': " + TypeOfRecordVal->getValue()->getAsString());
|
||||
PrintFatalNote("The 'TypeOf_xxx' field must be a string naming a "
|
||||
"GenericEnum record, or \"code\"");
|
||||
@@ -737,9 +739,9 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
|
||||
|
||||
StringRef FilterClass = TableRec->getValueAsString("FilterClass");
|
||||
if (!Records.getClass(FilterClass))
|
||||
PrintFatalError(TableRec->getValue("FilterClass"),
|
||||
Twine("Table FilterClass '") +
|
||||
FilterClass + "' does not exist");
|
||||
PrintFatalError(TableRec->getValue("FilterClass"),
|
||||
Twine("Table FilterClass '") + FilterClass +
|
||||
"' does not exist");
|
||||
|
||||
RecordVal *FilterClassFieldVal = TableRec->getValue("FilterClassField");
|
||||
std::vector<Record *> Definitions =
|
||||
@@ -779,14 +781,14 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
|
||||
Record *TableRec = IndexRec->getValueAsDef("Table");
|
||||
auto It = TableMap.find(TableRec);
|
||||
if (It == TableMap.end())
|
||||
PrintFatalError(IndexRec->getValue("Table"),
|
||||
PrintFatalError(IndexRec->getValue("Table"),
|
||||
Twine("SearchIndex '") + IndexRec->getName() +
|
||||
"' refers to nonexistent table '" +
|
||||
TableRec->getName());
|
||||
|
||||
GenericTable &Table = *It->second;
|
||||
Table.Indices.push_back(
|
||||
parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(),
|
||||
parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(),
|
||||
IndexRec->getValueAsListOfStrings("Key"),
|
||||
IndexRec->getValueAsBit("EarlyOut")));
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ static inline void printChar(raw_ostream &OS, char C) {
|
||||
///
|
||||
/// @tparam SeqT The sequence container. (vector or string).
|
||||
/// @tparam Less A stable comparator for SeqT elements.
|
||||
template<typename SeqT, typename Less = std::less<typename SeqT::value_type> >
|
||||
template <typename SeqT, typename Less = std::less<typename SeqT::value_type>>
|
||||
class SequenceToOffsetTable {
|
||||
typedef typename SeqT::value_type ElemT;
|
||||
|
||||
@@ -53,8 +53,8 @@ class SequenceToOffsetTable {
|
||||
struct SeqLess {
|
||||
Less L;
|
||||
bool operator()(const SeqT &A, const SeqT &B) const {
|
||||
return std::lexicographical_compare(A.rbegin(), A.rend(),
|
||||
B.rbegin(), B.rend(), L);
|
||||
return std::lexicographical_compare(A.rbegin(), A.rend(), B.rbegin(),
|
||||
B.rend(), L);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -153,15 +153,15 @@ public:
|
||||
|
||||
/// emit - Print out the table as the body of an array initializer.
|
||||
/// Use the Print function to print elements.
|
||||
void emit(raw_ostream &OS,
|
||||
void (*Print)(raw_ostream&, ElemT),
|
||||
void emit(raw_ostream &OS, void (*Print)(raw_ostream &, ElemT),
|
||||
const char *Term = "0") const {
|
||||
assert((empty() || Entries) && "Call layout() before emit()");
|
||||
for (typename SeqMap::const_iterator I = Seqs.begin(), E = Seqs.end();
|
||||
I != E; ++I) {
|
||||
OS << " /* " << I->second << " */ ";
|
||||
for (typename SeqT::const_iterator SI = I->first.begin(),
|
||||
SE = I->first.end(); SI != SE; ++SI) {
|
||||
SE = I->first.end();
|
||||
SI != SE; ++SI) {
|
||||
Print(OS, *SI);
|
||||
OS << ", ";
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ struct LessRecordFieldFieldName {
|
||||
};
|
||||
|
||||
class SubtargetEmitter {
|
||||
// Each processor has a SchedClassDesc table with an entry for each SchedClass.
|
||||
// The SchedClassDesc table indexes into a global write resource table, write
|
||||
// latency table, and read advance table.
|
||||
// Each processor has a SchedClassDesc table with an entry for each
|
||||
// SchedClass. The SchedClassDesc table indexes into a global write resource
|
||||
// table, write latency table, and read advance table.
|
||||
struct SchedClassTables {
|
||||
std::vector<std::vector<MCSchedClassDesc>> ProcSchedClasses;
|
||||
std::vector<MCWriteProcResEntry> WriteProcResources;
|
||||
@@ -89,20 +89,18 @@ class SubtargetEmitter {
|
||||
const DenseMap<Record *, unsigned> &FeatureMap);
|
||||
unsigned CPUKeyValues(raw_ostream &OS,
|
||||
const DenseMap<Record *, unsigned> &FeatureMap);
|
||||
void FormItineraryStageString(const std::string &Names,
|
||||
Record *ItinData, std::string &ItinString,
|
||||
unsigned &NStages);
|
||||
void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString,
|
||||
void FormItineraryStageString(const std::string &Names, Record *ItinData,
|
||||
std::string &ItinString, unsigned &NStages);
|
||||
void FormItineraryOperandCycleString(Record *ItinData,
|
||||
std::string &ItinString,
|
||||
unsigned &NOperandCycles);
|
||||
void FormItineraryBypassString(const std::string &Names,
|
||||
Record *ItinData,
|
||||
std::string &ItinString, unsigned NOperandCycles);
|
||||
void EmitStageAndOperandCycleData(raw_ostream &OS,
|
||||
std::vector<std::vector<InstrItinerary>>
|
||||
&ProcItinLists);
|
||||
void FormItineraryBypassString(const std::string &Names, Record *ItinData,
|
||||
std::string &ItinString,
|
||||
unsigned NOperandCycles);
|
||||
void EmitStageAndOperandCycleData(
|
||||
raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists);
|
||||
void EmitItineraries(raw_ostream &OS,
|
||||
std::vector<std::vector<InstrItinerary>>
|
||||
&ProcItinLists);
|
||||
std::vector<std::vector<InstrItinerary>> &ProcItinLists);
|
||||
unsigned EmitRegisterFileTables(const CodeGenProcModel &ProcModel,
|
||||
raw_ostream &OS);
|
||||
void EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel,
|
||||
@@ -153,15 +151,16 @@ public:
|
||||
void SubtargetEmitter::Enumeration(raw_ostream &OS,
|
||||
DenseMap<Record *, unsigned> &FeatureMap) {
|
||||
// Get all records of class and sort
|
||||
std::vector<Record*> DefList =
|
||||
Records.getAllDerivedDefinitions("SubtargetFeature");
|
||||
std::vector<Record *> DefList =
|
||||
Records.getAllDerivedDefinitions("SubtargetFeature");
|
||||
llvm::sort(DefList, LessRecord());
|
||||
|
||||
unsigned N = DefList.size();
|
||||
if (N == 0)
|
||||
return;
|
||||
if (N + 1 > MAX_SUBTARGET_FEATURES)
|
||||
PrintFatalError("Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");
|
||||
PrintFatalError(
|
||||
"Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");
|
||||
|
||||
OS << "namespace " << Target << " {\n";
|
||||
|
||||
@@ -248,8 +247,8 @@ void SubtargetEmitter::EmitSubtargetInfoMacroCalls(raw_ostream &OS) {
|
||||
unsigned SubtargetEmitter::FeatureKeyValues(
|
||||
raw_ostream &OS, const DenseMap<Record *, unsigned> &FeatureMap) {
|
||||
// Gather and sort all the features
|
||||
std::vector<Record*> FeatureList =
|
||||
Records.getAllDerivedDefinitions("SubtargetFeature");
|
||||
std::vector<Record *> FeatureList =
|
||||
Records.getAllDerivedDefinitions("SubtargetFeature");
|
||||
|
||||
if (FeatureList.empty())
|
||||
return 0;
|
||||
@@ -269,13 +268,14 @@ unsigned SubtargetEmitter::FeatureKeyValues(
|
||||
StringRef CommandLineName = Feature->getValueAsString("Name");
|
||||
StringRef Desc = Feature->getValueAsString("Desc");
|
||||
|
||||
if (CommandLineName.empty()) continue;
|
||||
if (CommandLineName.empty())
|
||||
continue;
|
||||
|
||||
// Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in } }
|
||||
// Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in
|
||||
// } }
|
||||
OS << " { "
|
||||
<< "\"" << CommandLineName << "\", "
|
||||
<< "\"" << Desc << "\", "
|
||||
<< Target << "::" << Name << ", ";
|
||||
<< "\"" << Desc << "\", " << Target << "::" << Name << ", ";
|
||||
|
||||
RecVec ImpliesList = Feature->getValueAsListOfDefs("Implies");
|
||||
|
||||
@@ -299,8 +299,8 @@ unsigned
|
||||
SubtargetEmitter::CPUKeyValues(raw_ostream &OS,
|
||||
const DenseMap<Record *, unsigned> &FeatureMap) {
|
||||
// Gather and sort processor information
|
||||
std::vector<Record*> ProcessorList =
|
||||
Records.getAllDerivedDefinitions("Processor");
|
||||
std::vector<Record *> ProcessorList =
|
||||
Records.getAllDerivedDefinitions("Processor");
|
||||
llvm::sort(ProcessorList, LessRecordFieldName());
|
||||
|
||||
// Begin processor table
|
||||
@@ -324,7 +324,7 @@ SubtargetEmitter::CPUKeyValues(raw_ostream &OS,
|
||||
|
||||
// Emit the scheduler model pointer.
|
||||
const std::string &ProcModelName =
|
||||
SchedModels.getModelForProc(Processor).ModelName;
|
||||
SchedModels.getModelForProc(Processor).ModelName;
|
||||
OS << ", &" << ProcModelName << " },\n";
|
||||
}
|
||||
|
||||
@@ -363,7 +363,8 @@ void SubtargetEmitter::FormItineraryStageString(const std::string &Name,
|
||||
for (unsigned j = 0, M = UnitList.size(); j < M;) {
|
||||
// Add name and bitwise or
|
||||
ItinString += Name + "FU::" + UnitList[j]->getName().str();
|
||||
if (++j < M) ItinString += " | ";
|
||||
if (++j < M)
|
||||
ItinString += " | ";
|
||||
}
|
||||
|
||||
int TimeInc = Stage->getValueAsInt("TimeInc");
|
||||
@@ -374,7 +375,8 @@ void SubtargetEmitter::FormItineraryStageString(const std::string &Name,
|
||||
|
||||
// Close off stage
|
||||
ItinString += " }";
|
||||
if (++i < N) ItinString += ", ";
|
||||
if (++i < N)
|
||||
ItinString += ", ";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,11 +385,11 @@ void SubtargetEmitter::FormItineraryStageString(const std::string &Name,
|
||||
// operand cycle initialization for the specified itinerary. N is the
|
||||
// number of operands that has cycles specified.
|
||||
//
|
||||
void SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData,
|
||||
std::string &ItinString, unsigned &NOperandCycles) {
|
||||
void SubtargetEmitter::FormItineraryOperandCycleString(
|
||||
Record *ItinData, std::string &ItinString, unsigned &NOperandCycles) {
|
||||
// Get operand cycle list
|
||||
std::vector<int64_t> OperandCycleList =
|
||||
ItinData->getValueAsListOfInts("OperandCycles");
|
||||
ItinData->getValueAsListOfInts("OperandCycles");
|
||||
|
||||
// For each operand cycle
|
||||
NOperandCycles = OperandCycleList.size();
|
||||
@@ -422,12 +424,10 @@ void SubtargetEmitter::FormItineraryBypassString(const std::string &Name,
|
||||
// cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed
|
||||
// by CodeGenSchedClass::Index.
|
||||
//
|
||||
void SubtargetEmitter::
|
||||
EmitStageAndOperandCycleData(raw_ostream &OS,
|
||||
std::vector<std::vector<InstrItinerary>>
|
||||
&ProcItinLists) {
|
||||
void SubtargetEmitter::EmitStageAndOperandCycleData(
|
||||
raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists) {
|
||||
// Multiple processor models may share an itinerary record. Emit it once.
|
||||
SmallPtrSet<Record*, 8> ItinsDefSet;
|
||||
SmallPtrSet<Record *, 8> ItinsDefSet;
|
||||
|
||||
// Emit functional units for all the itineraries.
|
||||
for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
|
||||
@@ -452,30 +452,31 @@ EmitStageAndOperandCycleData(raw_ostream &OS,
|
||||
RecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP");
|
||||
if (!BPs.empty()) {
|
||||
OS << "\n// Pipeline forwarding paths for itineraries \"" << Name
|
||||
<< "\"\n" << "namespace " << Name << "Bypass {\n";
|
||||
<< "\"\n"
|
||||
<< "namespace " << Name << "Bypass {\n";
|
||||
|
||||
OS << " const unsigned NoBypass = 0;\n";
|
||||
for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j)
|
||||
OS << " const unsigned " << BPs[j]->getName()
|
||||
<< " = 1 << " << j << ";\n";
|
||||
OS << " const unsigned " << BPs[j]->getName() << " = 1 << " << j
|
||||
<< ";\n";
|
||||
|
||||
OS << "} // end namespace " << Name << "Bypass\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Begin stages table
|
||||
std::string StageTable = "\nextern const llvm::InstrStage " + Target +
|
||||
"Stages[] = {\n";
|
||||
std::string StageTable =
|
||||
"\nextern const llvm::InstrStage " + Target + "Stages[] = {\n";
|
||||
StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n";
|
||||
|
||||
// Begin operand cycle table
|
||||
std::string OperandCycleTable = "extern const unsigned " + Target +
|
||||
"OperandCycles[] = {\n";
|
||||
std::string OperandCycleTable =
|
||||
"extern const unsigned " + Target + "OperandCycles[] = {\n";
|
||||
OperandCycleTable += " 0, // No itinerary\n";
|
||||
|
||||
// Begin pipeline bypass table
|
||||
std::string BypassTable = "extern const unsigned " + Target +
|
||||
"ForwardingPaths[] = {\n";
|
||||
std::string BypassTable =
|
||||
"extern const unsigned " + Target + "ForwardingPaths[] = {\n";
|
||||
BypassTable += " 0, // No itinerary\n";
|
||||
|
||||
// For each Itinerary across all processors, add a unique entry to the stages,
|
||||
@@ -485,7 +486,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS,
|
||||
std::map<std::string, unsigned> ItinStageMap, ItinOperandMap;
|
||||
for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
|
||||
// Add process itinerary to the list.
|
||||
ProcItinLists.resize(ProcItinLists.size()+1);
|
||||
ProcItinLists.resize(ProcItinLists.size() + 1);
|
||||
|
||||
// If this processor defines no itineraries, then leave the itinerary list
|
||||
// empty.
|
||||
@@ -542,19 +543,20 @@ EmitStageAndOperandCycleData(raw_ostream &OS,
|
||||
// Check to see if operand cycle already exists and create if it doesn't
|
||||
uint16_t FindOperandCycle = 0;
|
||||
if (NOperandCycles > 0) {
|
||||
std::string ItinOperandString = ItinOperandCycleString+ItinBypassString;
|
||||
std::string ItinOperandString =
|
||||
ItinOperandCycleString + ItinBypassString;
|
||||
FindOperandCycle = ItinOperandMap[ItinOperandString];
|
||||
if (FindOperandCycle == 0) {
|
||||
// Emit as cycle, // index
|
||||
OperandCycleTable += ItinOperandCycleString + ", // ";
|
||||
std::string OperandIdxComment = itostr(OperandCycleCount);
|
||||
if (NOperandCycles > 1)
|
||||
OperandIdxComment += "-"
|
||||
+ itostr(OperandCycleCount + NOperandCycles - 1);
|
||||
OperandIdxComment +=
|
||||
"-" + itostr(OperandCycleCount + NOperandCycles - 1);
|
||||
OperandCycleTable += OperandIdxComment + "\n";
|
||||
// Record Itin class number.
|
||||
ItinOperandMap[ItinOperandCycleString] =
|
||||
FindOperandCycle = OperandCycleCount;
|
||||
ItinOperandMap[ItinOperandCycleString] = FindOperandCycle =
|
||||
OperandCycleCount;
|
||||
// Emit as bypass, // index
|
||||
BypassTable += ItinBypassString + ", // " + OperandIdxComment + "\n";
|
||||
OperandCycleCount += NOperandCycles;
|
||||
@@ -599,17 +601,17 @@ EmitStageAndOperandCycleData(raw_ostream &OS,
|
||||
// Itineraries for each processor. The Itinerary lists are indexed on
|
||||
// CodeGenSchedClass::Index.
|
||||
//
|
||||
void SubtargetEmitter::
|
||||
EmitItineraries(raw_ostream &OS,
|
||||
std::vector<std::vector<InstrItinerary>> &ProcItinLists) {
|
||||
void SubtargetEmitter::EmitItineraries(
|
||||
raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists) {
|
||||
// Multiple processor models may share an itinerary record. Emit it once.
|
||||
SmallPtrSet<Record*, 8> ItinsDefSet;
|
||||
SmallPtrSet<Record *, 8> ItinsDefSet;
|
||||
|
||||
// For each processor's machine model
|
||||
std::vector<std::vector<InstrItinerary>>::iterator
|
||||
ProcItinListsIter = ProcItinLists.begin();
|
||||
std::vector<std::vector<InstrItinerary>>::iterator ProcItinListsIter =
|
||||
ProcItinLists.begin();
|
||||
for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
|
||||
PE = SchedModels.procModelEnd(); PI != PE; ++PI, ++ProcItinListsIter) {
|
||||
PE = SchedModels.procModelEnd();
|
||||
PI != PE; ++PI, ++ProcItinListsIter) {
|
||||
|
||||
Record *ItinsDef = PI->ItinsDef;
|
||||
if (!ItinsDefSet.insert(ItinsDef).second)
|
||||
@@ -636,13 +638,10 @@ EmitItineraries(raw_ostream &OS,
|
||||
|
||||
// Emit Itinerary in the form of
|
||||
// { firstStage, lastStage, firstCycle, lastCycle } // index
|
||||
OS << " { " <<
|
||||
Intinerary.NumMicroOps << ", " <<
|
||||
Intinerary.FirstStage << ", " <<
|
||||
Intinerary.LastStage << ", " <<
|
||||
Intinerary.FirstOperandCycle << ", " <<
|
||||
Intinerary.LastOperandCycle << " }" <<
|
||||
", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n";
|
||||
OS << " { " << Intinerary.NumMicroOps << ", " << Intinerary.FirstStage
|
||||
<< ", " << Intinerary.LastStage << ", " << Intinerary.FirstOperandCycle
|
||||
<< ", " << Intinerary.LastOperandCycle << " }"
|
||||
<< ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n";
|
||||
}
|
||||
// End processor itinerary table
|
||||
OS << " { 0, uint16_t(~0U), uint16_t(~0U), uint16_t(~0U), uint16_t(~0U) }"
|
||||
@@ -840,13 +839,11 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
|
||||
NumUnits += RU->getValueAsInt("NumUnits");
|
||||
SubUnitsOffset += RU->getValueAsInt("NumUnits");
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Find the SuperIdx
|
||||
if (PRDef->getValueInit("Super")->isComplete()) {
|
||||
SuperDef =
|
||||
SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"),
|
||||
ProcModel, PRDef->getLoc());
|
||||
SuperDef = SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"),
|
||||
ProcModel, PRDef->getLoc());
|
||||
SuperIdx = ProcModel.getProcResourceIdx(SuperDef);
|
||||
}
|
||||
NumUnits = PRDef->getValueAsInt("NumUnits");
|
||||
@@ -862,7 +859,7 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
|
||||
} else {
|
||||
OS << "nullptr";
|
||||
}
|
||||
OS << "}, // #" << i+1;
|
||||
OS << "}, // #" << i + 1;
|
||||
if (SuperDef)
|
||||
OS << ", Super=" << SuperDef->getName();
|
||||
OS << "\n";
|
||||
@@ -872,8 +869,9 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
|
||||
|
||||
// Find the WriteRes Record that defines processor resources for this
|
||||
// SchedWrite.
|
||||
Record *SubtargetEmitter::FindWriteResources(
|
||||
const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) {
|
||||
Record *
|
||||
SubtargetEmitter::FindWriteResources(const CodeGenSchedRW &SchedWrite,
|
||||
const CodeGenProcModel &ProcModel) {
|
||||
|
||||
// Check if the SchedWrite is already subtarget-specific and directly
|
||||
// specifies a set of processor resources.
|
||||
@@ -883,16 +881,18 @@ Record *SubtargetEmitter::FindWriteResources(
|
||||
Record *AliasDef = nullptr;
|
||||
for (Record *A : SchedWrite.Aliases) {
|
||||
const CodeGenSchedRW &AliasRW =
|
||||
SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
|
||||
SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
|
||||
if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
|
||||
Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
|
||||
if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
|
||||
continue;
|
||||
}
|
||||
if (AliasDef)
|
||||
PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "
|
||||
"defined for processor " + ProcModel.ModelName +
|
||||
" Ensure only one SchedAlias exists per RW.");
|
||||
PrintFatalError(AliasRW.TheDef->getLoc(),
|
||||
"Multiple aliases "
|
||||
"defined for processor " +
|
||||
ProcModel.ModelName +
|
||||
" Ensure only one SchedAlias exists per RW.");
|
||||
AliasDef = AliasRW.TheDef;
|
||||
}
|
||||
if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes"))
|
||||
@@ -903,12 +903,12 @@ Record *SubtargetEmitter::FindWriteResources(
|
||||
for (Record *WR : ProcModel.WriteResDefs) {
|
||||
if (!WR->isSubClassOf("WriteRes"))
|
||||
continue;
|
||||
if (AliasDef == WR->getValueAsDef("WriteType")
|
||||
|| SchedWrite.TheDef == WR->getValueAsDef("WriteType")) {
|
||||
if (AliasDef == WR->getValueAsDef("WriteType") ||
|
||||
SchedWrite.TheDef == WR->getValueAsDef("WriteType")) {
|
||||
if (ResDef) {
|
||||
PrintFatalError(WR->getLoc(), "Resources are defined for both "
|
||||
"SchedWrite and its alias on processor " +
|
||||
ProcModel.ModelName);
|
||||
"SchedWrite and its alias on processor " +
|
||||
ProcModel.ModelName);
|
||||
}
|
||||
ResDef = WR;
|
||||
}
|
||||
@@ -918,7 +918,7 @@ Record *SubtargetEmitter::FindWriteResources(
|
||||
if (!ResDef) {
|
||||
PrintFatalError(ProcModel.ModelDef->getLoc(),
|
||||
Twine("Processor does not define resources for ") +
|
||||
SchedWrite.TheDef->getName());
|
||||
SchedWrite.TheDef->getName());
|
||||
}
|
||||
return ResDef;
|
||||
}
|
||||
@@ -935,16 +935,18 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
|
||||
Record *AliasDef = nullptr;
|
||||
for (Record *A : SchedRead.Aliases) {
|
||||
const CodeGenSchedRW &AliasRW =
|
||||
SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
|
||||
SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
|
||||
if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
|
||||
Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
|
||||
if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
|
||||
continue;
|
||||
}
|
||||
if (AliasDef)
|
||||
PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases "
|
||||
"defined for processor " + ProcModel.ModelName +
|
||||
" Ensure only one SchedAlias exists per RW.");
|
||||
PrintFatalError(AliasRW.TheDef->getLoc(),
|
||||
"Multiple aliases "
|
||||
"defined for processor " +
|
||||
ProcModel.ModelName +
|
||||
" Ensure only one SchedAlias exists per RW.");
|
||||
AliasDef = AliasRW.TheDef;
|
||||
}
|
||||
if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance"))
|
||||
@@ -955,12 +957,12 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
|
||||
for (Record *RA : ProcModel.ReadAdvanceDefs) {
|
||||
if (!RA->isSubClassOf("ReadAdvance"))
|
||||
continue;
|
||||
if (AliasDef == RA->getValueAsDef("ReadType")
|
||||
|| SchedRead.TheDef == RA->getValueAsDef("ReadType")) {
|
||||
if (AliasDef == RA->getValueAsDef("ReadType") ||
|
||||
SchedRead.TheDef == RA->getValueAsDef("ReadType")) {
|
||||
if (ResDef) {
|
||||
PrintFatalError(RA->getLoc(), "Resources are defined for both "
|
||||
"SchedRead and its alias on processor " +
|
||||
ProcModel.ModelName);
|
||||
"SchedRead and its alias on processor " +
|
||||
ProcModel.ModelName);
|
||||
}
|
||||
ResDef = RA;
|
||||
}
|
||||
@@ -970,7 +972,7 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
|
||||
if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") {
|
||||
PrintFatalError(ProcModel.ModelDef->getLoc(),
|
||||
Twine("Processor does not define resources for ") +
|
||||
SchedRead.TheDef->getName());
|
||||
SchedRead.TheDef->getName());
|
||||
}
|
||||
return ResDef;
|
||||
}
|
||||
@@ -994,11 +996,10 @@ void SubtargetEmitter::ExpandProcResources(
|
||||
if (SubDef->isSubClassOf("ProcResGroup")) {
|
||||
// Disallow this for simplicitly.
|
||||
PrintFatalError(SubDef->getLoc(), "Processor resource group "
|
||||
" cannot be a super resources.");
|
||||
" cannot be a super resources.");
|
||||
}
|
||||
Record *SuperDef =
|
||||
SchedModels.findProcResUnits(SubDef->getValueAsDef("Super"), PM,
|
||||
SubDef->getLoc());
|
||||
Record *SuperDef = SchedModels.findProcResUnits(
|
||||
SubDef->getValueAsDef("Super"), PM, SubDef->getLoc());
|
||||
PRVec.push_back(SuperDef);
|
||||
ReleaseAtCycles.push_back(ReleaseAtCycles[i]);
|
||||
AcquireAtCycles.push_back(AcquireAtCycles[i]);
|
||||
@@ -1010,7 +1011,7 @@ void SubtargetEmitter::ExpandProcResources(
|
||||
continue;
|
||||
RecVec SuperResources = PR->getValueAsListOfDefs("Resources");
|
||||
RecIter SubI = SubResources.begin(), SubE = SubResources.end();
|
||||
for( ; SubI != SubE; ++SubI) {
|
||||
for (; SubI != SubE; ++SubI) {
|
||||
if (!is_contained(SuperResources, *SubI)) {
|
||||
break;
|
||||
}
|
||||
@@ -1051,7 +1052,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
// A Variant SchedClass has no resources of its own.
|
||||
bool HasVariants = false;
|
||||
for (const CodeGenSchedTransition &CGT :
|
||||
make_range(SC.Transitions.begin(), SC.Transitions.end())) {
|
||||
make_range(SC.Transitions.begin(), SC.Transitions.end())) {
|
||||
if (CGT.ProcIndex == ProcModel.Index) {
|
||||
HasVariants = true;
|
||||
break;
|
||||
@@ -1114,8 +1115,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
|
||||
for (unsigned W : Writes) {
|
||||
IdxVec WriteSeq;
|
||||
SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false,
|
||||
ProcModel);
|
||||
SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false, ProcModel);
|
||||
|
||||
// For each operand, create a latency entry.
|
||||
MCWriteLatencyEntry WLEntry;
|
||||
@@ -1125,7 +1125,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
// If this Write is not referenced by a ReadAdvance, don't distinguish it
|
||||
// from other WriteLatency entries.
|
||||
if (!SchedModels.hasReadOfWrite(
|
||||
SchedModels.getSchedWrite(WriteID).TheDef)) {
|
||||
SchedModels.getSchedWrite(WriteID).TheDef)) {
|
||||
WriteID = 0;
|
||||
}
|
||||
WLEntry.WriteResourceID = WriteID;
|
||||
@@ -1133,7 +1133,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
for (unsigned WS : WriteSeq) {
|
||||
|
||||
Record *WriteRes =
|
||||
FindWriteResources(SchedModels.getSchedWrite(WS), ProcModel);
|
||||
FindWriteResources(SchedModels.getSchedWrite(WS), ProcModel);
|
||||
|
||||
// Mark the parent class as invalid for unsupported write types.
|
||||
if (WriteRes->getValueAsBit("Unsupported")) {
|
||||
@@ -1170,7 +1170,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
.concat(Twine(ReleaseAtCycles.size())));
|
||||
}
|
||||
|
||||
if (!AcquireAtCycles.empty() && AcquireAtCycles.size() != PRVec.size()) {
|
||||
if (!AcquireAtCycles.empty() &&
|
||||
AcquireAtCycles.size() != PRVec.size()) {
|
||||
PrintFatalError(
|
||||
WriteRes->getLoc(),
|
||||
Twine("Inconsistent resource cycles: size(AcquireAtCycles) != "
|
||||
@@ -1197,8 +1198,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
ExpandProcResources(PRVec, ReleaseAtCycles, AcquireAtCycles, ProcModel);
|
||||
assert(AcquireAtCycles.size() == ReleaseAtCycles.size());
|
||||
|
||||
for (unsigned PRIdx = 0, PREnd = PRVec.size();
|
||||
PRIdx != PREnd; ++PRIdx) {
|
||||
for (unsigned PRIdx = 0, PREnd = PRVec.size(); PRIdx != PREnd;
|
||||
++PRIdx) {
|
||||
MCWriteProcResEntry WPREntry;
|
||||
WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);
|
||||
assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");
|
||||
@@ -1220,9 +1221,9 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
// serially, rather than multiple parallel uses. This is important for
|
||||
// in-order machine where the resource consumption is a hazard.
|
||||
unsigned WPRIdx = 0, WPREnd = WriteProcResources.size();
|
||||
for( ; WPRIdx != WPREnd; ++WPRIdx) {
|
||||
if (WriteProcResources[WPRIdx].ProcResourceIdx
|
||||
== WPREntry.ProcResourceIdx) {
|
||||
for (; WPRIdx != WPREnd; ++WPRIdx) {
|
||||
if (WriteProcResources[WPRIdx].ProcResourceIdx ==
|
||||
WPREntry.ProcResourceIdx) {
|
||||
// TODO: multiple use of the same resources would
|
||||
// require either 1. thinking of how to handle multiple
|
||||
// intervals for the same resource in
|
||||
@@ -1245,10 +1246,10 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
}
|
||||
// Create an entry for each operand Read in this SchedClass.
|
||||
// Entries must be sorted first by UseIdx then by WriteResourceID.
|
||||
for (unsigned UseIdx = 0, EndIdx = Reads.size();
|
||||
UseIdx != EndIdx; ++UseIdx) {
|
||||
for (unsigned UseIdx = 0, EndIdx = Reads.size(); UseIdx != EndIdx;
|
||||
++UseIdx) {
|
||||
Record *ReadAdvance =
|
||||
FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel);
|
||||
FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel);
|
||||
if (!ReadAdvance)
|
||||
continue;
|
||||
|
||||
@@ -1267,7 +1268,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
}
|
||||
}
|
||||
llvm::sort(WriteIDs);
|
||||
for(unsigned W : WriteIDs) {
|
||||
for (unsigned W : WriteIDs) {
|
||||
MCReadAdvanceEntry RAEntry;
|
||||
RAEntry.UseIdx = UseIdx;
|
||||
RAEntry.WriteResourceID = W;
|
||||
@@ -1288,9 +1289,9 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
|
||||
SCDesc.NumWriteProcResEntries = WriteProcResources.size();
|
||||
std::vector<MCWriteProcResEntry>::iterator WPRPos =
|
||||
std::search(SchedTables.WriteProcResources.begin(),
|
||||
SchedTables.WriteProcResources.end(),
|
||||
WriteProcResources.begin(), WriteProcResources.end());
|
||||
std::search(SchedTables.WriteProcResources.begin(),
|
||||
SchedTables.WriteProcResources.end(),
|
||||
WriteProcResources.begin(), WriteProcResources.end());
|
||||
if (WPRPos != SchedTables.WriteProcResources.end())
|
||||
SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin();
|
||||
else {
|
||||
@@ -1300,10 +1301,9 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
}
|
||||
// Latency entries must remain in operand order.
|
||||
SCDesc.NumWriteLatencyEntries = WriteLatencies.size();
|
||||
std::vector<MCWriteLatencyEntry>::iterator WLPos =
|
||||
std::search(SchedTables.WriteLatencies.begin(),
|
||||
SchedTables.WriteLatencies.end(),
|
||||
WriteLatencies.begin(), WriteLatencies.end());
|
||||
std::vector<MCWriteLatencyEntry>::iterator WLPos = std::search(
|
||||
SchedTables.WriteLatencies.begin(), SchedTables.WriteLatencies.end(),
|
||||
WriteLatencies.begin(), WriteLatencies.end());
|
||||
if (WLPos != SchedTables.WriteLatencies.end()) {
|
||||
unsigned idx = WLPos - SchedTables.WriteLatencies.begin();
|
||||
SCDesc.WriteLatencyIdx = idx;
|
||||
@@ -1312,8 +1312,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
std::string::npos) {
|
||||
SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size();
|
||||
llvm::append_range(SchedTables.WriteLatencies, WriteLatencies);
|
||||
llvm::append_range(SchedTables.WriterNames, WriterNames);
|
||||
@@ -1321,9 +1320,9 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
// ReadAdvanceEntries must remain in operand order.
|
||||
SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size();
|
||||
std::vector<MCReadAdvanceEntry>::iterator RAPos =
|
||||
std::search(SchedTables.ReadAdvanceEntries.begin(),
|
||||
SchedTables.ReadAdvanceEntries.end(),
|
||||
ReadAdvanceEntries.begin(), ReadAdvanceEntries.end());
|
||||
std::search(SchedTables.ReadAdvanceEntries.begin(),
|
||||
SchedTables.ReadAdvanceEntries.end(),
|
||||
ReadAdvanceEntries.begin(), ReadAdvanceEntries.end());
|
||||
if (RAPos != SchedTables.ReadAdvanceEntries.end())
|
||||
SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin();
|
||||
else {
|
||||
@@ -1355,8 +1354,8 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
|
||||
|
||||
// Emit global WriteLatencyTable.
|
||||
OS << "\n// {Cycles, WriteResourceID}\n"
|
||||
<< "extern const llvm::MCWriteLatencyEntry "
|
||||
<< Target << "WriteLatencyTable[] = {\n"
|
||||
<< "extern const llvm::MCWriteLatencyEntry " << Target
|
||||
<< "WriteLatencyTable[] = {\n"
|
||||
<< " { 0, 0}, // Invalid\n";
|
||||
for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size();
|
||||
WLIdx != WLEnd; ++WLIdx) {
|
||||
@@ -1371,8 +1370,8 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
|
||||
|
||||
// Emit global ReadAdvanceTable.
|
||||
OS << "\n// {UseIdx, WriteResourceID, Cycles}\n"
|
||||
<< "extern const llvm::MCReadAdvanceEntry "
|
||||
<< Target << "ReadAdvanceTable[] = {\n"
|
||||
<< "extern const llvm::MCReadAdvanceEntry " << Target
|
||||
<< "ReadAdvanceTable[] = {\n"
|
||||
<< " {0, 0, 0}, // Invalid\n";
|
||||
for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size();
|
||||
RAIdx != RAEnd; ++RAIdx) {
|
||||
@@ -1388,22 +1387,23 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
|
||||
|
||||
// Emit a SchedClass table for each processor.
|
||||
for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
|
||||
PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
|
||||
PE = SchedModels.procModelEnd();
|
||||
PI != PE; ++PI) {
|
||||
if (!PI->hasInstrSchedModel())
|
||||
continue;
|
||||
|
||||
std::vector<MCSchedClassDesc> &SCTab =
|
||||
SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())];
|
||||
SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())];
|
||||
|
||||
OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup, RetireOOO,"
|
||||
<< " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n";
|
||||
OS << "static const llvm::MCSchedClassDesc "
|
||||
<< PI->ModelName << "SchedClasses[] = {\n";
|
||||
OS << "static const llvm::MCSchedClassDesc " << PI->ModelName
|
||||
<< "SchedClasses[] = {\n";
|
||||
|
||||
// The first class is always invalid. We no way to distinguish it except by
|
||||
// name and position.
|
||||
assert(SchedModels.getSchedClass(0).Name == "NoInstrModel"
|
||||
&& "invalid class not first");
|
||||
assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" &&
|
||||
"invalid class not first");
|
||||
OS << " {DBGFIELD(\"InvalidSchedClass\") "
|
||||
<< MCSchedClassDesc::InvalidNumMicroOps
|
||||
<< ", false, false, false, 0, 0, 0, 0, 0, 0},\n";
|
||||
@@ -1414,17 +1414,15 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
|
||||
OS << " {DBGFIELD(\"" << SchedClass.Name << "\") ";
|
||||
if (SchedClass.Name.size() < 18)
|
||||
OS.indent(18 - SchedClass.Name.size());
|
||||
OS << MCDesc.NumMicroOps
|
||||
<< ", " << ( MCDesc.BeginGroup ? "true" : "false" )
|
||||
<< ", " << ( MCDesc.EndGroup ? "true" : "false" )
|
||||
<< ", " << ( MCDesc.RetireOOO ? "true" : "false" )
|
||||
<< ", " << format("%2d", MCDesc.WriteProcResIdx)
|
||||
<< ", " << MCDesc.NumWriteProcResEntries
|
||||
<< ", " << format("%2d", MCDesc.WriteLatencyIdx)
|
||||
<< ", " << MCDesc.NumWriteLatencyEntries
|
||||
<< ", " << format("%2d", MCDesc.ReadAdvanceIdx)
|
||||
<< ", " << MCDesc.NumReadAdvanceEntries
|
||||
<< "}, // #" << SCIdx << '\n';
|
||||
OS << MCDesc.NumMicroOps << ", " << (MCDesc.BeginGroup ? "true" : "false")
|
||||
<< ", " << (MCDesc.EndGroup ? "true" : "false") << ", "
|
||||
<< (MCDesc.RetireOOO ? "true" : "false") << ", "
|
||||
<< format("%2d", MCDesc.WriteProcResIdx) << ", "
|
||||
<< MCDesc.NumWriteProcResEntries << ", "
|
||||
<< format("%2d", MCDesc.WriteLatencyIdx) << ", "
|
||||
<< MCDesc.NumWriteLatencyEntries << ", "
|
||||
<< format("%2d", MCDesc.ReadAdvanceIdx) << ", "
|
||||
<< MCDesc.NumReadAdvanceEntries << "}, // #" << SCIdx << '\n';
|
||||
}
|
||||
OS << "}; // " << PI->ModelName << "SchedClasses\n";
|
||||
}
|
||||
@@ -1439,9 +1437,10 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
|
||||
// Emit processor resource table.
|
||||
if (PM.hasInstrSchedModel())
|
||||
EmitProcessorResources(PM, OS);
|
||||
else if(!PM.ProcResourceDefs.empty())
|
||||
PrintFatalError(PM.ModelDef->getLoc(), "SchedMachineModel defines "
|
||||
"ProcResources without defining WriteRes SchedWriteRes");
|
||||
else if (!PM.ProcResourceDefs.empty())
|
||||
PrintFatalError(PM.ModelDef->getLoc(),
|
||||
"SchedMachineModel defines "
|
||||
"ProcResources without defining WriteRes SchedWriteRes");
|
||||
|
||||
// Begin processor itinerary properties
|
||||
OS << "\n";
|
||||
@@ -1454,13 +1453,13 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
|
||||
EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ',');
|
||||
|
||||
bool PostRAScheduler =
|
||||
(PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false);
|
||||
(PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false);
|
||||
|
||||
OS << " " << (PostRAScheduler ? "true" : "false") << ", // "
|
||||
OS << " " << (PostRAScheduler ? "true" : "false") << ", // "
|
||||
<< "PostRAScheduler\n";
|
||||
|
||||
bool CompleteModel =
|
||||
(PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false);
|
||||
(PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false);
|
||||
|
||||
OS << " " << (CompleteModel ? "true" : "false") << ", // "
|
||||
<< "CompleteModel\n";
|
||||
@@ -1473,11 +1472,14 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
|
||||
|
||||
OS << " " << PM.Index << ", // Processor ID\n";
|
||||
if (PM.hasInstrSchedModel())
|
||||
OS << " " << PM.ModelName << "ProcResources" << ",\n"
|
||||
<< " " << PM.ModelName << "SchedClasses" << ",\n"
|
||||
<< " " << PM.ProcResourceDefs.size()+1 << ",\n"
|
||||
<< " " << (SchedModels.schedClassEnd()
|
||||
- SchedModels.schedClassBegin()) << ",\n";
|
||||
OS << " " << PM.ModelName << "ProcResources"
|
||||
<< ",\n"
|
||||
<< " " << PM.ModelName << "SchedClasses"
|
||||
<< ",\n"
|
||||
<< " " << PM.ProcResourceDefs.size() + 1 << ",\n"
|
||||
<< " "
|
||||
<< (SchedModels.schedClassEnd() - SchedModels.schedClassBegin())
|
||||
<< ",\n";
|
||||
else
|
||||
OS << " nullptr, nullptr, 0, 0,"
|
||||
<< " // No instruction-level machine model.\n";
|
||||
@@ -1669,8 +1671,8 @@ void SubtargetEmitter::emitSchedModelHelpersImpl(
|
||||
// Construct a switch statement where the condition is a check on the
|
||||
// scheduling class identifier. There is a `case` for every variant class
|
||||
// defined by the processor models of this target.
|
||||
// Each `case` implements a number of rules to resolve (i.e. to transition from)
|
||||
// a variant scheduling class to another scheduling class. Rules are
|
||||
// Each `case` implements a number of rules to resolve (i.e. to transition
|
||||
// from) a variant scheduling class to another scheduling class. Rules are
|
||||
// described by instances of CodeGenSchedTransition. Note that transitions may
|
||||
// not be valid for all processors.
|
||||
OS << " switch (SchedClass) {\n";
|
||||
@@ -1781,8 +1783,8 @@ void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName,
|
||||
OS << "unsigned " << ClassName << "::getHwMode() const {\n";
|
||||
for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) {
|
||||
const HwMode &HM = CGH.getMode(M);
|
||||
OS << " if (checkFeatures(\"" << HM.Features
|
||||
<< "\")) return " << M << ";\n";
|
||||
OS << " if (checkFeatures(\"" << HM.Features << "\")) return " << M
|
||||
<< ";\n";
|
||||
}
|
||||
OS << " return 0;\n}\n";
|
||||
}
|
||||
@@ -1808,8 +1810,8 @@ void SubtargetEmitter::emitGetMacroFusions(const std::string &ClassName,
|
||||
// Produces a subtarget specific function for parsing
|
||||
// the subtarget features string.
|
||||
void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) {
|
||||
std::vector<Record*> Features =
|
||||
Records.getAllDerivedDefinitions("SubtargetFeature");
|
||||
std::vector<Record *> Features =
|
||||
Records.getAllDerivedDefinitions("SubtargetFeature");
|
||||
llvm::sort(Features, LessRecord());
|
||||
|
||||
OS << "// ParseSubtargetFeatures - Parses features string setting specified\n"
|
||||
@@ -1836,15 +1838,12 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) {
|
||||
StringRef Value = R->getValueAsString("Value");
|
||||
StringRef FieldName = R->getValueAsString("FieldName");
|
||||
|
||||
if (Value=="true" || Value=="false")
|
||||
OS << " if (Bits[" << Target << "::"
|
||||
<< Instance << "]) "
|
||||
<< FieldName << " = " << Value << ";\n";
|
||||
if (Value == "true" || Value == "false")
|
||||
OS << " if (Bits[" << Target << "::" << Instance << "]) " << FieldName
|
||||
<< " = " << Value << ";\n";
|
||||
else
|
||||
OS << " if (Bits[" << Target << "::"
|
||||
<< Instance << "] && "
|
||||
<< FieldName << " < " << Value << ") "
|
||||
<< FieldName << " = " << Value << ";\n";
|
||||
OS << " if (Bits[" << Target << "::" << Instance << "] && " << FieldName
|
||||
<< " < " << Value << ") " << FieldName << " = " << Value << ";\n";
|
||||
}
|
||||
|
||||
OS << "}\n";
|
||||
@@ -1955,15 +1954,15 @@ void SubtargetEmitter::run(raw_ostream &OS) {
|
||||
OS << Target << "SubTypeKV, ";
|
||||
else
|
||||
OS << "std::nullopt, ";
|
||||
OS << '\n'; OS.indent(22);
|
||||
OS << Target << "WriteProcResTable, "
|
||||
<< Target << "WriteLatencyTable, "
|
||||
OS << '\n';
|
||||
OS.indent(22);
|
||||
OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, "
|
||||
<< Target << "ReadAdvanceTable, ";
|
||||
OS << '\n'; OS.indent(22);
|
||||
OS << '\n';
|
||||
OS.indent(22);
|
||||
if (SchedModels.hasItineraries()) {
|
||||
OS << Target << "Stages, "
|
||||
<< Target << "OperandCycles, "
|
||||
<< Target << "ForwardingPaths";
|
||||
OS << Target << "Stages, " << Target << "OperandCycles, " << Target
|
||||
<< "ForwardingPaths";
|
||||
} else
|
||||
OS << "nullptr, nullptr, nullptr";
|
||||
OS << ");\n}\n\n";
|
||||
@@ -2027,12 +2026,12 @@ void SubtargetEmitter::run(raw_ostream &OS) {
|
||||
OS << "namespace llvm {\n";
|
||||
OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
|
||||
OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n";
|
||||
OS << "extern const llvm::MCWriteProcResEntry "
|
||||
<< Target << "WriteProcResTable[];\n";
|
||||
OS << "extern const llvm::MCWriteLatencyEntry "
|
||||
<< Target << "WriteLatencyTable[];\n";
|
||||
OS << "extern const llvm::MCReadAdvanceEntry "
|
||||
<< Target << "ReadAdvanceTable[];\n";
|
||||
OS << "extern const llvm::MCWriteProcResEntry " << Target
|
||||
<< "WriteProcResTable[];\n";
|
||||
OS << "extern const llvm::MCWriteLatencyEntry " << Target
|
||||
<< "WriteLatencyTable[];\n";
|
||||
OS << "extern const llvm::MCReadAdvanceEntry " << Target
|
||||
<< "ReadAdvanceTable[];\n";
|
||||
|
||||
if (SchedModels.hasItineraries()) {
|
||||
OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";
|
||||
@@ -2051,15 +2050,15 @@ void SubtargetEmitter::run(raw_ostream &OS) {
|
||||
OS << "ArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), ";
|
||||
else
|
||||
OS << "std::nullopt, ";
|
||||
OS << '\n'; OS.indent(24);
|
||||
OS << Target << "WriteProcResTable, "
|
||||
<< Target << "WriteLatencyTable, "
|
||||
OS << '\n';
|
||||
OS.indent(24);
|
||||
OS << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, "
|
||||
<< Target << "ReadAdvanceTable, ";
|
||||
OS << '\n'; OS.indent(24);
|
||||
OS << '\n';
|
||||
OS.indent(24);
|
||||
if (SchedModels.hasItineraries()) {
|
||||
OS << Target << "Stages, "
|
||||
<< Target << "OperandCycles, "
|
||||
<< Target << "ForwardingPaths";
|
||||
OS << Target << "Stages, " << Target << "OperandCycles, " << Target
|
||||
<< "ForwardingPaths";
|
||||
} else
|
||||
OS << "nullptr, nullptr, nullptr";
|
||||
OS << ") {}\n\n";
|
||||
|
||||
@@ -81,7 +81,7 @@ void SubtargetFeatureInfo::emitNameTable(
|
||||
uint64_t IndexUB = 0;
|
||||
for (const auto &SF : SubtargetFeatures)
|
||||
if (IndexUB <= SF.second.Index)
|
||||
IndexUB = SF.second.Index+1;
|
||||
IndexUB = SF.second.Index + 1;
|
||||
|
||||
std::vector<std::string> Names;
|
||||
if (IndexUB > 0)
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
|
||||
namespace llvm {
|
||||
struct SubtargetFeatureInfo;
|
||||
using SubtargetFeatureInfoMap = std::map<Record *, SubtargetFeatureInfo, LessRecordByID>;
|
||||
using SubtargetFeatureInfoMap =
|
||||
std::map<Record *, SubtargetFeatureInfo, LessRecordByID>;
|
||||
|
||||
/// Helper class for storing information on a subtarget feature which
|
||||
/// participates in instruction matching.
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
// backends, this means that the EmitFoo function is the only thing not in
|
||||
// the anonymous namespace.
|
||||
|
||||
|
||||
// FIXME: Reorganize TableGen so that build dependencies can be more
|
||||
// accurately expressed. Currently, touching any of the emitters (or
|
||||
// anything that they transitively depend on) causes everything dependent
|
||||
@@ -57,7 +56,6 @@
|
||||
// TableGen binary with as few dependencies as possible on the rest of
|
||||
// LLVM.
|
||||
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class raw_ostream;
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
const char *llvm::getMinimalTypeForRange(uint64_t Range, unsigned MaxSize LLVM_ATTRIBUTE_UNUSED) {
|
||||
const char *
|
||||
llvm::getMinimalTypeForRange(uint64_t Range,
|
||||
unsigned MaxSize LLVM_ATTRIBUTE_UNUSED) {
|
||||
// TODO: The original callers only used 32 and 64 so these are the only
|
||||
// values permitted. Rather than widen the supported values we should
|
||||
// allow 64 for the callers that currently use 32 and remove the
|
||||
|
||||
@@ -16,6 +16,6 @@ namespace llvm {
|
||||
/// MaxSize indicates the largest size of integer to consider (in bits) and only
|
||||
/// supports values of at least 32.
|
||||
const char *getMinimalTypeForRange(uint64_t Range, unsigned MaxSize = 64);
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
||||
@@ -63,7 +63,8 @@ void emitWebAssemblyDisassemblerTables(
|
||||
// should be the canonical one. This determines which variant gets
|
||||
// printed in a disassembly. We want e.g. "call" not "i32.call", and
|
||||
// "end" when we don't know if its "end_loop" or "end_block" etc.
|
||||
bool IsCanonicalExisting = CGIP.second->TheDef->getValueAsBit("IsCanonical");
|
||||
bool IsCanonicalExisting =
|
||||
CGIP.second->TheDef->getValueAsBit("IsCanonical");
|
||||
// We already have one marked explicitly as canonical, so keep it.
|
||||
if (IsCanonicalExisting)
|
||||
continue;
|
||||
@@ -126,7 +127,8 @@ void emitWebAssemblyDisassemblerTables(
|
||||
++J) {
|
||||
size_t K = 0;
|
||||
for (; K < CurOperandList.size(); ++K) {
|
||||
if (OperandTable[J + K] != CurOperandList[K]) break;
|
||||
if (OperandTable[J + K] != CurOperandList[K])
|
||||
break;
|
||||
}
|
||||
if (K == CurOperandList.size()) {
|
||||
OperandStart = J;
|
||||
|
||||
@@ -83,7 +83,8 @@ void X86CompressEVEXTablesEmitter::printTable(const std::vector<Entry> &Table,
|
||||
void X86CompressEVEXTablesEmitter::printCheckPredicate(
|
||||
const PredicateInstMap &PredicateInsts, raw_ostream &OS) {
|
||||
|
||||
OS << "static bool checkPredicate(unsigned Opc, const X86Subtarget *Subtarget) {\n"
|
||||
OS << "static bool checkPredicate(unsigned Opc, const X86Subtarget "
|
||||
"*Subtarget) {\n"
|
||||
<< " switch (Opc) {\n"
|
||||
<< " default: return true;\n";
|
||||
for (const auto &[Key, Val] : PredicateInsts) {
|
||||
@@ -207,9 +208,9 @@ void X86CompressEVEXTablesEmitter::run(raw_ostream &OS) {
|
||||
NewInst = &TempInst;
|
||||
}
|
||||
} else {
|
||||
// For each pre-compression instruction look for a match in the appropriate
|
||||
// vector (instructions with the same opcode) using function object
|
||||
// IsMatch.
|
||||
// For each pre-compression instruction look for a match in the
|
||||
// appropriate vector (instructions with the same opcode) using function
|
||||
// object IsMatch.
|
||||
auto Match = llvm::find_if(CompressedInsts[Opcode], IsMatch(Inst));
|
||||
if (Match != CompressedInsts[Opcode].end())
|
||||
NewInst = *Match;
|
||||
@@ -225,7 +226,7 @@ void X86CompressEVEXTablesEmitter::run(raw_ostream &OS) {
|
||||
return Name == "HasAVXNECONVERT" || Name == "HasAVXVNNI" ||
|
||||
Name == "HasAVXIFMA";
|
||||
});
|
||||
if(It!= Predicates.end())
|
||||
if (It != Predicates.end())
|
||||
PredicateInsts[*It].push_back(NewInst);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,9 +49,7 @@ struct OpcodeDecision {
|
||||
struct ContextDecision {
|
||||
OpcodeDecision opcodeDecisions[llvm::X86Disassembler::IC_max];
|
||||
|
||||
ContextDecision() {
|
||||
memset(opcodeDecisions, 0, sizeof(opcodeDecisions));
|
||||
}
|
||||
ContextDecision() { memset(opcodeDecisions, 0, sizeof(opcodeDecisions)); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,8 +41,9 @@ static inline const char *stringForContext(InstructionContext insnContext) {
|
||||
break;
|
||||
#define ENUM_ENTRY_K_B(n, r, d) \
|
||||
ENUM_ENTRY(n, r, d) \
|
||||
ENUM_ENTRY(n##_K_B, r, d) ENUM_ENTRY(n##_KZ, r, d) ENUM_ENTRY(n##_K, r, d) \
|
||||
ENUM_ENTRY(n##_B, r, d) ENUM_ENTRY(n##_KZ_B, r, d)
|
||||
ENUM_ENTRY(n##_K_B, r, d) \
|
||||
ENUM_ENTRY(n##_KZ, r, d) \
|
||||
ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d) ENUM_ENTRY(n##_KZ_B, r, d)
|
||||
INSTRUCTION_CONTEXTS
|
||||
#undef ENUM_ENTRY
|
||||
#undef ENUM_ENTRY_K_B
|
||||
@@ -595,8 +596,8 @@ static inline bool outranks(InstructionContext upper,
|
||||
#define ENUM_ENTRY_K_B(n, r, d) \
|
||||
ENUM_ENTRY(n, r, d) \
|
||||
ENUM_ENTRY(n##_K_B, r, d) \
|
||||
ENUM_ENTRY(n##_KZ_B, r, d) ENUM_ENTRY(n##_KZ, r, d) ENUM_ENTRY(n##_K, r, d) \
|
||||
ENUM_ENTRY(n##_B, r, d)
|
||||
ENUM_ENTRY(n##_KZ_B, r, d) \
|
||||
ENUM_ENTRY(n##_KZ, r, d) ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d)
|
||||
static int ranks[IC_max] = {INSTRUCTION_CONTEXTS};
|
||||
#undef ENUM_ENTRY
|
||||
#undef ENUM_ENTRY_K_B
|
||||
@@ -822,7 +823,8 @@ void DisassemblerTables::emitContextDecision(raw_ostream &o1, raw_ostream &o2,
|
||||
}
|
||||
|
||||
i2--;
|
||||
o2.indent(i2) << "}};" << "\n";
|
||||
o2.indent(i2) << "}};"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void DisassemblerTables::emitInstructionInfo(raw_ostream &o,
|
||||
@@ -859,7 +861,8 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o,
|
||||
}
|
||||
o << " },\n";
|
||||
}
|
||||
o << "};" << "\n\n";
|
||||
o << "};"
|
||||
<< "\n\n";
|
||||
|
||||
o.indent(i * 2) << "static const struct InstructionSpecifier ";
|
||||
o << INSTRUCTIONS_STR "[" << InstructionSpecifiers.size() << "] = {\n";
|
||||
@@ -885,7 +888,8 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o,
|
||||
}
|
||||
|
||||
i--;
|
||||
o.indent(i * 2) << "};" << "\n";
|
||||
o.indent(i * 2) << "};"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
|
||||
@@ -1004,7 +1008,8 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
|
||||
}
|
||||
|
||||
i--;
|
||||
o.indent(i * 2) << "};" << "\n";
|
||||
o.indent(i * 2) << "};"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void DisassemblerTables::emitContextDecisions(raw_ostream &o1, raw_ostream &o2,
|
||||
|
||||
@@ -91,8 +91,8 @@ private:
|
||||
/// @param ModRMTableNum - next table number for adding to ModRMTable.
|
||||
/// @param decision - The ModR/M decision to emit. This decision has 256
|
||||
/// entries - emitModRMDecision decides how to compact it.
|
||||
void emitModRMDecision(raw_ostream &o1, raw_ostream &o2,
|
||||
unsigned &i1, unsigned &i2, unsigned &ModRMTableNum,
|
||||
void emitModRMDecision(raw_ostream &o1, raw_ostream &o2, unsigned &i1,
|
||||
unsigned &i2, unsigned &ModRMTableNum,
|
||||
ModRMDecision &decision) const;
|
||||
|
||||
/// emitOpcodeDecision - Emits an OpcodeDecision and all its subsidiary ModR/M
|
||||
@@ -119,8 +119,8 @@ private:
|
||||
/// @param ModRMTableNum - next table number for adding to ModRMTable.
|
||||
/// @param decision - The OpcodeDecision to emit along with its subsidiary
|
||||
/// structures.
|
||||
void emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2,
|
||||
unsigned &i1, unsigned &i2, unsigned &ModRMTableNum,
|
||||
void emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2, unsigned &i1,
|
||||
unsigned &i2, unsigned &ModRMTableNum,
|
||||
OpcodeDecision &decision) const;
|
||||
|
||||
/// emitContextDecision - Emits a ContextDecision and all its subsidiary
|
||||
@@ -153,9 +153,9 @@ private:
|
||||
/// @param decision - The ContextDecision to emit along with its subsidiary
|
||||
/// structures.
|
||||
/// @param name - The name for the ContextDecision.
|
||||
void emitContextDecision(raw_ostream &o1, raw_ostream &o2,
|
||||
unsigned &i1, unsigned &i2, unsigned &ModRMTableNum,
|
||||
ContextDecision &decision, const char* name) const;
|
||||
void emitContextDecision(raw_ostream &o1, raw_ostream &o2, unsigned &i1,
|
||||
unsigned &i2, unsigned &ModRMTableNum,
|
||||
ContextDecision &decision, const char *name) const;
|
||||
|
||||
/// emitInstructionInfo - Prints the instruction specifier table, which has
|
||||
/// one entry for each instruction, and contains name and operand
|
||||
@@ -200,7 +200,8 @@ private:
|
||||
/// IC is the context corresponding to the mask 0x00, and there are 256
|
||||
/// possible masks.
|
||||
///
|
||||
/// @param o - The output stream to which the context table should be written.
|
||||
/// @param o - The output stream to which the context table should be
|
||||
/// written.
|
||||
/// @param i - The indent level for use with the stream.
|
||||
void emitContextTable(raw_ostream &o, uint32_t &i) const;
|
||||
|
||||
@@ -213,9 +214,8 @@ private:
|
||||
/// @param i1 - The indent level to use with stream o1.
|
||||
/// @param i2 - The indent level to use with stream o2.
|
||||
/// @param ModRMTableNum - next table number for adding to ModRMTable.
|
||||
void emitContextDecisions(raw_ostream &o1, raw_ostream &o2,
|
||||
unsigned &i1, unsigned &i2,
|
||||
unsigned &ModRMTableNum) const;
|
||||
void emitContextDecisions(raw_ostream &o1, raw_ostream &o2, unsigned &i1,
|
||||
unsigned &i2, unsigned &ModRMTableNum) const;
|
||||
|
||||
/// setTableFields - Uses a ModRMFilter to set the appropriate entries in a
|
||||
/// ModRMDecision to refer to a particular instruction ID.
|
||||
@@ -224,10 +224,9 @@ private:
|
||||
/// @param filter - The filter to use in deciding which entries to populate.
|
||||
/// @param uid - The unique ID to set matching entries to.
|
||||
/// @param opcode - The opcode of the instruction, for error reporting.
|
||||
void setTableFields(ModRMDecision &decision,
|
||||
const ModRMFilter &filter,
|
||||
InstrUID uid,
|
||||
uint8_t opcode);
|
||||
void setTableFields(ModRMDecision &decision, const ModRMFilter &filter,
|
||||
InstrUID uid, uint8_t opcode);
|
||||
|
||||
public:
|
||||
/// Constructor - Allocates space for the class decisions and clears them.
|
||||
DisassemblerTables();
|
||||
@@ -247,7 +246,8 @@ public:
|
||||
/// @param insnContext - The context to use (IC, IC_64BIT, etc.)
|
||||
/// @param opcode - The last byte of the opcode (not counting any escape
|
||||
/// or extended opcodes).
|
||||
/// @param filter - The ModRMFilter that decides which ModR/M byte values
|
||||
/// @param filter - The ModRMFilter that decides which ModR/M byte
|
||||
/// values
|
||||
/// correspond to the desired instruction.
|
||||
/// @param uid - The unique ID of the instruction.
|
||||
/// @param is32bit - Instructon is only 32-bit
|
||||
@@ -255,23 +255,17 @@ public:
|
||||
/// @param ignoresVEX_L - Instruction ignores VEX.L
|
||||
/// @param ignoresVEX_W - Instruction ignores VEX.W
|
||||
/// @param AddrSize - Instructions address size 16/32/64. 0 is unspecified
|
||||
void setTableFields(OpcodeType type,
|
||||
InstructionContext insnContext,
|
||||
uint8_t opcode,
|
||||
const ModRMFilter &filter,
|
||||
InstrUID uid,
|
||||
bool is32bit,
|
||||
bool noPrefix,
|
||||
bool ignoresVEX_L,
|
||||
bool ignoresVEX_W,
|
||||
unsigned AddrSize);
|
||||
void setTableFields(OpcodeType type, InstructionContext insnContext,
|
||||
uint8_t opcode, const ModRMFilter &filter, InstrUID uid,
|
||||
bool is32bit, bool noPrefix, bool ignoresVEX_L,
|
||||
bool ignoresVEX_W, unsigned AddrSize);
|
||||
|
||||
/// specForUID - Returns the instruction specifier for a given unique
|
||||
/// instruction ID. Used when resolving collisions.
|
||||
///
|
||||
/// @param uid - The unique ID of the instruction.
|
||||
/// @return - A reference to the instruction specifier.
|
||||
InstructionSpecifier& specForUID(InstrUID uid) {
|
||||
InstructionSpecifier &specForUID(InstrUID uid) {
|
||||
if (uid >= InstructionSpecifiers.size())
|
||||
InstructionSpecifiers.resize(uid + 1);
|
||||
|
||||
@@ -282,9 +276,7 @@ public:
|
||||
// from any instructions added to the tables.
|
||||
// @return - true if there were; false otherwise.
|
||||
|
||||
bool hasConflicts() {
|
||||
return HasConflicts;
|
||||
}
|
||||
bool hasConflicts() { return HasConflicts; }
|
||||
};
|
||||
|
||||
} // namespace X86Disassembler
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
|
||||
using namespace llvm::X86Disassembler;
|
||||
|
||||
void ModRMFilter::anchor() { }
|
||||
void ModRMFilter::anchor() {}
|
||||
|
||||
void DumbFilter::anchor() { }
|
||||
void DumbFilter::anchor() {}
|
||||
|
||||
void ModFilter::anchor() { }
|
||||
void ModFilter::anchor() {}
|
||||
|
||||
void ExtendedFilter::anchor() { }
|
||||
void ExtendedFilter::anchor() {}
|
||||
|
||||
void ExtendedRMFilter::anchor() { }
|
||||
void ExtendedRMFilter::anchor() {}
|
||||
|
||||
void ExactFilter::anchor() { }
|
||||
void ExactFilter::anchor() {}
|
||||
|
||||
@@ -27,9 +27,10 @@ namespace X86Disassembler {
|
||||
/// ModR/M bytes.
|
||||
class ModRMFilter {
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
/// Destructor - Override as necessary.
|
||||
virtual ~ModRMFilter() { }
|
||||
virtual ~ModRMFilter() {}
|
||||
|
||||
/// isDumb - Indicates whether this filter returns the same value for
|
||||
/// any value of the ModR/M byte.
|
||||
@@ -50,14 +51,11 @@ public:
|
||||
/// for operands.
|
||||
class DumbFilter : public ModRMFilter {
|
||||
void anchor() override;
|
||||
public:
|
||||
bool isDumb() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool accepts(uint8_t modRM) const override {
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
bool isDumb() const override { return true; }
|
||||
|
||||
bool accepts(uint8_t modRM) const override { return true; }
|
||||
};
|
||||
|
||||
/// ModFilter - Filters based on the mod bits [bits 7-6] of the ModR/M byte.
|
||||
@@ -66,6 +64,7 @@ public:
|
||||
class ModFilter : public ModRMFilter {
|
||||
void anchor() override;
|
||||
bool R;
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
///
|
||||
@@ -86,6 +85,7 @@ class ExtendedFilter : public ModRMFilter {
|
||||
void anchor() override;
|
||||
bool R;
|
||||
uint8_t NNN;
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
///
|
||||
@@ -95,9 +95,9 @@ public:
|
||||
ExtendedFilter(bool r, uint8_t nnn) : R(r), NNN(nnn) {}
|
||||
|
||||
bool accepts(uint8_t modRM) const override {
|
||||
return (((R && ((modRM & 0xc0) == 0xc0)) ||
|
||||
(!R && ((modRM & 0xc0) != 0xc0))) &&
|
||||
(((modRM & 0x38) >> 3) == NNN));
|
||||
return (
|
||||
((R && ((modRM & 0xc0) == 0xc0)) || (!R && ((modRM & 0xc0) != 0xc0))) &&
|
||||
(((modRM & 0x38) >> 3) == NNN));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -107,6 +107,7 @@ class ExtendedRMFilter : public ModRMFilter {
|
||||
void anchor() override;
|
||||
bool R;
|
||||
uint8_t NNN;
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
///
|
||||
@@ -116,8 +117,7 @@ public:
|
||||
ExtendedRMFilter(bool r, uint8_t nnn) : R(r), NNN(nnn) {}
|
||||
|
||||
bool accepts(uint8_t modRM) const override {
|
||||
return ((R && ((modRM & 0xc0) == 0xc0)) &&
|
||||
((modRM & 0x7) == NNN));
|
||||
return ((R && ((modRM & 0xc0) == 0xc0)) && ((modRM & 0x7) == NNN));
|
||||
}
|
||||
};
|
||||
/// ExactFilter - The occasional extended opcode (such as VMCALL or MONITOR)
|
||||
@@ -125,15 +125,14 @@ public:
|
||||
class ExactFilter : public ModRMFilter {
|
||||
void anchor() override;
|
||||
uint8_t ModRM;
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
///
|
||||
/// \param modRM The required value of the full ModR/M byte.
|
||||
ExactFilter(uint8_t modRM) : ModRM(modRM) {}
|
||||
|
||||
bool accepts(uint8_t modRM) const override {
|
||||
return (ModRM == modRM);
|
||||
}
|
||||
bool accepts(uint8_t modRM) const override { return (ModRM == modRM); }
|
||||
};
|
||||
|
||||
} // namespace X86Disassembler
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===- X86RecognizableInstr.cpp - Disassembler instruction spec --*- C++ -*-===//
|
||||
//===- X86RecognizableInstr.cpp - Disassembler instruction spec -*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===- X86RecognizableInstr.h - Disassembler instruction spec ----*- C++ -*-===//
|
||||
//===- X86RecognizableInstr.h - Disassembler instruction spec ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
Reference in New Issue
Block a user