//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "InstructionEncoding.h" #include "CodeGenInstruction.h" #include "VarLenCodeEmitterGen.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/TableGen/Error.h" using namespace llvm; std::pair InstructionEncoding::findOperandDecoderMethod(const Record *Record) { std::string Decoder; const RecordVal *DecoderString = Record->getValue("DecoderMethod"); const StringInit *String = DecoderString ? dyn_cast(DecoderString->getValue()) : nullptr; if (String) { Decoder = String->getValue().str(); if (!Decoder.empty()) return {Decoder, false}; } if (Record->isSubClassOf("RegisterOperand")) // Allows use of a DecoderMethod in referenced RegisterClass if set. return findOperandDecoderMethod(Record->getValueAsDef("RegClass")); if (Record->isSubClassOf("RegisterClass")) { Decoder = "Decode" + Record->getName().str() + "RegisterClass"; } else if (Record->isSubClassOf("RegClassByHwMode")) { Decoder = "Decode" + Record->getName().str() + "RegClassByHwMode"; } else if (Record->isSubClassOf("PointerLikeRegClass")) { Decoder = "DecodePointerLikeRegClass" + utostr(Record->getValueAsInt("RegClassKind")); } return {Decoder, true}; } OperandInfo InstructionEncoding::getOpInfo(const Record *TypeRecord) { const RecordVal *HasCompleteDecoderVal = TypeRecord->getValue("hasCompleteDecoder"); const BitInit *HasCompleteDecoderBit = HasCompleteDecoderVal ? dyn_cast(HasCompleteDecoderVal->getValue()) : nullptr; bool HasCompleteDecoder = HasCompleteDecoderBit ? HasCompleteDecoderBit->getValue() : true; return OperandInfo(findOperandDecoderMethod(TypeRecord).first, HasCompleteDecoder); } void InstructionEncoding::parseVarLenEncoding(const VarLenInst &VLI) { InstBits = KnownBits(VLI.size()); SoftFailMask = APInt(VLI.size(), 0); // Parse Inst field. unsigned I = 0; for (const EncodingSegment &S : VLI) { if (const auto *SegmentBits = dyn_cast(S.Value)) { for (const Init *V : SegmentBits->getBits()) { if (const auto *B = dyn_cast(V)) { if (B->getValue()) InstBits.One.setBit(I); else InstBits.Zero.setBit(I); } ++I; } } else if (const auto *B = dyn_cast(S.Value)) { if (B->getValue()) InstBits.One.setBit(I); else InstBits.Zero.setBit(I); ++I; } else { I += S.BitWidth; } } assert(I == VLI.size()); } void InstructionEncoding::parseFixedLenEncoding( const BitsInit &RecordInstBits) { // For fixed length instructions, sometimes the `Inst` field specifies more // bits than the actual size of the instruction, which is specified in `Size`. // In such cases, we do some basic validation and drop the upper bits. unsigned BitWidth = EncodingDef->getValueAsInt("Size") * 8; unsigned InstNumBits = RecordInstBits.getNumBits(); // Returns true if all bits in `Bits` are zero or unset. auto CheckAllZeroOrUnset = [&](ArrayRef Bits, const RecordVal *Field) { bool AllZeroOrUnset = llvm::all_of(Bits, [](const Init *Bit) { if (const auto *BI = dyn_cast(Bit)) return !BI->getValue(); return isa(Bit); }); if (AllZeroOrUnset) return; PrintNote([Field](raw_ostream &OS) { Field->print(OS); }); PrintFatalError(EncodingDef, Twine(Name) + ": Size is " + Twine(BitWidth) + " bits, but " + Field->getName() + " bits beyond that are not zero/unset"); }; if (InstNumBits < BitWidth) PrintFatalError(EncodingDef, Twine(Name) + ": Size is " + Twine(BitWidth) + " bits, but Inst specifies only " + Twine(InstNumBits) + " bits"); if (InstNumBits > BitWidth) { // Ensure that all the bits beyond 'Size' are 0 or unset (i.e., carry no // actual encoding). ArrayRef UpperBits = RecordInstBits.getBits().drop_front(BitWidth); const RecordVal *InstField = EncodingDef->getValue("Inst"); CheckAllZeroOrUnset(UpperBits, InstField); } ArrayRef ActiveInstBits = RecordInstBits.getBits().take_front(BitWidth); InstBits = KnownBits(BitWidth); SoftFailMask = APInt(BitWidth, 0); // Parse Inst field. for (auto [I, V] : enumerate(ActiveInstBits)) { if (const auto *B = dyn_cast(V)) { if (B->getValue()) InstBits.One.setBit(I); else InstBits.Zero.setBit(I); } } // Parse SoftFail field. const RecordVal *SoftFailField = EncodingDef->getValue("SoftFail"); if (!SoftFailField) return; const auto *SFBits = dyn_cast(SoftFailField->getValue()); if (!SFBits || SFBits->getNumBits() != InstNumBits) { PrintNote(EncodingDef->getLoc(), "in record"); PrintFatalError(SoftFailField, formatv("SoftFail field, if defined, must be " "of the same type as Inst, which is bits<{}>", InstNumBits)); } if (InstNumBits > BitWidth) { // Ensure that all upper bits of `SoftFail` are 0 or unset. ArrayRef UpperBits = SFBits->getBits().drop_front(BitWidth); CheckAllZeroOrUnset(UpperBits, SoftFailField); } ArrayRef ActiveSFBits = SFBits->getBits().take_front(BitWidth); for (auto [I, V] : enumerate(ActiveSFBits)) { if (const auto *B = dyn_cast(V); B && B->getValue()) { if (!InstBits.Zero[I] && !InstBits.One[I]) { PrintNote(EncodingDef->getLoc(), "in record"); PrintError(SoftFailField, formatv("SoftFail{{{0}} = 1 requires Inst{{{0}} " "to be fully defined (0 or 1, not '?')", I)); } SoftFailMask.setBit(I); } } } void InstructionEncoding::parseVarLenOperands(const VarLenInst &VLI) { SmallVector TiedTo; for (const auto &[Idx, Op] : enumerate(Inst->Operands)) { if (Op.MIOperandInfo && Op.MIOperandInfo->getNumArgs() > 0) for (auto *Arg : Op.MIOperandInfo->getArgs()) Operands.push_back(getOpInfo(cast(Arg)->getDef())); else Operands.push_back(getOpInfo(Op.Rec)); int TiedReg = Op.getTiedRegister(); TiedTo.push_back(-1); if (TiedReg != -1) { TiedTo[Idx] = TiedReg; TiedTo[TiedReg] = Idx; } } unsigned CurrBitPos = 0; for (const auto &EncodingSegment : VLI) { unsigned Offset = 0; StringRef OpName; if (const StringInit *SI = dyn_cast(EncodingSegment.Value)) { OpName = SI->getValue(); } else if (const DagInit *DI = dyn_cast(EncodingSegment.Value)) { OpName = cast(DI->getArg(0))->getValue(); Offset = cast(DI->getArg(2))->getValue(); } if (!OpName.empty()) { auto OpSubOpPair = Inst->Operands.parseOperandName(OpName); unsigned OpIdx = Inst->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) { unsigned OpIdx = Inst->Operands.getFlattenedOperandNumber( {TiedReg, OpSubOpPair.second}); Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset); } } CurrBitPos += EncodingSegment.BitWidth; } } static void debugDumpRecord(const Record &Rec) { // Dump the record, so we can see what's going on. PrintNote([&Rec](raw_ostream &OS) { OS << "Dumping record for previous error:\n"; OS << Rec; }); } /// 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 &InstBits, std::map &TiedNames, const Record *OpRec, StringRef OpName, OperandInfo &OpInfo) { OpInfo.Name = OpName; // 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, we're done with this operand. if (!OpEncodingField) { OpInfo.HasNoEncoding = true; 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(OpEncodingField->getValue())) { OpInfo.InitValue = OpBit->getValue(); return; } if (const auto *OpBits = dyn_cast(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(OpBits->getBit(I))) OpInfo.InitValue = OpInfo.InitValue.value_or(0) | static_cast(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 // be encoded as follows: // // 7 6 5 4 3 2 1 0 // {1, op{5}, op{2}, op{1}, 0, op{4}, op{3}, ?} // // In this example the operand is encoded in three segments: // // Base Width Offset // op{2...1} 4 2 1 // op{4...3} 1 2 3 // op{5} 6 1 5 // for (unsigned I = 0, J = 0; I != InstBits.getNumBits(); I = J) { const VarInit *Var; unsigned Offset = 0; for (; J != InstBits.getNumBits(); ++J) { const Init *BitJ = InstBits.getBit(J); if (const auto *VBI = dyn_cast(BitJ)) { Var = dyn_cast(VBI->getBitVar()); if (I == J) Offset = VBI->getBitNum(); else if (VBI->getBitNum() != Offset + J - I) break; } else { Var = dyn_cast(BitJ); } if (!Var || (Var->getName() != OpName && Var->getName() != TiedNames[OpName])) break; } if (I == J) ++J; else OpInfo.addField(I, J - I, Offset); } } void InstructionEncoding::parseFixedLenOperands(const BitsInit &Bits) { // Search for tied operands, so that we can correctly instantiate // operands that are not explicitly represented in the encoding. std::map TiedNames; for (const auto &Op : Inst->Operands) { for (const auto &[J, CI] : enumerate(Op.Constraints)) { if (!CI.isTied()) continue; std::pair SO = Inst->Operands.getSubOperandNumber(CI.getTiedOperand()); StringRef TiedName = Inst->Operands[SO.first].SubOpNames[SO.second]; if (TiedName.empty()) TiedName = Inst->Operands[SO.first].Name; StringRef MyName = Op.SubOpNames[J]; if (MyName.empty()) MyName = Op.Name; TiedNames[MyName] = TiedName; TiedNames[TiedName] = MyName; } } // For each operand, see if we can figure out where it is encoded. for (const CGIOperandList::OperandInfo &Op : Inst->Operands) { // Lookup the decoder method and construct a new OperandInfo to hold our // result. OperandInfo OpInfo = getOpInfo(Op.Rec); // If we have named sub-operands... if (Op.MIOperandInfo && !Op.SubOpNames[0].empty()) { // Then there should not be a custom decoder specified on the top-level // type. if (!OpInfo.Decoder.empty()) { PrintError(EncodingDef, "DecoderEmitter: operand \"" + Op.Name + "\" has type \"" + Op.Rec->getName() + "\" with a custom DecoderMethod, but also named " "sub-operands."); continue; } // Decode each of the sub-ops separately. for (auto [SubOpName, SubOp] : zip_equal(Op.SubOpNames, Op.MIOperandInfo->getArgs())) { const Record *SubOpRec = cast(SubOp)->getDef(); OperandInfo SubOpInfo = getOpInfo(SubOpRec); addOneOperandFields(EncodingDef, Bits, TiedNames, SubOpRec, SubOpName, SubOpInfo); Operands.push_back(std::move(SubOpInfo)); } continue; } // Otherwise, if we have an operand with sub-operands, but they aren't // named... if (Op.MIOperandInfo && OpInfo.Decoder.empty()) { // If we have sub-ops, we'd better have a custom decoder. // (Otherwise we don't know how to populate them properly...) if (Op.MIOperandInfo->getNumArgs()) { PrintError(EncodingDef, "DecoderEmitter: operand \"" + Op.Name + "\" has non-empty MIOperandInfo, but doesn't " "have a custom decoder!"); debugDumpRecord(*EncodingDef); continue; } } addOneOperandFields(EncodingDef, Bits, TiedNames, Op.Rec, Op.Name, OpInfo); Operands.push_back(std::move(OpInfo)); } } InstructionEncoding::InstructionEncoding(const Record *EncodingDef, const CodeGenInstruction *Inst) : EncodingDef(EncodingDef), Inst(Inst) { const Record *InstDef = Inst->TheDef; // Give this encoding a name. if (EncodingDef != InstDef) Name = (EncodingDef->getName() + Twine(':')).str(); Name.append(InstDef->getName()); DecoderNamespace = EncodingDef->getValueAsString("DecoderNamespace"); DecoderMethod = EncodingDef->getValueAsString("DecoderMethod"); if (!DecoderMethod.empty()) HasCompleteDecoder = EncodingDef->getValueAsBit("hasCompleteDecoder"); const RecordVal *InstField = EncodingDef->getValue("Inst"); if (const auto *DI = dyn_cast(InstField->getValue())) { VarLenInst VLI(DI, InstField); parseVarLenEncoding(VLI); // If the encoding has a custom decoder, don't bother parsing the operands. if (DecoderMethod.empty()) parseVarLenOperands(VLI); } else { const auto *BI = cast(InstField->getValue()); parseFixedLenEncoding(*BI); // If the encoding has a custom decoder, don't bother parsing the operands. if (DecoderMethod.empty()) parseFixedLenOperands(*BI); } if (DecoderMethod.empty()) { // A generated decoder is always successful if none of the operand // decoders can fail (all are always successful). HasCompleteDecoder = all_of(Operands, [](const OperandInfo &Op) { // By default, a generated operand decoder is assumed to always succeed. // This can be overridden by the user. return Op.Decoder.empty() || Op.HasCompleteDecoder; }); } }