diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:04 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:11 +0000 |
commit | e3b557809604d036af6e00c60f012c2025b59a5e (patch) | |
tree | 8a11ba2269a3b669601e2fd41145b174008f4da8 /llvm/utils/TableGen/DecoderEmitter.cpp | |
parent | 08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff) |
Diffstat (limited to 'llvm/utils/TableGen/DecoderEmitter.cpp')
-rw-r--r-- | llvm/utils/TableGen/DecoderEmitter.cpp | 320 |
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 |