aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen/CodeEmitterGen.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-07-26 19:03:47 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-07-26 19:04:23 +0000
commit7fa27ce4a07f19b07799a767fc29416f3b625afb (patch)
tree27825c83636c4de341eb09a74f49f5d38a15d165 /llvm/utils/TableGen/CodeEmitterGen.cpp
parente3b557809604d036af6e00c60f012c2025b59a5e (diff)
downloadsrc-7fa27ce4a07f19b07799a767fc29416f3b625afb.tar.gz
src-7fa27ce4a07f19b07799a767fc29416f3b625afb.zip
Vendor import of llvm-project main llvmorg-17-init-19304-gd0b54bb50e51,vendor/llvm-project/llvmorg-17-init-19304-gd0b54bb50e51
the last commit before the upstream release/17.x branch was created.
Diffstat (limited to 'llvm/utils/TableGen/CodeEmitterGen.cpp')
-rw-r--r--llvm/utils/TableGen/CodeEmitterGen.cpp242
1 files changed, 120 insertions, 122 deletions
diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp
index dc4fd589eaa8..48ed319bf06f 100644
--- a/llvm/utils/TableGen/CodeEmitterGen.cpp
+++ b/llvm/utils/TableGen/CodeEmitterGen.cpp
@@ -7,15 +7,25 @@
//===----------------------------------------------------------------------===//
//
// CodeEmitterGen uses the descriptions of instructions and their fields to
-// construct an automated code emitter: a function that, given a MachineInstr,
-// returns the (currently, 32-bit unsigned) value of the instruction.
+// construct an automated code emitter: a function called
+// getBinaryCodeForInstr() that, given a MCInst, returns the value of the
+// instruction - either as an uint64_t or as an APInt, depending on the
+// maximum bit width of all Inst definitions.
+//
+// In addition, it generates another function called getOperandBitOffset()
+// that, given a MCInst and an operand index, returns the minimum of indices of
+// all bits that carry some portion of the respective operand. When the target's
+// encodeInstruction() stores the instruction in a little-endian byte order, the
+// returned value is the offset of the start of the operand in the encoded
+// instruction. Other targets might need to adjust the returned value according
+// to their encodeInstruction() implementation.
//
//===----------------------------------------------------------------------===//
+#include "CodeGenHwModes.h"
#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
-#include "SubtargetFeatureInfo.h"
-#include "Types.h"
+#include "InfoByHwMode.h"
#include "VarLenCodeEmitterGen.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
@@ -46,19 +56,24 @@ public:
private:
int getVariableBit(const std::string &VarName, BitsInit *BI, int bit);
- std::string getInstructionCase(Record *R, CodeGenTarget &Target);
- std::string getInstructionCaseForEncoding(Record *R, Record *EncodingDef,
- CodeGenTarget &Target);
+ std::pair<std::string, std::string>
+ getInstructionCases(Record *R, CodeGenTarget &Target);
+ void addInstructionCasesForEncoding(Record *R, Record *EncodingDef,
+ CodeGenTarget &Target, std::string &Case,
+ std::string &BitOffsetCase);
bool addCodeToMergeInOperand(Record *R, BitsInit *BI,
- const std::string &VarName, unsigned &NumberedOp,
- std::set<unsigned> &NamedOpIndices,
- std::string &Case, CodeGenTarget &Target);
+ const std::string &VarName, std::string &Case,
+ std::string &BitOffsetCase,
+ CodeGenTarget &Target);
void emitInstructionBaseValues(
raw_ostream &o, ArrayRef<const CodeGenInstruction *> NumberedInstructions,
CodeGenTarget &Target, int HwMode = -1);
- unsigned BitWidth;
- bool UseAPInt;
+ void
+ emitCaseMap(raw_ostream &o,
+ const std::map<std::string, std::vector<std::string>> &CaseMap);
+ unsigned BitWidth = 0u;
+ bool UseAPInt = false;
};
// If the VarBitInit at position 'bit' matches the specified variable then
@@ -80,9 +95,8 @@ int CodeEmitterGen::getVariableBit(const std::string &VarName,
// Returns true if it succeeds, false if an error.
bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
const std::string &VarName,
- unsigned &NumberedOp,
- std::set<unsigned> &NamedOpIndices,
std::string &Case,
+ std::string &BitOffsetCase,
CodeGenTarget &Target) {
CodeGenInstruction &CGI = Target.getInstruction(R);
@@ -113,52 +127,8 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
// Get the machine operand number for the indicated operand.
OpIdx = CGI.Operands[OpIdx].MIOperandNo;
} else {
- // Fall back to positional lookup. By default, we now disable positional
- // lookup (and print an error, below), but even so, we'll do the lookup to
- // help print a helpful diagnostic message.
- //
- // TODO: When we remove useDeprecatedPositionallyEncodedOperands, delete all
- // this code, just leaving a "no operand named X in record Y" error.
-
- unsigned NumberOps = CGI.Operands.size();
- /// If this operand is not supposed to be emitted by the
- /// generated emitter, skip it.
- while (NumberedOp < NumberOps &&
- (CGI.Operands.isFlatOperandNotEmitted(NumberedOp) ||
- (!NamedOpIndices.empty() && NamedOpIndices.count(
- CGI.Operands.getSubOperandNumber(NumberedOp).first)))) {
- ++NumberedOp;
- }
-
- if (NumberedOp >=
- CGI.Operands.back().MIOperandNo + CGI.Operands.back().MINumOperands) {
- if (!Target.getInstructionSet()->getValueAsBit(
- "useDeprecatedPositionallyEncodedOperands")) {
- PrintError(R, Twine("No operand named ") + VarName + " in record " +
- R->getName() +
- " (would've given 'too few operands' error with "
- "useDeprecatedPositionallyEncodedOperands=true)");
- } else {
- PrintError(R, "Too few operands in record " + R->getName() +
- " (no match for variable " + VarName + ")");
- }
- return false;
- }
-
- OpIdx = NumberedOp++;
-
- if (!Target.getInstructionSet()->getValueAsBit(
- "useDeprecatedPositionallyEncodedOperands")) {
- std::pair<unsigned, unsigned> SO =
- CGI.Operands.getSubOperandNumber(OpIdx);
- std::string OpName = CGI.Operands[SO.first].Name;
- PrintError(R, Twine("No operand named ") + VarName + " in record " +
- R->getName() + " (would've used positional operand #" +
- Twine(SO.first) + " ('" + OpName + "') sub-op #" +
- Twine(SO.second) +
- " with useDeprecatedPositionallyEncodedOperands=true)");
- return false;
- }
+ PrintError(R, Twine("No operand named ") + VarName + " in record " + R->getName());
+ return false;
}
if (CGI.Operands.isFlatOperandNotEmitted(OpIdx)) {
@@ -222,6 +192,7 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
++numOperandLits;
}
+ unsigned BitOffset = -1;
for (; bit >= 0; ) {
int varBit = getVariableBit(VarName, BI, bit);
@@ -230,7 +201,7 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
--bit;
continue;
}
-
+
// Figure out the consecutive range of bits covered by this operand, in
// order to generate better encoding code.
int beginInstBit = bit;
@@ -249,6 +220,7 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
unsigned loBit = beginVarBit - N + 1;
unsigned hiBit = loBit + N;
unsigned loInstBit = beginInstBit - N + 1;
+ BitOffset = loInstBit;
if (UseAPInt) {
std::string extractStr;
if (N >= 64) {
@@ -290,65 +262,71 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
}
}
}
+
+ if (BitOffset != (unsigned)-1) {
+ BitOffsetCase += " case " + utostr(OpIdx) + ":\n";
+ BitOffsetCase += " // op: " + VarName + "\n";
+ BitOffsetCase += " return " + utostr(BitOffset) + ";\n";
+ }
+
return true;
}
-std::string CodeEmitterGen::getInstructionCase(Record *R,
- CodeGenTarget &Target) {
- std::string Case;
+std::pair<std::string, std::string>
+CodeEmitterGen::getInstructionCases(Record *R, CodeGenTarget &Target) {
+ std::string Case, BitOffsetCase;
+
+ auto append = [&](const char *S) {
+ Case += S;
+ BitOffsetCase += S;
+ };
+
if (const RecordVal *RV = R->getValue("EncodingInfos")) {
if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
const CodeGenHwModes &HWM = Target.getHwModes();
EncodingInfoByHwMode EBM(DI->getDef(), HWM);
- Case += " switch (HwMode) {\n";
- Case += " default: llvm_unreachable(\"Unhandled HwMode\");\n";
+ append(" switch (HwMode) {\n");
+ append(" default: llvm_unreachable(\"Unhandled HwMode\");\n");
for (auto &KV : EBM) {
- Case += " case " + itostr(KV.first) + ": {\n";
- Case += getInstructionCaseForEncoding(R, KV.second, Target);
- Case += " break;\n";
- Case += " }\n";
+ append((" case " + itostr(KV.first) + ": {\n").c_str());
+ addInstructionCasesForEncoding(R, KV.second, Target, Case,
+ BitOffsetCase);
+ append(" break;\n");
+ append(" }\n");
}
- Case += " }\n";
- return Case;
+ append(" }\n");
+ return std::make_pair(std::move(Case), std::move(BitOffsetCase));
}
}
- return getInstructionCaseForEncoding(R, R, Target);
+ addInstructionCasesForEncoding(R, R, Target, Case, BitOffsetCase);
+ return std::make_pair(std::move(Case), std::move(BitOffsetCase));
}
-std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *EncodingDef,
- CodeGenTarget &Target) {
- std::string Case;
+void CodeEmitterGen::addInstructionCasesForEncoding(
+ Record *R, Record *EncodingDef, CodeGenTarget &Target, std::string &Case,
+ std::string &BitOffsetCase) {
BitsInit *BI = EncodingDef->getValueAsBitsInit("Inst");
- unsigned NumberedOp = 0;
- std::set<unsigned> NamedOpIndices;
-
- // Collect the set of operand indices that might correspond to named
- // operand, and skip these when assigning operands based on position.
- if (Target.getInstructionSet()->
- getValueAsBit("noNamedPositionallyEncodedOperands")) {
- CodeGenInstruction &CGI = Target.getInstruction(R);
- for (const RecordVal &RV : R->getValues()) {
- unsigned OpIdx;
- if (!CGI.Operands.hasOperandNamed(RV.getName(), OpIdx))
- continue;
-
- NamedOpIndices.insert(OpIdx);
- }
- }
// Loop over all of the fields in the instruction, determining which are the
// operands to the instruction.
bool Success = true;
+ size_t OrigBitOffsetCaseSize = BitOffsetCase.size();
+ BitOffsetCase += " switch (OpNum) {\n";
+ size_t BitOffsetCaseSizeBeforeLoop = BitOffsetCase.size();
for (const RecordVal &RV : EncodingDef->getValues()) {
// Ignore fixed fields in the record, we're looking for values like:
// bits<5> RST = { ?, ?, ?, ?, ? };
if (RV.isNonconcreteOK() || RV.getValue()->isComplete())
continue;
- Success &=
- addCodeToMergeInOperand(R, BI, std::string(RV.getName()), NumberedOp,
- NamedOpIndices, Case, Target);
+ Success &= addCodeToMergeInOperand(R, BI, std::string(RV.getName()), Case,
+ BitOffsetCase, Target);
}
+ // Avoid empty switches.
+ if (BitOffsetCase.size() == BitOffsetCaseSizeBeforeLoop)
+ BitOffsetCase.resize(OrigBitOffsetCaseSize);
+ else
+ BitOffsetCase += " }\n";
if (!Success) {
// Dump the record, so we can see what's going on...
@@ -367,8 +345,6 @@ std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *Enc
Case += ", STI";
Case += ");\n";
}
-
- return Case;
}
static void emitInstBits(raw_ostream &OS, const APInt &Bits) {
@@ -419,7 +395,29 @@ void CodeEmitterGen::emitInstructionBaseValues(
o << " UINT64_C(0)\n };\n";
}
+void CodeEmitterGen::emitCaseMap(
+ raw_ostream &o,
+ const std::map<std::string, std::vector<std::string>> &CaseMap) {
+ std::map<std::string, std::vector<std::string>>::const_iterator IE, EE;
+ for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) {
+ const std::string &Case = IE->first;
+ const std::vector<std::string> &InstList = IE->second;
+
+ for (int i = 0, N = InstList.size(); i < N; i++) {
+ if (i)
+ o << "\n";
+ o << " case " << InstList[i] << ":";
+ }
+ o << " {\n";
+ o << Case;
+ o << " break;\n"
+ << " }\n";
+ }
+}
+
void CodeEmitterGen::run(raw_ostream &o) {
+ emitSourceFileHeader("Machine Code Emitter", o);
+
CodeGenTarget Target(Records);
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
@@ -498,6 +496,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
// Map to accumulate all the cases.
std::map<std::string, std::vector<std::string>> CaseMap;
+ std::map<std::string, std::vector<std::string>> BitOffsetCaseMap;
// Construct all cases statement for each opcode
for (Record *R : Insts) {
@@ -506,9 +505,11 @@ void CodeEmitterGen::run(raw_ostream &o) {
continue;
std::string InstName =
(R->getValueAsString("Namespace") + "::" + R->getName()).str();
- std::string Case = getInstructionCase(R, Target);
+ std::string Case, BitOffsetCase;
+ std::tie(Case, BitOffsetCase) = getInstructionCases(R, Target);
- CaseMap[Case].push_back(std::move(InstName));
+ CaseMap[Case].push_back(InstName);
+ BitOffsetCaseMap[BitOffsetCase].push_back(std::move(InstName));
}
// Emit initial function code
@@ -531,21 +532,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
}
// Emit each case statement
- std::map<std::string, std::vector<std::string>>::iterator IE, EE;
- for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) {
- const std::string &Case = IE->first;
- std::vector<std::string> &InstList = IE->second;
-
- for (int i = 0, N = InstList.size(); i < N; i++) {
- if (i)
- o << "\n";
- o << " case " << InstList[i] << ":";
- }
- o << " {\n";
- o << Case;
- o << " break;\n"
- << " }\n";
- }
+ emitCaseMap(o, CaseMap);
// Default case: unhandled opcode
o << " default:\n"
@@ -559,16 +546,27 @@ void CodeEmitterGen::run(raw_ostream &o) {
else
o << " return Value;\n";
o << "}\n\n";
+
+ o << "#ifdef GET_OPERAND_BIT_OFFSET\n"
+ << "#undef GET_OPERAND_BIT_OFFSET\n\n"
+ << "uint32_t " << Target.getName()
+ << "MCCodeEmitter::getOperandBitOffset(const MCInst &MI,\n"
+ << " unsigned OpNum,\n"
+ << " const MCSubtargetInfo &STI) const {\n"
+ << " switch (MI.getOpcode()) {\n";
+ emitCaseMap(o, BitOffsetCaseMap);
+ o << " }\n"
+ << " std::string msg;\n"
+ << " raw_string_ostream Msg(msg);\n"
+ << " Msg << \"Not supported instr[opcode]: \" << MI << \"[\" << OpNum "
+ "<< \"]\";\n"
+ << " report_fatal_error(Msg.str().c_str());\n"
+ << "}\n\n"
+ << "#endif // GET_OPERAND_BIT_OFFSET\n\n";
}
}
} // end anonymous namespace
-namespace llvm {
-
-void EmitCodeEmitter(RecordKeeper &RK, raw_ostream &OS) {
- emitSourceFileHeader("Machine Code Emitter", OS);
- CodeEmitterGen(RK).run(OS);
-}
-
-} // end namespace llvm
+static TableGen::Emitter::OptClass<CodeEmitterGen>
+ X("gen-emitter", "Generate machine code emitter");