summaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen/DecoderEmitter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/utils/TableGen/DecoderEmitter.cpp')
-rw-r--r--llvm/utils/TableGen/DecoderEmitter.cpp105
1 files changed, 82 insertions, 23 deletions
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 339063dd112a..ebb7deb757c4 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -104,6 +104,18 @@ static cl::opt<bool> SpecializeDecodersPerBitwidth(
"Helps reduce the code size."),
cl::init(false), cl::cat(DisassemblerEmitterCat));
+static cl::opt<bool> IgnoreNonDecodableOperands(
+ "ignore-non-decodable-operands",
+ cl::desc(
+ "Do not issue an error if an operand cannot be decoded automatically."),
+ cl::init(false), cl::cat(DisassemblerEmitterCat));
+
+static cl::opt<bool> IgnoreFullyDefinedOperands(
+ "ignore-fully-defined-operands",
+ cl::desc(
+ "Do not automatically decode operands with no '?' in their encoding."),
+ cl::init(false), cl::cat(DisassemblerEmitterCat));
+
STATISTIC(NumEncodings, "Number of encodings considered");
STATISTIC(NumEncodingsLackingDisasm,
"Number of encodings without disassembler info");
@@ -149,7 +161,7 @@ struct OperandInfo {
std::vector<EncodingField> Fields;
std::string Decoder;
bool HasCompleteDecoder;
- uint64_t InitValue = 0;
+ std::optional<uint64_t> InitValue;
OperandInfo(std::string D, bool HCD) : Decoder(D), HasCompleteDecoder(HCD) {}
@@ -1110,11 +1122,29 @@ FilterChooser::getIslands(const KnownBits &EncodingBits) const {
void DecoderTableBuilder::emitBinaryParser(raw_ostream &OS, indent Indent,
const OperandInfo &OpInfo) const {
- bool UseInsertBits = OpInfo.numFields() != 1 || OpInfo.InitValue != 0;
+ // Special case for 'bits<0>'.
+ if (OpInfo.Fields.empty() && !OpInfo.InitValue) {
+ if (IgnoreNonDecodableOperands)
+ return;
+ assert(!OpInfo.Decoder.empty());
+ // The operand has no encoding, so the corresponding argument is omitted.
+ // This avoids confusion and allows the function to be overloaded if the
+ // operand does have an encoding in other instructions.
+ OS << Indent << "if (!Check(S, " << OpInfo.Decoder << "(MI, Decoder)))\n"
+ << Indent << " return MCDisassembler::Fail;\n";
+ return;
+ }
+
+ if (OpInfo.Fields.empty() && OpInfo.InitValue && IgnoreFullyDefinedOperands)
+ return;
+
+ // We need to construct the encoding of the operand from pieces if it is not
+ // encoded sequentially or has a non-zero constant part in the encoding.
+ bool UseInsertBits = OpInfo.numFields() > 1 || OpInfo.InitValue.value_or(0);
if (UseInsertBits) {
OS << Indent << "tmp = 0x";
- OS.write_hex(OpInfo.InitValue);
+ OS.write_hex(OpInfo.InitValue.value_or(0));
OS << ";\n";
}
@@ -1158,8 +1188,7 @@ void DecoderTableBuilder::emitDecoder(raw_ostream &OS, indent Indent,
}
for (const OperandInfo &Op : Encoding.getOperands())
- if (Op.numFields())
- emitBinaryParser(OS, Indent, Op);
+ emitBinaryParser(OS, Indent, Op);
}
unsigned DecoderTableBuilder::getDecoderIndex(unsigned EncodingID) const {
@@ -1941,15 +1970,48 @@ static void debugDumpRecord(const Record &Rec) {
static void addOneOperandFields(const Record *EncodingDef,
const BitsInit &InstBits,
std::map<StringRef, StringRef> &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;
+ const Record *OpRec, StringRef OpName,
+ OperandInfo &OpInfo) {
+ // Find a field with the operand's name.
+ const RecordVal *OpEncodingField = EncodingDef->getValue(OpName);
+
+ // If there is no such field, try tied operand's name.
+ if (!OpEncodingField) {
+ if (auto I = TiedNames.find(OpName); I != TiedNames.end())
+ OpEncodingField = EncodingDef->getValue(I->second);
+
+ // If still no luck, the old behavior is to not decode this operand
+ // automatically and let the target do it. This is error-prone, so
+ // the new behavior is to report an error.
+ if (!OpEncodingField) {
+ if (!IgnoreNonDecodableOperands)
+ PrintError(EncodingDef->getLoc(),
+ "could not find field for operand '" + OpName + "'");
+ return;
+ }
+ }
+
+ // Some or all bits of the operand may be required to be 0 or 1 depending
+ // on the instruction's encoding. Collect those bits.
+ if (const auto *OpBit = dyn_cast<BitInit>(OpEncodingField->getValue())) {
+ OpInfo.InitValue = OpBit->getValue();
+ return;
+ }
+ if (const auto *OpBits = dyn_cast<BitsInit>(OpEncodingField->getValue())) {
+ if (OpBits->getNumBits() == 0) {
+ if (OpInfo.Decoder.empty()) {
+ PrintError(EncodingDef->getLoc(), "operand '" + OpName + "' of type '" +
+ OpRec->getName() +
+ "' must have a decoder method");
+ }
+ return;
+ }
+ for (unsigned I = 0; I < OpBits->getNumBits(); ++I) {
+ if (const auto *OpBit = dyn_cast<BitInit>(OpBits->getBit(I)))
+ OpInfo.InitValue = OpInfo.InitValue.value_or(0) |
+ static_cast<uint64_t>(OpBit->getValue()) << I;
+ }
+ }
// Find out where the variable bits of the operand are encoded. The bits don't
// have to be consecutive or in ascending order. For example, an operand could
@@ -2034,8 +2096,10 @@ void InstructionEncoding::parseFixedLenOperands(const BitsInit &Bits) {
// Decode each of the sub-ops separately.
for (auto [SubOpName, SubOp] :
zip_equal(Op.SubOpNames, Op.MIOperandInfo->getArgs())) {
- OperandInfo SubOpInfo = getOpInfo(cast<DefInit>(SubOp)->getDef());
- addOneOperandFields(EncodingDef, Bits, TiedNames, SubOpName, SubOpInfo);
+ const Record *SubOpRec = cast<DefInit>(SubOp)->getDef();
+ OperandInfo SubOpInfo = getOpInfo(SubOpRec);
+ addOneOperandFields(EncodingDef, Bits, TiedNames, SubOpRec, SubOpName,
+ SubOpInfo);
Operands.push_back(std::move(SubOpInfo));
}
continue;
@@ -2056,13 +2120,8 @@ void InstructionEncoding::parseFixedLenOperands(const BitsInit &Bits) {
}
}
- addOneOperandFields(EncodingDef, Bits, TiedNames, Op.Name, 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)
- Operands.push_back(std::move(OpInfo));
+ addOneOperandFields(EncodingDef, Bits, TiedNames, Op.Rec, Op.Name, OpInfo);
+ Operands.push_back(std::move(OpInfo));
}
}