aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen/DecoderEmitter.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:04 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:11 +0000
commite3b557809604d036af6e00c60f012c2025b59a5e (patch)
tree8a11ba2269a3b669601e2fd41145b174008f4da8 /llvm/utils/TableGen/DecoderEmitter.cpp
parent08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff)
Diffstat (limited to 'llvm/utils/TableGen/DecoderEmitter.cpp')
-rw-r--r--llvm/utils/TableGen/DecoderEmitter.cpp320
1 files changed, 194 insertions, 126 deletions
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 8477e0639f90..8f816744370c 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -127,17 +127,8 @@ class DecoderEmitter {
std::vector<EncodingAndInst> NumberedEncodings;
public:
- // Defaults preserved here for documentation, even though they aren't
- // strictly necessary given the way that this is currently being called.
- DecoderEmitter(RecordKeeper &R, std::string PredicateNamespace,
- std::string GPrefix = "if (",
- std::string GPostfix = " == MCDisassembler::Fail)",
- std::string ROK = "MCDisassembler::Success",
- std::string RFail = "MCDisassembler::Fail", std::string L = "")
- : RK(R), Target(R), PredicateNamespace(std::move(PredicateNamespace)),
- GuardPrefix(std::move(GPrefix)), GuardPostfix(std::move(GPostfix)),
- ReturnOK(std::move(ROK)), ReturnFail(std::move(RFail)),
- Locals(std::move(L)) {}
+ DecoderEmitter(RecordKeeper &R, std::string PredicateNamespace)
+ : RK(R), Target(R), PredicateNamespace(std::move(PredicateNamespace)) {}
// Emit the decoder state machine table.
void emitTable(formatted_raw_ostream &o, DecoderTable &Table,
@@ -160,9 +151,6 @@ private:
public:
std::string PredicateNamespace;
- std::string GuardPrefix, GuardPostfix;
- std::string ReturnOK, ReturnFail;
- std::string Locals;
};
} // end anonymous namespace
@@ -1170,11 +1158,11 @@ void FilterChooser::emitBinaryParser(raw_ostream &o, unsigned &Indentation,
if (Decoder != "") {
OpHasCompleteDecoder = OpInfo.HasCompleteDecoder;
- o.indent(Indentation) << Emitter->GuardPrefix << Decoder
- << "(MI, tmp, Address, Decoder)"
- << Emitter->GuardPostfix
- << " { " << (OpHasCompleteDecoder ? "" : "DecodeComplete = false; ")
- << "return MCDisassembler::Fail; }\n";
+ o.indent(Indentation) << "if (!Check(S, " << Decoder
+ << "(MI, tmp, Address, Decoder))) { "
+ << (OpHasCompleteDecoder ? ""
+ : "DecodeComplete = false; ")
+ << "return MCDisassembler::Fail; }\n";
} else {
OpHasCompleteDecoder = true;
o.indent(Indentation) << "MI.addOperand(MCOperand::createImm(tmp));\n";
@@ -1189,11 +1177,11 @@ void FilterChooser::emitDecoder(raw_ostream &OS, unsigned Indentation,
// If a custom instruction decoder was specified, use that.
if (Op.numFields() == 0 && !Op.Decoder.empty()) {
HasCompleteDecoder = Op.HasCompleteDecoder;
- OS.indent(Indentation) << Emitter->GuardPrefix << Op.Decoder
- << "(MI, insn, Address, Decoder)"
- << Emitter->GuardPostfix
- << " { " << (HasCompleteDecoder ? "" : "DecodeComplete = false; ")
- << "return MCDisassembler::Fail; }\n";
+ OS.indent(Indentation)
+ << "if (!Check(S, " << Op.Decoder
+ << "(MI, insn, Address, Decoder))) { "
+ << (HasCompleteDecoder ? "" : "DecodeComplete = false; ")
+ << "return MCDisassembler::Fail; }\n";
break;
}
@@ -1905,6 +1893,8 @@ void parseVarLenInstOperand(const Record &Def,
OpName);
unsigned OpIdx = CGI.Operands.getFlattenedOperandNumber(OpSubOpPair);
Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset);
+ if (!EncodingSegment.CustomDecoder.empty())
+ Operands[OpIdx].Decoder = EncodingSegment.CustomDecoder.str();
int TiedReg = TiedTo[OpSubOpPair.first];
if (TiedReg != -1) {
@@ -1918,6 +1908,55 @@ void parseVarLenInstOperand(const Record &Def,
}
}
+static void debugDumpRecord(const Record &Rec) {
+ // Dump the record, so we can see what's going on...
+ std::string E;
+ raw_string_ostream S(E);
+ S << "Dumping record for previous error:\n";
+ S << Rec;
+ PrintNote(E);
+}
+
+/// For an operand field named OpName: populate OpInfo.InitValue with the
+/// constant-valued bit values, and OpInfo.Fields with the ranges of bits to
+/// insert from the decoded instruction.
+static void addOneOperandFields(const Record &EncodingDef, const BitsInit &Bits,
+ std::map<std::string, std::string> &TiedNames,
+ StringRef OpName, OperandInfo &OpInfo) {
+ // Some bits of the operand may be required to be 1 depending on the
+ // instruction's encoding. Collect those bits.
+ if (const RecordVal *EncodedValue = EncodingDef.getValue(OpName))
+ if (const BitsInit *OpBits = dyn_cast<BitsInit>(EncodedValue->getValue()))
+ for (unsigned I = 0; I < OpBits->getNumBits(); ++I)
+ if (const BitInit *OpBit = dyn_cast<BitInit>(OpBits->getBit(I)))
+ if (OpBit->getValue())
+ OpInfo.InitValue |= 1ULL << I;
+
+ for (unsigned I = 0, J = 0; I != Bits.getNumBits(); I = J) {
+ VarInit *Var;
+ unsigned Offset = 0;
+ for (; J != Bits.getNumBits(); ++J) {
+ VarBitInit *BJ = dyn_cast<VarBitInit>(Bits.getBit(J));
+ if (BJ) {
+ Var = dyn_cast<VarInit>(BJ->getBitVar());
+ if (I == J)
+ Offset = BJ->getBitNum();
+ else if (BJ->getBitNum() != Offset + J - I)
+ break;
+ } else {
+ Var = dyn_cast<VarInit>(Bits.getBit(J));
+ }
+ if (!Var || (Var->getName() != OpName &&
+ Var->getName() != TiedNames[std::string(OpName)]))
+ break;
+ }
+ if (I == J)
+ ++J;
+ else
+ OpInfo.addField(I, J - I, Offset);
+ }
+}
+
static unsigned
populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
const CodeGenInstruction &CGI, unsigned Opc,
@@ -1966,14 +2005,23 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
// operands that are not explicitly represented in the encoding.
std::map<std::string, std::string> TiedNames;
for (unsigned i = 0; i < CGI.Operands.size(); ++i) {
- int tiedTo = CGI.Operands[i].getTiedRegister();
- if (tiedTo != -1) {
- std::pair<unsigned, unsigned> SO =
- CGI.Operands.getSubOperandNumber(tiedTo);
- TiedNames[std::string(InOutOperands[i].second)] =
- std::string(InOutOperands[SO.first].second);
- TiedNames[std::string(InOutOperands[SO.first].second)] =
- std::string(InOutOperands[i].second);
+ auto &Op = CGI.Operands[i];
+ for (unsigned j = 0; j < Op.Constraints.size(); ++j) {
+ const CGIOperandList::ConstraintInfo &CI = Op.Constraints[j];
+ if (CI.isTied()) {
+ int tiedTo = CI.getTiedOperand();
+ std::pair<unsigned, unsigned> SO =
+ CGI.Operands.getSubOperandNumber(tiedTo);
+ std::string TiedName = CGI.Operands[SO.first].SubOpNames[SO.second];
+ if (TiedName.empty())
+ TiedName = CGI.Operands[SO.first].Name;
+ std::string MyName = Op.SubOpNames[j];
+ if (MyName.empty())
+ MyName = Op.Name;
+
+ TiedNames[MyName] = TiedName;
+ TiedNames[TiedName] = MyName;
+ }
}
}
@@ -1982,8 +2030,12 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
} else {
std::map<std::string, std::vector<OperandInfo>> NumberedInsnOperands;
std::set<std::string> NumberedInsnOperandsNoTie;
- if (Target.getInstructionSet()->getValueAsBit(
- "decodePositionallyEncodedOperands")) {
+ bool SupportPositionalDecoding =
+ Target.getInstructionSet()->getValueAsBit(
+ "useDeprecatedPositionallyEncodedOperands") &&
+ Target.getInstructionSet()->getValueAsBit(
+ "decodePositionallyEncodedOperands");
+ if (SupportPositionalDecoding) {
const std::vector<RecordVal> &Vals = Def.getValues();
unsigned NumberedOp = 0;
@@ -2025,7 +2077,9 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
// Skip variables that correspond to explicitly-named operands.
unsigned OpIdx;
- if (CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx))
+ std::pair<unsigned, unsigned> SubOp;
+ if (CGI.Operands.hasSubOperandAlias(Vals[i].getName(), SubOp) ||
+ CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx))
continue;
// Get the bit range for this operand:
@@ -2127,106 +2181,113 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
// For each operand, see if we can figure out where it is encoded.
for (const auto &Op : InOutOperands) {
- if (!NumberedInsnOperands[std::string(Op.second)].empty()) {
- llvm::append_range(InsnOperands,
- NumberedInsnOperands[std::string(Op.second)]);
- continue;
- }
- if (!NumberedInsnOperands[TiedNames[std::string(Op.second)]].empty()) {
- if (!NumberedInsnOperandsNoTie.count(
- TiedNames[std::string(Op.second)])) {
- // Figure out to which (sub)operand we're tied.
- unsigned i =
- CGI.Operands.getOperandNamed(TiedNames[std::string(Op.second)]);
- int tiedTo = CGI.Operands[i].getTiedRegister();
- if (tiedTo == -1) {
- i = CGI.Operands.getOperandNamed(Op.second);
- tiedTo = CGI.Operands[i].getTiedRegister();
- }
-
- if (tiedTo != -1) {
- std::pair<unsigned, unsigned> SO =
- CGI.Operands.getSubOperandNumber(tiedTo);
+ Init *OpInit = Op.first;
+ StringRef OpName = Op.second;
- InsnOperands.push_back(
- NumberedInsnOperands[TiedNames[std::string(Op.second)]]
- [SO.second]);
- }
+ if (SupportPositionalDecoding) {
+ if (!NumberedInsnOperands[std::string(OpName)].empty()) {
+ llvm::append_range(InsnOperands,
+ NumberedInsnOperands[std::string(OpName)]);
+ continue;
}
- continue;
- }
-
- // At this point, we can locate the decoder field, but we need to know how
- // to interpret it. As a first step, require the target to provide
- // callbacks for decoding register classes.
-
- OperandInfo OpInfo = getOpInfo(cast<DefInit>(Op.first)->getDef());
-
- // Some bits of the operand may be required to be 1 depending on the
- // instruction's encoding. Collect those bits.
- if (const RecordVal *EncodedValue = EncodingDef.getValue(Op.second))
- if (const BitsInit *OpBits =
- dyn_cast<BitsInit>(EncodedValue->getValue()))
- for (unsigned I = 0; I < OpBits->getNumBits(); ++I)
- if (const BitInit *OpBit = dyn_cast<BitInit>(OpBits->getBit(I)))
- if (OpBit->getValue())
- OpInfo.InitValue |= 1ULL << I;
-
- unsigned Base = ~0U;
- unsigned Width = 0;
- unsigned Offset = 0;
-
- for (unsigned bi = 0; bi < Bits.getNumBits(); ++bi) {
- VarInit *Var = nullptr;
- VarBitInit *BI = dyn_cast<VarBitInit>(Bits.getBit(bi));
- if (BI)
- Var = dyn_cast<VarInit>(BI->getBitVar());
- else
- Var = dyn_cast<VarInit>(Bits.getBit(bi));
-
- if (!Var) {
- if (Base != ~0U) {
- OpInfo.addField(Base, Width, Offset);
- Base = ~0U;
- Width = 0;
- Offset = 0;
+ if (!NumberedInsnOperands[TiedNames[std::string(OpName)]].empty()) {
+ if (!NumberedInsnOperandsNoTie.count(
+ TiedNames[std::string(OpName)])) {
+ // Figure out to which (sub)operand we're tied.
+ unsigned i =
+ CGI.Operands.getOperandNamed(TiedNames[std::string(OpName)]);
+ int tiedTo = CGI.Operands[i].getTiedRegister();
+ if (tiedTo == -1) {
+ i = CGI.Operands.getOperandNamed(OpName);
+ tiedTo = CGI.Operands[i].getTiedRegister();
+ }
+
+ if (tiedTo != -1) {
+ std::pair<unsigned, unsigned> SO =
+ CGI.Operands.getSubOperandNumber(tiedTo);
+
+ InsnOperands.push_back(
+ NumberedInsnOperands[TiedNames[std::string(OpName)]]
+ [SO.second]);
+ }
}
continue;
}
+ }
- if ((Var->getName() != Op.second &&
- Var->getName() != TiedNames[std::string(Op.second)])) {
- if (Base != ~0U) {
- OpInfo.addField(Base, Width, Offset);
- Base = ~0U;
- Width = 0;
- Offset = 0;
- }
+ // 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.
+ DagInit *SubArgDag = dyn_cast<DagInit>(OpInit);
+ if (SubArgDag)
+ OpInit = SubArgDag->getOperator();
+ Record *OpTypeRec = cast<DefInit>(OpInit)->getDef();
+ // Lookup the sub-operands from the operand type record (note that only
+ // Operand subclasses have MIOperandInfo, see CodeGenInstruction.cpp).
+ DagInit *SubOps = OpTypeRec->isSubClassOf("Operand")
+ ? OpTypeRec->getValueAsDag("MIOperandInfo")
+ : nullptr;
+
+ // Lookup the decoder method and construct a new OperandInfo to hold our result.
+ OperandInfo OpInfo = getOpInfo(OpTypeRec);
+
+ // If we have named sub-operands...
+ if (SubArgDag) {
+ // Then there should not be a custom decoder specified on the top-level
+ // type.
+ if (!OpInfo.Decoder.empty()) {
+ PrintError(EncodingDef.getLoc(),
+ "DecoderEmitter: operand \"" + OpName + "\" has type \"" +
+ OpInit->getAsString() +
+ "\" with a custom DecoderMethod, but also named "
+ "sub-operands.");
continue;
}
- if (Base == ~0U) {
- Base = bi;
- Width = 1;
- Offset = BI ? BI->getBitNum() : 0;
- } else if (BI && BI->getBitNum() != Offset + Width) {
- OpInfo.addField(Base, Width, Offset);
- Base = bi;
- Width = 1;
- Offset = BI->getBitNum();
- } else {
- ++Width;
+ // Decode each of the sub-ops separately.
+ assert(SubOps && SubArgDag->getNumArgs() == SubOps->getNumArgs());
+ for (unsigned i = 0; i < SubOps->getNumArgs(); ++i) {
+ StringRef SubOpName = SubArgDag->getArgNameStr(i);
+ OperandInfo SubOpInfo =
+ getOpInfo(cast<DefInit>(SubOps->getArg(i))->getDef());
+
+ addOneOperandFields(EncodingDef, Bits, TiedNames, SubOpName,
+ SubOpInfo);
+ InsnOperands.push_back(SubOpInfo);
}
+ continue;
}
- if (Base != ~0U)
- OpInfo.addField(Base, Width, Offset);
+ // Otherwise, if we have an operand with sub-operands, but they aren't
+ // named...
+ if (SubOps && OpInfo.Decoder.empty()) {
+ // If it's a single sub-operand, and no custom decoder, use the decoder
+ // from the one sub-operand.
+ if (SubOps->getNumArgs() == 1)
+ OpInfo = getOpInfo(cast<DefInit>(SubOps->getArg(0))->getDef());
+
+ // If we have multiple sub-ops, there'd better have a custom
+ // decoder. (Otherwise we don't know how to populate them properly...)
+ if (SubOps->getNumArgs() > 1) {
+ PrintError(EncodingDef.getLoc(),
+ "DecoderEmitter: operand \"" + OpName +
+ "\" uses MIOperandInfo with multiple ops, but doesn't "
+ "have a custom decoder!");
+ debugDumpRecord(EncodingDef);
+ continue;
+ }
+ }
+ addOneOperandFields(EncodingDef, Bits, TiedNames, OpName, OpInfo);
+ // FIXME: it should be an error not to find a definition for a given
+ // operand, rather than just failing to add it to the resulting
+ // instruction! (This is a longstanding bug, which will be addressed in an
+ // upcoming change.)
if (OpInfo.numFields() > 0)
InsnOperands.push_back(OpInfo);
}
}
-
Operands[Opc] = InsnOperands;
#if 0
@@ -2254,7 +2315,7 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
// fieldFromInstruction().
// On Windows we make sure that this function is not inlined when
// using the VS compiler. It has a bug which causes the function
-// to be optimized out in some circustances. See llvm.org/pr38292
+// to be optimized out in some circumstances. See llvm.org/pr38292
static void emitFieldFromInstruction(formatted_raw_ostream &OS) {
OS << "// Helper functions for extracting fields from encoded instructions.\n"
<< "// InsnType must either be integral or an APInt-like object that "
@@ -2520,6 +2581,17 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS,
<< "}\n\n";
}
+// Helper to propagate SoftFail status. Returns false if the status is Fail;
+// callers are expected to early-exit in that condition. (Note, the '&' operator
+// is correct to propagate the values of this enum; see comment on 'enum
+// DecodeStatus'.)
+static void emitCheck(formatted_raw_ostream &OS) {
+ OS << "static bool Check(DecodeStatus &Out, DecodeStatus In) {\n"
+ << " Out = static_cast<DecodeStatus>(Out & In);\n"
+ << " return Out != MCDisassembler::Fail;\n"
+ << "}\n\n";
+}
+
// Emits disassembler code for instruction decoding.
void DecoderEmitter::run(raw_ostream &o) {
formatted_raw_ostream OS(o);
@@ -2536,6 +2608,7 @@ void DecoderEmitter::run(raw_ostream &o) {
emitFieldFromInstruction(OS);
emitInsertBits(OS);
+ emitCheck(OS);
Target.reverseBitsForLittleEndianEncoding();
@@ -2671,7 +2744,6 @@ void DecoderEmitter::run(raw_ostream &o) {
// Print the table to the output stream.
emitTable(OS, TableInfo.Table, 0, FC.getBitWidth(), Opc.first.first);
- OS.flush();
}
// For variable instruction, we emit a instruction length table
@@ -2694,12 +2766,8 @@ void DecoderEmitter::run(raw_ostream &o) {
namespace llvm {
void EmitDecoder(RecordKeeper &RK, raw_ostream &OS,
- const std::string &PredicateNamespace,
- const std::string &GPrefix, const std::string &GPostfix,
- const std::string &ROK, const std::string &RFail,
- const std::string &L) {
- DecoderEmitter(RK, PredicateNamespace, GPrefix, GPostfix, ROK, RFail, L)
- .run(OS);
+ const std::string &PredicateNamespace) {
+ DecoderEmitter(RK, PredicateNamespace).run(OS);
}
} // end namespace llvm