diff options
Diffstat (limited to 'llvm/utils')
43 files changed, 1513 insertions, 928 deletions
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index 1acc2a86d176..c13e5b5deff6 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -595,8 +595,9 @@ struct MatchableInfo { /// findAsmOperandNamed - Find the first AsmOperand with the specified name. /// This does not check the suboperand index. int findAsmOperandNamed(StringRef N, int LastIdx = -1) const { - auto I = std::find_if(AsmOperands.begin() + LastIdx + 1, AsmOperands.end(), - [&](const AsmOperand &Op) { return Op.SrcOpName == N; }); + auto I = + llvm::find_if(llvm::drop_begin(AsmOperands, LastIdx + 1), + [&](const AsmOperand &Op) { return Op.SrcOpName == N; }); return (I != AsmOperands.end()) ? I - AsmOperands.begin() : -1; } @@ -1449,17 +1450,23 @@ void AsmMatcherInfo::buildOperandMatchInfo() { typedef std::map<ClassInfo *, unsigned, deref<std::less<>>> OpClassMaskTy; OpClassMaskTy OpClassMask; + bool CallCustomParserForAllOperands = + AsmParser->getValueAsBit("CallCustomParserForAllOperands"); for (const auto &MI : Matchables) { OpClassMask.clear(); // Keep track of all operands of this instructions which belong to the // same class. + unsigned NumOptionalOps = 0; for (unsigned i = 0, e = MI->AsmOperands.size(); i != e; ++i) { const MatchableInfo::AsmOperand &Op = MI->AsmOperands[i]; - if (Op.Class->ParserMethod.empty()) - continue; - unsigned &OperandMask = OpClassMask[Op.Class]; - OperandMask |= (1 << i); + if (CallCustomParserForAllOperands || !Op.Class->ParserMethod.empty()) { + unsigned &OperandMask = OpClassMask[Op.Class]; + OperandMask |= maskTrailingOnes<unsigned>(NumOptionalOps + 1) + << (i - NumOptionalOps); + } + if (Op.Class->IsOptional) + ++NumOptionalOps; } // Generate operand match info for each mnemonic/operand class pair. @@ -2835,12 +2842,12 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info, return true; } -static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, - const AsmMatcherInfo &Info, StringRef ClassName, - StringToOffsetTable &StringTable, - unsigned MaxMnemonicIndex, - unsigned MaxFeaturesIndex, - bool HasMnemonicFirst) { +static void +emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, + const AsmMatcherInfo &Info, StringRef ClassName, + StringToOffsetTable &StringTable, + unsigned MaxMnemonicIndex, unsigned MaxFeaturesIndex, + bool HasMnemonicFirst, const Record &AsmParser) { unsigned MaxMask = 0; for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) { MaxMask |= OMI.OperandMask; @@ -2991,9 +2998,12 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, OS << " continue;\n\n"; // Emit call to the custom parser method + StringRef ParserName = AsmParser.getValueAsString("OperandParserMethod"); + if (ParserName.empty()) + ParserName = "tryCustomParseOperand"; OS << " // call custom parse method to handle the operand\n"; - OS << " OperandMatchResultTy Result = "; - OS << "tryCustomParseOperand(Operands, it->Class);\n"; + OS << " OperandMatchResultTy Result = " << ParserName + << "(Operands, it->Class);\n"; OS << " if (Result != MatchOperand_NoMatch)\n"; OS << " return Result;\n"; OS << " }\n\n"; @@ -3028,11 +3038,9 @@ static void emitAsmTiedOperandConstraints(CodeGenTarget &Target, OS << " if (OpndNum1 != OpndNum2) {\n"; OS << " auto &SrcOp1 = Operands[OpndNum1];\n"; OS << " auto &SrcOp2 = Operands[OpndNum2];\n"; - OS << " if (SrcOp1->isReg() && SrcOp2->isReg()) {\n"; - OS << " if (!AsmParser.regsEqual(*SrcOp1, *SrcOp2)) {\n"; - OS << " ErrorInfo = OpndNum2;\n"; - OS << " return false;\n"; - OS << " }\n"; + OS << " if (!AsmParser.areEqualRegs(*SrcOp1, *SrcOp2)) {\n"; + OS << " ErrorInfo = OpndNum2;\n"; + OS << " return false;\n"; OS << " }\n"; OS << " }\n"; OS << " break;\n"; @@ -3667,7 +3675,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " else\n"; OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \": \");\n"; OS << " if (ActualIdx >= Operands.size()) {\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"actual operand index out of range \");\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"actual operand " + "index out of range\\n\");\n"; if (ReportMultipleNearMisses) { OS << " bool ThisOperandValid = (Formal == " <<"InvalidMatchClass) || " "isSubclass(Formal, OptionalMatchClass);\n"; @@ -3686,17 +3695,26 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " break;\n"; OS << " }\n"; OS << " } else {\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"but formal operand not required\\n\");\n"; - OS << " break;\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"but formal " + "operand not required\\n\");\n"; OS << " }\n"; OS << " continue;\n"; } else { - OS << " OperandsValid = (Formal == InvalidMatchClass) || isSubclass(Formal, OptionalMatchClass);\n"; - OS << " if (!OperandsValid) ErrorInfo = ActualIdx;\n"; + OS << " if (Formal == InvalidMatchClass) {\n"; if (HasOptionalOperands) { - OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands + OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands << ");\n"; } + OS << " break;\n"; + OS << " }\n"; + OS << " if (isSubclass(Formal, OptionalMatchClass)) {\n"; + if (HasOptionalOperands) { + OS << " OptionalOperandsMask.set(FormalIdx);\n"; + } + OS << " continue;\n"; + OS << " }\n"; + OS << " OperandsValid = false;\n"; + OS << " ErrorInfo = ActualIdx;\n"; OS << " break;\n"; } OS << " }\n"; @@ -3929,7 +3947,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " MII.getDeprecatedInfo(Inst, getSTI(), Info)) {\n"; OS << " SMLoc Loc = ((" << Target.getName() << "Operand &)*Operands[0]).getStartLoc();\n"; - OS << " getParser().Warning(Loc, Info, None);\n"; + OS << " getParser().Warning(Loc, Info, std::nullopt);\n"; OS << " }\n"; } @@ -3961,7 +3979,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (!Info.OperandMatchInfo.empty()) emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable, MaxMnemonicIndex, FeatureBitsets.size(), - HasMnemonicFirst); + HasMnemonicFirst, *AsmParser); OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n"; diff --git a/llvm/utils/TableGen/AsmWriterEmitter.cpp b/llvm/utils/TableGen/AsmWriterEmitter.cpp index 1d738274c75a..f2e4d15a2c75 100644 --- a/llvm/utils/TableGen/AsmWriterEmitter.cpp +++ b/llvm/utils/TableGen/AsmWriterEmitter.cpp @@ -412,7 +412,7 @@ void AsmWriterEmitter::EmitGetMnemonic( << "_t Bits = 0;\n"; while (BytesNeeded != 0) { // Figure out how big this table section needs to be, but no bigger than 4. - unsigned TableSize = std::min(1 << Log2_32(BytesNeeded), 4); + unsigned TableSize = std::min(llvm::bit_floor(BytesNeeded), 4u); BytesNeeded -= TableSize; TableSize *= 8; // Convert to bits; uint64_t Mask = (1ULL << TableSize) - 1; @@ -618,10 +618,11 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { "/// for the specified register.\n" "const char *" << Target.getName() << ClassName << "::"; if (hasAltNames) - O << "\ngetRegisterName(unsigned RegNo, unsigned AltIdx) {\n"; + O << "\ngetRegisterName(MCRegister Reg, unsigned AltIdx) {\n"; else - O << "getRegisterName(unsigned RegNo) {\n"; - O << " assert(RegNo && RegNo < " << (Registers.size()+1) + O << "getRegisterName(MCRegister Reg) {\n"; + O << " unsigned RegNo = Reg.id();\n" + << " assert(RegNo && RegNo < " << (Registers.size() + 1) << " && \"Invalid register number!\");\n" << "\n"; @@ -1177,10 +1178,10 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { O << "#endif\n\n"; O.indent(2) << "AliasMatchingData M {\n"; - O.indent(2) << " makeArrayRef(OpToPatterns),\n"; - O.indent(2) << " makeArrayRef(Patterns),\n"; - O.indent(2) << " makeArrayRef(Conds),\n"; - O.indent(2) << " StringRef(AsmStrings, array_lengthof(AsmStrings)),\n"; + O.indent(2) << " ArrayRef(OpToPatterns),\n"; + O.indent(2) << " ArrayRef(Patterns),\n"; + O.indent(2) << " ArrayRef(Conds),\n"; + O.indent(2) << " StringRef(AsmStrings, std::size(AsmStrings)),\n"; if (MCOpPredicates.empty()) O.indent(2) << " nullptr,\n"; else diff --git a/llvm/utils/TableGen/Attributes.cpp b/llvm/utils/TableGen/Attributes.cpp index 1f975f52d6e7..735c53dd6fcf 100644 --- a/llvm/utils/TableGen/Attributes.cpp +++ b/llvm/utils/TableGen/Attributes.cpp @@ -43,7 +43,7 @@ void Attributes::emitTargetIndependentNames(raw_ostream &OS) { << "(FIRST, SECOND) ATTRIBUTE_ALL(FIRST, SECOND)\n"; OS << "#endif\n\n"; for (StringRef KindName : KindNames) { - for (auto A : Records.getAllDerivedDefinitions(KindName)) { + for (auto *A : Records.getAllDerivedDefinitions(KindName)) { OS << MacroName << "(" << A->getName() << "," << A->getValueAsString("AttrString") << ")\n"; } @@ -63,7 +63,7 @@ void Attributes::emitTargetIndependentNames(raw_ostream &OS) { unsigned Value = 1; // Leave zero for AttrKind::None. for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr"}) { OS << "First" << KindName << " = " << Value << ",\n"; - for (auto A : Records.getAllDerivedDefinitions(KindName)) { + for (auto *A : Records.getAllDerivedDefinitions(KindName)) { OS << A->getName() << " = " << Value << ",\n"; Value++; } @@ -112,7 +112,7 @@ void Attributes::emitAttributeProperties(raw_ostream &OS) { OS << "#undef GET_ATTR_PROP_TABLE\n"; OS << "static const uint8_t AttrPropTable[] = {\n"; for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr"}) { - for (auto A : Records.getAllDerivedDefinitions(KindName)) { + for (auto *A : Records.getAllDerivedDefinitions(KindName)) { OS << "0"; for (Init *P : *A->getValueAsListInit("Properties")) OS << " | AttributeProperty::" << cast<DefInit>(P)->getDef()->getName(); diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp index 1d00c3cfd069..dc4fd589eaa8 100644 --- a/llvm/utils/TableGen/CodeEmitterGen.cpp +++ b/llvm/utils/TableGen/CodeEmitterGen.cpp @@ -25,7 +25,6 @@ #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" -#include <cassert> #include <cstdint> #include <map> #include <set> @@ -50,9 +49,8 @@ private: std::string getInstructionCase(Record *R, CodeGenTarget &Target); std::string getInstructionCaseForEncoding(Record *R, Record *EncodingDef, CodeGenTarget &Target); - void AddCodeToMergeInOperand(Record *R, BitsInit *BI, - const std::string &VarName, - unsigned &NumberedOp, + bool addCodeToMergeInOperand(Record *R, BitsInit *BI, + const std::string &VarName, unsigned &NumberedOp, std::set<unsigned> &NamedOpIndices, std::string &Case, CodeGenTarget &Target); @@ -79,11 +77,13 @@ int CodeEmitterGen::getVariableBit(const std::string &VarName, return -1; } -void CodeEmitterGen:: -AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, - unsigned &NumberedOp, - std::set<unsigned> &NamedOpIndices, - std::string &Case, CodeGenTarget &Target) { +// 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, + CodeGenTarget &Target) { CodeGenInstruction &CGI = Target.getInstruction(R); // Determine if VarName actually contributes to the Inst encoding. @@ -99,18 +99,27 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, // If we found no bits, ignore this value, otherwise emit the call to get the // operand encoding. - if (bit < 0) return; - + if (bit < 0) + return true; + // If the operand matches by name, reference according to that // operand number. Non-matching operands are assumed to be in // order. unsigned OpIdx; - if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) { + std::pair<unsigned, unsigned> SubOp; + if (CGI.Operands.hasSubOperandAlias(VarName, SubOp)) { + OpIdx = CGI.Operands[SubOp.first].MIOperandNo + SubOp.second; + } else if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) { // Get the machine operand number for the indicated operand. OpIdx = CGI.Operands[OpIdx].MIOperandNo; - assert(!CGI.Operands.isFlatOperandNotEmitted(OpIdx) && - "Explicitly used operand also marked as not emitted!"); } 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. @@ -123,41 +132,59 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, if (NumberedOp >= CGI.Operands.back().MIOperandNo + CGI.Operands.back().MINumOperands) { - std::string E; - raw_string_ostream S(E); - S << "Too few operands in record " << R->getName() - << " (no match for variable " << VarName << "):\n"; - S << *R; - PrintFatalError(R, E); + 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; + } } - + + if (CGI.Operands.isFlatOperandNotEmitted(OpIdx)) { + PrintError(R, "Operand " + VarName + " used but also marked as not emitted!"); + return false; + } + std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(OpIdx); - std::string &EncoderMethodName = CGI.Operands[SO.first].EncoderMethodName; + std::string &EncoderMethodName = + CGI.Operands[SO.first].EncoderMethodNames[SO.second]; if (UseAPInt) Case += " op.clearAllBits();\n"; - // If the source operand has a custom encoder, use it. This will - // get the encoding for all of the suboperands. + Case += " // op: " + VarName + "\n"; + + // If the source operand has a custom encoder, use it. if (!EncoderMethodName.empty()) { - // A custom encoder has all of the information for the - // sub-operands, if there are more than one, so only - // query the encoder once per source operand. - if (SO.second == 0) { - Case += " // op: " + VarName + "\n"; - if (UseAPInt) { - Case += " " + EncoderMethodName + "(MI, " + utostr(OpIdx); - Case += ", op"; - } else { - Case += " op = " + EncoderMethodName + "(MI, " + utostr(OpIdx); - } - Case += ", Fixups, STI);\n"; + if (UseAPInt) { + Case += " " + EncoderMethodName + "(MI, " + utostr(OpIdx); + Case += ", op"; + } else { + Case += " op = " + EncoderMethodName + "(MI, " + utostr(OpIdx); } + Case += ", Fixups, STI);\n"; } else { - Case += " // op: " + VarName + "\n"; if (UseAPInt) { Case += " getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")"; Case += ", op, Fixups, STI"; @@ -263,6 +290,7 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, } } } + return true; } std::string CodeEmitterGen::getInstructionCase(Record *R, @@ -310,14 +338,25 @@ std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *Enc // Loop over all of the fields in the instruction, determining which are the // operands to the instruction. + bool Success = true; 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; - AddCodeToMergeInOperand(R, BI, std::string(RV.getName()), NumberedOp, - NamedOpIndices, Case, Target); + Success &= + addCodeToMergeInOperand(R, BI, std::string(RV.getName()), NumberedOp, + NamedOpIndices, Case, Target); + } + + if (!Success) { + // 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 << *R; + PrintNote(E); } StringRef PostEmitter = R->getValueAsString("PostEncoderMethod"); @@ -370,8 +409,8 @@ void CodeEmitterGen::emitInstructionBaseValues( // Start by filling in fixed values. APInt Value(BitWidth, 0); for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) { - if (BitInit *B = dyn_cast<BitInit>(BI->getBit(e - i - 1))) - Value |= APInt(BitWidth, (uint64_t)B->getValue()) << (e - i - 1); + if (auto *B = dyn_cast<BitInit>(BI->getBit(i)); B && B->getValue()) + Value.setBit(i); } o << " "; emitInstBits(o, Value); @@ -478,9 +517,8 @@ void CodeEmitterGen::run(raw_ostream &o) { o << " const unsigned opcode = MI.getOpcode();\n" << " if (Scratch.getBitWidth() != " << BitWidth << ")\n" << " Scratch = Scratch.zext(" << BitWidth << ");\n" - << " Inst = APInt(" << BitWidth - << ", makeArrayRef(InstBits + opcode * " << NumWords << ", " << NumWords - << "));\n" + << " Inst = APInt(" << BitWidth << ", ArrayRef(InstBits + opcode * " + << NumWords << ", " << NumWords << "));\n" << " APInt &Value = Inst;\n" << " APInt &op = Scratch;\n" << " switch (opcode) {\n"; diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp index c15728ac7d23..dd04778e2dbe 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp @@ -544,9 +544,9 @@ bool TypeInfer::EnforceSmallerThan(TypeSetByHwMode &Small, TypeSetByHwMode &Big, // Always treat non-scalable MVTs as smaller than scalable MVTs for the // purposes of ordering. auto ASize = std::make_tuple(A.isScalableVector(), A.getScalarSizeInBits(), - A.getSizeInBits().getKnownMinSize()); + A.getSizeInBits().getKnownMinValue()); auto BSize = std::make_tuple(B.isScalableVector(), B.getScalarSizeInBits(), - B.getSizeInBits().getKnownMinSize()); + B.getSizeInBits().getKnownMinValue()); return ASize < BSize; }; auto SameKindLE = [](MVT A, MVT B) -> bool { @@ -558,9 +558,9 @@ bool TypeInfer::EnforceSmallerThan(TypeSetByHwMode &Small, TypeSetByHwMode &Big, return false; return std::make_tuple(A.getScalarSizeInBits(), - A.getSizeInBits().getKnownMinSize()) <= + A.getSizeInBits().getKnownMinValue()) <= std::make_tuple(B.getScalarSizeInBits(), - B.getSizeInBits().getKnownMinSize()); + B.getSizeInBits().getKnownMinValue()); }; for (unsigned M : Modes) { @@ -740,7 +740,7 @@ bool TypeInfer::EnforceSameNumElts(TypeSetByHwMode &V, TypeSetByHwMode &W) { auto NoLength = [](const SmallDenseSet<ElementCount> &Lengths, MVT T) -> bool { return !Lengths.count(T.isVector() ? T.getVectorElementCount() - : ElementCount::getNull()); + : ElementCount()); }; SmallVector<unsigned, 4> Modes; @@ -751,11 +751,9 @@ bool TypeInfer::EnforceSameNumElts(TypeSetByHwMode &V, TypeSetByHwMode &W) { SmallDenseSet<ElementCount> VN, WN; for (MVT T : VS) - VN.insert(T.isVector() ? T.getVectorElementCount() - : ElementCount::getNull()); + VN.insert(T.isVector() ? T.getVectorElementCount() : ElementCount()); for (MVT T : WS) - WN.insert(T.isVector() ? T.getVectorElementCount() - : ElementCount::getNull()); + WN.insert(T.isVector() ? T.getVectorElementCount() : ElementCount()); Changed |= berase_if(VS, std::bind(NoLength, WN, std::placeholders::_1)); Changed |= berase_if(WS, std::bind(NoLength, VN, std::placeholders::_1)); @@ -2998,7 +2996,7 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit, // chain. if (Int.IS.RetVTs.empty()) Operator = getDAGPatterns().get_intrinsic_void_sdnode(); - else if (Int.ModRef != CodeGenIntrinsic::NoMem || Int.hasSideEffects) + else if (!Int.ME.doesNotAccessMemory() || Int.hasSideEffects) // Has side-effects, requires chain. Operator = getDAGPatterns().get_intrinsic_w_chain_sdnode(); else // Otherwise, no chain. @@ -3637,16 +3635,17 @@ public: if (N->NodeHasProperty(SDNPHasChain, CDP)) hasChain = true; if (const CodeGenIntrinsic *IntInfo = N->getIntrinsicInfo(CDP)) { + ModRefInfo MR = IntInfo->ME.getModRef(); // If this is an intrinsic, analyze it. - if (IntInfo->ModRef & CodeGenIntrinsic::MR_Ref) - mayLoad = true;// These may load memory. + if (isRefSet(MR)) + mayLoad = true; // These may load memory. - if (IntInfo->ModRef & CodeGenIntrinsic::MR_Mod) - mayStore = true;// Intrinsics that can write to memory are 'mayStore'. + if (isModSet(MR)) + mayStore = true; // Intrinsics that can write to memory are 'mayStore'. - if (IntInfo->ModRef >= CodeGenIntrinsic::ReadWriteMem || - IntInfo->hasSideEffects) - // ReadWriteMem intrinsics can have other strange effects. + // Consider intrinsics that don't specify any restrictions on memory + // effects as having a side-effect. + if (IntInfo->ME == MemoryEffects::unknown() || IntInfo->hasSideEffects) hasSideEffects = true; } } diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.h b/llvm/utils/TableGen/CodeGenDAGPatterns.h index dbdc72f0873a..ec35e6680088 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.h +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.h @@ -50,7 +50,7 @@ using TreePatternNodePtr = std::shared_ptr<TreePatternNode>; /// To reduce the allocations even further, make MachineValueTypeSet own /// the storage and use std::array as the bit container. struct MachineValueTypeSet { - static_assert(std::is_same<std::underlying_type<MVT::SimpleValueType>::type, + static_assert(std::is_same<std::underlying_type_t<MVT::SimpleValueType>, uint8_t>::value, "Change uint8_t here to the SimpleValueType's type"); static unsigned constexpr Capacity = std::numeric_limits<uint8_t>::max()+1; @@ -69,7 +69,7 @@ struct MachineValueTypeSet { unsigned size() const { unsigned Count = 0; for (WordType W : Words) - Count += countPopulation(W); + Count += llvm::popcount(W); return Count; } LLVM_ATTRIBUTE_ALWAYS_INLINE @@ -150,7 +150,7 @@ struct MachineValueTypeSet { WordType W = Set->Words[SkipWords]; W &= maskLeadingOnes<WordType>(WordWidth-SkipBits); if (W != 0) - return Count + findFirstSet(W); + return Count + llvm::countr_zero(W); Count += WordWidth; SkipWords++; } @@ -158,7 +158,7 @@ struct MachineValueTypeSet { for (unsigned i = SkipWords; i != NumWords; ++i) { WordType W = Set->Words[i]; if (W != 0) - return Count + findFirstSet(W); + return Count + llvm::countr_zero(W); Count += WordWidth; } return Capacity; diff --git a/llvm/utils/TableGen/CodeGenInstruction.cpp b/llvm/utils/TableGen/CodeGenInstruction.cpp index ba12633ace8c..238c6a1b6ba8 100644 --- a/llvm/utils/TableGen/CodeGenInstruction.cpp +++ b/llvm/utils/TableGen/CodeGenInstruction.cpp @@ -67,6 +67,10 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { ArgName = InDI->getArgNameStr(i-NumDefs); } + DagInit *SubArgDag = dyn_cast<DagInit>(ArgInit); + if (SubArgDag) + ArgInit = SubArgDag->getOperator(); + DefInit *Arg = dyn_cast<DefInit>(ArgInit); if (!Arg) PrintFatalError(R->getLoc(), "Illegal operand for the '" + R->getName() + @@ -116,10 +120,11 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { } else if (Rec->isSubClassOf("RegisterClass")) { OperandType = "OPERAND_REGISTER"; } else if (!Rec->isSubClassOf("PointerLikeRegClass") && - !Rec->isSubClassOf("unknown_class")) + !Rec->isSubClassOf("unknown_class")) { PrintFatalError(R->getLoc(), "Unknown operand class '" + Rec->getName() + "' in '" + R->getName() + "' instruction!"); + } // Check that the operand has a name and that it's unique. if (ArgName.empty()) @@ -132,20 +137,60 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { Twine(i) + " has the same name as a previous operand!"); - OperandList.emplace_back( + OperandInfo &OpInfo = OperandList.emplace_back( Rec, std::string(ArgName), std::string(PrintMethod), - std::string(EncoderMethod), OperandNamespace + "::" + OperandType, - MIOperandNo, NumOps, MIOpInfo); + OperandNamespace + "::" + OperandType, MIOperandNo, NumOps, MIOpInfo); + + if (SubArgDag) { + if (SubArgDag->getNumArgs() != NumOps) { + PrintFatalError(R->getLoc(), "In instruction '" + R->getName() + + "', operand #" + Twine(i) + " has " + + Twine(SubArgDag->getNumArgs()) + + " sub-arg names, expected " + + Twine(NumOps) + "."); + } + + for (unsigned j = 0; j < NumOps; ++j) { + if (!isa<UnsetInit>(SubArgDag->getArg(j))) + PrintFatalError(R->getLoc(), + "In instruction '" + R->getName() + "', operand #" + + Twine(i) + " sub-arg #" + Twine(j) + + " has unexpected operand (expected only $name)."); + + StringRef SubArgName = SubArgDag->getArgNameStr(j); + if (SubArgName.empty()) + PrintFatalError(R->getLoc(), "In instruction '" + R->getName() + + "', operand #" + Twine(i) + + " has no name!"); + if (!OperandNames.insert(std::string(SubArgName)).second) + PrintFatalError(R->getLoc(), + "In instruction '" + R->getName() + "', operand #" + + Twine(i) + " sub-arg #" + Twine(j) + + " has the same name as a previous operand!"); + + if (auto MaybeEncoderMethod = + cast<DefInit>(MIOpInfo->getArg(j)) + ->getDef() + ->getValueAsOptionalString("EncoderMethod")) { + OpInfo.EncoderMethodNames[j] = *MaybeEncoderMethod; + } + + OpInfo.SubOpNames[j] = SubArgName; + SubOpAliases[SubArgName] = std::make_pair(MIOperandNo, j); + } + } else if (!EncoderMethod.empty()) { + // If we have no explicit sub-op dag, but have an top-level encoder + // method, the single encoder will multiple sub-ops, itself. + OpInfo.EncoderMethodNames[0] = EncoderMethod; + for (unsigned j = 1; j < NumOps; ++j) + OpInfo.DoNotEncode[j] = true; + } + MIOperandNo += NumOps; } if (VariadicOuts) --NumDefs; - - // Make sure the constraints list for each operand is large enough to hold - // constraint info, even if none is present. - for (OperandInfo &OpInfo : OperandList) - OpInfo.Constraints.resize(OpInfo.MINumOperands); } @@ -175,6 +220,17 @@ bool CGIOperandList::hasOperandNamed(StringRef Name, unsigned &OpIdx) const { return false; } +bool CGIOperandList::hasSubOperandAlias( + StringRef Name, std::pair<unsigned, unsigned> &SubOp) const { + assert(!Name.empty() && "Cannot search for operand with no name!"); + auto SubOpIter = SubOpAliases.find(Name); + if (SubOpIter != SubOpAliases.end()) { + SubOp = SubOpIter->second; + return true; + } + return false; +} + std::pair<unsigned,unsigned> CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) { if (Op.empty() || Op[0] != '$') @@ -195,7 +251,21 @@ CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) { OpName = OpName.substr(0, DotIdx); } - unsigned OpIdx = getOperandNamed(OpName); + unsigned OpIdx; + + if (std::pair<unsigned, unsigned> SubOp; hasSubOperandAlias(OpName, SubOp)) { + // Found a name for a piece of an operand, just return it directly. + if (!SubOpName.empty()) { + PrintFatalError( + TheDef->getLoc(), + TheDef->getName() + + ": Cannot use dotted suboperand name within suboperand '" + + OpName + "'"); + } + return SubOp; + } + + OpIdx = getOperandNamed(OpName); if (SubOpName.empty()) { // If no suboperand name was specified: // If one was needed, throw. @@ -350,8 +420,6 @@ void CGIOperandList::ProcessDisableEncoding(StringRef DisableEncoding) { std::pair<unsigned,unsigned> Op = ParseOperandName(OpName, false); // Mark the operand as not-to-be encoded. - if (Op.second >= OperandList[Op.first].DoNotEncode.size()) - OperandList[Op.first].DoNotEncode.resize(Op.second+1); OperandList[Op.first].DoNotEncode[Op.second] = true; } @@ -511,9 +579,9 @@ FlattenAsmStringVariants(StringRef Cur, unsigned Variant) { return Res; } -bool CodeGenInstruction::isOperandImpl(unsigned i, +bool CodeGenInstruction::isOperandImpl(StringRef OpListName, unsigned i, StringRef PropertyName) const { - DagInit *ConstraintList = TheDef->getValueAsDag("InOperandList"); + DagInit *ConstraintList = TheDef->getValueAsDag(OpListName); if (!ConstraintList || i >= ConstraintList->getNumArgs()) return false; diff --git a/llvm/utils/TableGen/CodeGenInstruction.h b/llvm/utils/TableGen/CodeGenInstruction.h index d3de6d95780c..72626caada56 100644 --- a/llvm/utils/TableGen/CodeGenInstruction.h +++ b/llvm/utils/TableGen/CodeGenInstruction.h @@ -14,6 +14,7 @@ #define LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MachineValueType.h" #include <cassert> @@ -83,13 +84,16 @@ template <typename T> class ArrayRef; /// otherwise, it's empty. std::string Name; + /// The names of sub-operands, if given, otherwise empty. + std::vector<std::string> SubOpNames; + /// PrinterMethodName - The method used to print operands of this type in /// the asmprinter. std::string PrinterMethodName; - /// EncoderMethodName - The method used to get the machine operand value - /// for binary encoding. "getMachineOpValue" by default. - std::string EncoderMethodName; + /// The method used to get the machine operand value for binary + /// encoding, per sub-operand. If empty, uses "getMachineOpValue". + std::vector<std::string> EncoderMethodNames; /// OperandType - A value from MCOI::OperandType representing the type of /// the operand. @@ -118,12 +122,12 @@ template <typename T> class ArrayRef; std::vector<ConstraintInfo> Constraints; OperandInfo(Record *R, const std::string &N, const std::string &PMN, - const std::string &EMN, const std::string &OT, unsigned MION, - unsigned MINO, DagInit *MIOI) - : Rec(R), Name(N), PrinterMethodName(PMN), EncoderMethodName(EMN), - OperandType(OT), MIOperandNo(MION), MINumOperands(MINO), - MIOperandInfo(MIOI) {} - + const std::string &OT, unsigned MION, unsigned MINO, + DagInit *MIOI) + : Rec(R), Name(N), SubOpNames(MINO), PrinterMethodName(PMN), + EncoderMethodNames(MINO), OperandType(OT), MIOperandNo(MION), + MINumOperands(MINO), DoNotEncode(MINO), MIOperandInfo(MIOI), + Constraints(MINO) {} /// getTiedOperand - If this operand is tied to another one, return the /// other operand number. Otherwise, return -1. @@ -149,6 +153,9 @@ template <typename T> class ArrayRef; /// type (which is a record). std::vector<OperandInfo> OperandList; + /// SubOpAliases - List of alias names for suboperands. + StringMap<std::pair<unsigned, unsigned>> SubOpAliases; + // Information gleaned from the operand list. bool isPredicable; bool hasOptionalDef; @@ -179,6 +186,9 @@ template <typename T> class ArrayRef; /// operand. Otherwise, return false. bool hasOperandNamed(StringRef Name, unsigned &OpIdx) const; + bool hasSubOperandAlias(StringRef Name, + std::pair<unsigned, unsigned> &SubOp) const; + /// ParseOperandName - Parse an operand name like "$foo" or "$foo.bar", /// where $foo is a whole operand and $foo.bar refers to a suboperand. /// This aborts if the name is invalid. If AllowWholeOp is true, references @@ -313,17 +323,22 @@ template <typename T> class ArrayRef; // This can be used on intructions that use typeN or ptypeN to identify // operands that should be considered as pointers even though SelectionDAG // didn't make a distinction between integer and pointers. - bool isOperandAPointer(unsigned i) const { - return isOperandImpl(i, "IsPointer"); + bool isInOperandAPointer(unsigned i) const { + return isOperandImpl("InOperandList", i, "IsPointer"); + } + + bool isOutOperandAPointer(unsigned i) const { + return isOperandImpl("OutOperandList", i, "IsPointer"); } /// Check if the operand is required to be an immediate. - bool isOperandImmArg(unsigned i) const { - return isOperandImpl(i, "IsImmediate"); + bool isInOperandImmArg(unsigned i) const { + return isOperandImpl("InOperandList", i, "IsImmediate"); } private: - bool isOperandImpl(unsigned i, StringRef PropertyName) const; + bool isOperandImpl(StringRef OpListName, unsigned i, + StringRef PropertyName) const; }; diff --git a/llvm/utils/TableGen/CodeGenIntrinsics.h b/llvm/utils/TableGen/CodeGenIntrinsics.h index 599795e3c065..0558918b3028 100644 --- a/llvm/utils/TableGen/CodeGenIntrinsics.h +++ b/llvm/utils/TableGen/CodeGenIntrinsics.h @@ -14,7 +14,9 @@ #define LLVM_UTILS_TABLEGEN_CODEGENINTRINSICS_H #include "SDNodeProperties.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/MachineValueType.h" +#include "llvm/Support/ModRef.h" #include <string> #include <vector> @@ -57,51 +59,8 @@ struct CodeGenIntrinsic { IntrinsicSignature IS; - /// Bit flags describing the type (ref/mod) and location of memory - /// accesses that may be performed by the intrinsics. Analogous to - /// \c FunctionModRefBehaviour. - enum ModRefBits { - /// The intrinsic may access memory that is otherwise inaccessible via - /// LLVM IR. - MR_InaccessibleMem = 1, - - /// The intrinsic may access memory through pointer arguments. - /// LLVM IR. - MR_ArgMem = 2, - - /// The intrinsic may access memory anywhere, i.e. it is not restricted - /// to access through pointer arguments. - MR_Anywhere = 4 | MR_ArgMem | MR_InaccessibleMem, - - /// The intrinsic may read memory. - MR_Ref = 8, - - /// The intrinsic may write memory. - MR_Mod = 16, - - /// The intrinsic may both read and write memory. - MR_ModRef = MR_Ref | MR_Mod, - }; - - /// Memory mod/ref behavior of this intrinsic, corresponding to intrinsic - /// properties (IntrReadMem, IntrArgMemOnly, etc.). - enum ModRefBehavior { - NoMem = 0, - ReadArgMem = MR_Ref | MR_ArgMem, - ReadInaccessibleMem = MR_Ref | MR_InaccessibleMem, - ReadInaccessibleMemOrArgMem = MR_Ref | MR_ArgMem | MR_InaccessibleMem, - ReadMem = MR_Ref | MR_Anywhere, - WriteArgMem = MR_Mod | MR_ArgMem, - WriteInaccessibleMem = MR_Mod | MR_InaccessibleMem, - WriteInaccessibleMemOrArgMem = MR_Mod | MR_ArgMem | MR_InaccessibleMem, - WriteMem = MR_Mod | MR_Anywhere, - ReadWriteArgMem = MR_ModRef | MR_ArgMem, - ReadWriteInaccessibleMem = MR_ModRef | MR_InaccessibleMem, - ReadWriteInaccessibleMemOrArgMem = MR_ModRef | MR_ArgMem | - MR_InaccessibleMem, - ReadWriteMem = MR_ModRef | MR_Anywhere, - }; - ModRefBehavior ModRef; + /// Memory effects of the intrinsic. + MemoryEffects ME = MemoryEffects::unknown(); /// SDPatternOperator Properties applied to the intrinsic. unsigned Properties; @@ -154,6 +113,7 @@ struct CodeGenIntrinsic { NoCapture, NoAlias, NoUndef, + NonNull, Returned, ReadOnly, WriteOnly, @@ -163,20 +123,20 @@ struct CodeGenIntrinsic { }; struct ArgAttribute { - unsigned Index; ArgAttrKind Kind; uint64_t Value; - ArgAttribute(unsigned Idx, ArgAttrKind K, uint64_t V) - : Index(Idx), Kind(K), Value(V) {} + ArgAttribute(ArgAttrKind K, uint64_t V) : Kind(K), Value(V) {} bool operator<(const ArgAttribute &Other) const { - return std::tie(Index, Kind, Value) < - std::tie(Other.Index, Other.Kind, Other.Value); + return std::tie(Kind, Value) < std::tie(Other.Kind, Other.Value); } }; - std::vector<ArgAttribute> ArgumentAttributes; + /// Vector of attributes for each argument. + SmallVector<SmallVector<ArgAttribute, 0>> ArgumentAttributes; + + void addArgAttribute(unsigned Idx, ArgAttrKind AK, uint64_t V = 0); bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); @@ -217,6 +177,8 @@ public: bool empty() const { return Intrinsics.empty(); } size_t size() const { return Intrinsics.size(); } + auto begin() const { return Intrinsics.begin(); } + auto end() const { return Intrinsics.end(); } CodeGenIntrinsic &operator[](size_t Pos) { return Intrinsics[Pos]; } const CodeGenIntrinsic &operator[](size_t Pos) const { return Intrinsics[Pos]; diff --git a/llvm/utils/TableGen/CodeGenRegisters.cpp b/llvm/utils/TableGen/CodeGenRegisters.cpp index 93ed86cfb7e5..8ad8a7a5bc9b 100644 --- a/llvm/utils/TableGen/CodeGenRegisters.cpp +++ b/llvm/utils/TableGen/CodeGenRegisters.cpp @@ -154,8 +154,8 @@ CodeGenRegister::CodeGenRegister(Record *R, unsigned Enum) : TheDef(R), EnumValue(Enum), CostPerUse(R->getValueAsListOfInts("CostPerUse")), CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")), - HasDisjunctSubRegs(false), SubRegsComplete(false), - SuperRegsComplete(false), TopoSig(~0u) { + HasDisjunctSubRegs(false), Constant(R->getValueAsBit("isConstant")), + SubRegsComplete(false), SuperRegsComplete(false), TopoSig(~0u) { Artificial = R->getValueAsBit("isArtificial"); } @@ -803,10 +803,12 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) Allocatable = R->getValueAsBit("isAllocatable"); AltOrderSelect = R->getValueAsString("AltOrderSelect"); int AllocationPriority = R->getValueAsInt("AllocationPriority"); - if (AllocationPriority < 0 || AllocationPriority > 63) - PrintFatalError(R->getLoc(), "AllocationPriority out of range [0,63]"); + if (!isUInt<5>(AllocationPriority)) + PrintFatalError(R->getLoc(), "AllocationPriority out of range [0,31]"); this->AllocationPriority = AllocationPriority; + GlobalPriority = R->getValueAsBit("GlobalPriority"); + BitsInit *TSF = R->getValueAsBitsInit("TSFlags"); for (unsigned I = 0, E = TSF->getNumBits(); I != E; ++I) { BitInit *Bit = cast<BitInit>(TSF->getBit(I)); @@ -821,7 +823,8 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, StringRef Name, Key Props) : Members(*Props.Members), TheDef(nullptr), Name(std::string(Name)), TopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1), RSI(Props.RSI), - CopyCost(0), Allocatable(true), AllocationPriority(0), TSFlags(0) { + CopyCost(0), Allocatable(true), AllocationPriority(0), + GlobalPriority(false), TSFlags(0) { Artificial = true; GeneratePressureSet = false; for (const auto R : Members) { @@ -849,6 +852,7 @@ void CodeGenRegisterClass::inheritProperties(CodeGenRegBank &RegBank) { }); AltOrderSelect = Super.AltOrderSelect; AllocationPriority = Super.AllocationPriority; + GlobalPriority = Super.GlobalPriority; TSFlags = Super.TSFlags; GeneratePressureSet |= Super.GeneratePressureSet; @@ -1020,7 +1024,7 @@ void CodeGenRegisterClass::computeSubClasses(CodeGenRegBank &RegBank) { RC.inheritProperties(RegBank); } -Optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>> +std::optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>> CodeGenRegisterClass::getMatchingSubClassWithSubRegs( CodeGenRegBank &RegBank, const CodeGenSubRegIndex *SubIdx) const { auto SizeOrder = [this](const CodeGenRegisterClass *A, @@ -1040,7 +1044,7 @@ CodeGenRegisterClass::getMatchingSubClassWithSubRegs( // index and order them by size. BiggestSuperRC should always be first. CodeGenRegisterClass *BiggestSuperRegRC = getSubClassWithSubReg(SubIdx); if (!BiggestSuperRegRC) - return None; + return std::nullopt; BitVector SuperRegRCsBV = BiggestSuperRegRC->getSubClasses(); std::vector<CodeGenRegisterClass *> SuperRegRCs; for (auto &RC : RegClasses) @@ -1103,7 +1107,7 @@ CodeGenRegisterClass::getMatchingSubClassWithSubRegs( return std::make_pair(ChosenSuperRegClass, SubRegRC); } - return None; + return std::nullopt; } void CodeGenRegisterClass::getSuperRegClasses(const CodeGenSubRegIndex *SubIdx, @@ -1365,11 +1369,15 @@ getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex *, 8> &Parts) { unsigned Size = Parts.front()->Size; unsigned LastOffset = Parts.front()->Offset; unsigned LastSize = Parts.front()->Size; + unsigned UnknownSize = (uint16_t)-1; for (unsigned i = 1, e = Parts.size(); i != e; ++i) { Name += '_'; Name += Parts[i]->getName(); - Size += Parts[i]->Size; - if (Parts[i]->Offset != (LastOffset + LastSize)) + if (Size == UnknownSize || Parts[i]->Size == UnknownSize) + Size = UnknownSize; + else + Size += Parts[i]->Size; + if (LastSize == UnknownSize || Parts[i]->Offset != (LastOffset + LastSize)) isContinuous = false; LastOffset = Parts[i]->Offset; LastSize = Parts[i]->Size; diff --git a/llvm/utils/TableGen/CodeGenRegisters.h b/llvm/utils/TableGen/CodeGenRegisters.h index e5e92fc81f50..765425ed68cb 100644 --- a/llvm/utils/TableGen/CodeGenRegisters.h +++ b/llvm/utils/TableGen/CodeGenRegisters.h @@ -154,6 +154,7 @@ namespace llvm { bool CoveredBySubRegs; bool HasDisjunctSubRegs; bool Artificial; + bool Constant; // Map SubRegIndex -> Register. typedef std::map<CodeGenSubRegIndex *, CodeGenRegister *, @@ -233,7 +234,7 @@ namespace llvm { const RegUnitList &getRegUnits() const { return RegUnits; } ArrayRef<LaneBitmask> getRegUnitLaneMasks() const { - return makeArrayRef(RegUnitLaneMasks).slice(0, NativeRegUnits.count()); + return ArrayRef(RegUnitLaneMasks).slice(0, NativeRegUnits.count()); } // Get the native register units. This is a prefix of getRegUnits(). @@ -331,6 +332,7 @@ namespace llvm { bool Allocatable; StringRef AltOrderSelect; uint8_t AllocationPriority; + bool GlobalPriority; uint8_t TSFlags; /// Contains the combination of the lane masks of all subregisters. LaneBitmask LaneMask; @@ -390,7 +392,7 @@ namespace llvm { /// \return std::pair<SubClass, SubRegClass> where SubClass is a SubClass is /// a class where every register has SubIdx and SubRegClass is a class where /// every register is covered by the SubIdx subregister of SubClass. - Optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>> + std::optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>> getMatchingSubClassWithSubRegs(CodeGenRegBank &RegBank, const CodeGenSubRegIndex *SubIdx) const; @@ -470,6 +472,13 @@ namespace llvm { // Called by CodeGenRegBank::CodeGenRegBank(). static void computeSubClasses(CodeGenRegBank&); + + // Get ordering value among register base classes. + std::optional<int> getBaseClassOrder() const { + if (TheDef && !TheDef->isValueUnset("BaseClassOrder")) + return TheDef->getValueAsInt("BaseClassOrder"); + return {}; + } }; // Register categories are used when we need to deterine the category a @@ -522,7 +531,7 @@ namespace llvm { ArrayRef<const CodeGenRegister*> getRoots() const { assert(!(Roots[1] && !Roots[0]) && "Invalid roots array"); - return makeArrayRef(Roots, !!Roots[0] + !!Roots[1]); + return ArrayRef(Roots, !!Roots[0] + !!Roots[1]); } }; diff --git a/llvm/utils/TableGen/CodeGenSchedule.cpp b/llvm/utils/TableGen/CodeGenSchedule.cpp index 4933bfc476f4..441a088c1731 100644 --- a/llvm/utils/TableGen/CodeGenSchedule.cpp +++ b/llvm/utils/TableGen/CodeGenSchedule.cpp @@ -100,7 +100,7 @@ struct InstRegexOp : public SetTheory::Operator { if (removeParens(Original).find_first_of("|?") != std::string::npos) FirstMeta = 0; - Optional<Regex> Regexpr = None; + std::optional<Regex> Regexpr; StringRef Prefix = Original.substr(0, FirstMeta); StringRef PatStr = Original.substr(FirstMeta); if (!PatStr.empty()) { @@ -492,7 +492,7 @@ void CodeGenSchedModels::collectLoadStoreQueueInfo() { if (PM.StoreQueue) { PrintError(Queue->getLoc(), "Expected a single StoreQueue definition"); - PrintNote(PM.LoadQueue->getLoc(), + PrintNote(PM.StoreQueue->getLoc(), "Previous definition of StoreQueue was here"); } @@ -734,14 +734,12 @@ unsigned CodeGenSchedModels::getSchedRWIdx(const Record *Def, } bool CodeGenSchedModels::hasReadOfWrite(Record *WriteDef) const { - for (const CodeGenSchedRW &Read : SchedReads) { - Record *ReadDef = Read.TheDef; - if (!ReadDef || !ReadDef->isSubClassOf("ProcReadAdvance")) - continue; - - RecVec ValidWrites = ReadDef->getValueAsListOfDefs("ValidWrites"); - if (is_contained(ValidWrites, WriteDef)) { - return true; + for (auto& ProcModel : ProcModels) { + const RecVec &RADefs = ProcModel.ReadAdvanceDefs; + for (auto& RADef : RADefs) { + RecVec ValidWrites = RADef->getValueAsListOfDefs("ValidWrites"); + if (is_contained(ValidWrites, WriteDef)) + return true; } } return false; @@ -840,7 +838,7 @@ unsigned CodeGenSchedModels::findRWForSequence(ArrayRef<unsigned> Seq, std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; auto I = find_if(RWVec, [Seq](CodeGenSchedRW &RW) { - return makeArrayRef(RW.Sequence) == Seq; + return ArrayRef(RW.Sequence) == Seq; }); // Index zero reserved for invalid RW. return I == RWVec.end() ? 0 : std::distance(RWVec.begin(), I); diff --git a/llvm/utils/TableGen/CodeGenSchedule.h b/llvm/utils/TableGen/CodeGenSchedule.h index f7e35b0c808f..bbf5381ad086 100644 --- a/llvm/utils/TableGen/CodeGenSchedule.h +++ b/llvm/utils/TableGen/CodeGenSchedule.h @@ -145,8 +145,7 @@ struct CodeGenSchedClass { bool isKeyEqual(Record *IC, ArrayRef<unsigned> W, ArrayRef<unsigned> R) const { - return ItinClassDef == IC && makeArrayRef(Writes) == W && - makeArrayRef(Reads) == R; + return ItinClassDef == IC && ArrayRef(Writes) == W && ArrayRef(Reads) == R; } // Is this class generated from a variants if existing classes? Instructions diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp index af2e8576af2e..b7240f01300c 100644 --- a/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/CodeGenTarget.cpp @@ -91,8 +91,11 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v256i1: return "MVT::v256i1"; case MVT::v512i1: return "MVT::v512i1"; case MVT::v1024i1: return "MVT::v1024i1"; + case MVT::v2048i1: return "MVT::v2048i1"; case MVT::v128i2: return "MVT::v128i2"; + case MVT::v256i2: return "MVT::v256i2"; case MVT::v64i4: return "MVT::v64i4"; + case MVT::v128i4: return "MVT::v128i4"; case MVT::v1i8: return "MVT::v1i8"; case MVT::v2i8: return "MVT::v2i8"; case MVT::v4i8: return "MVT::v4i8"; @@ -123,6 +126,10 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v6i32: return "MVT::v6i32"; case MVT::v7i32: return "MVT::v7i32"; case MVT::v8i32: return "MVT::v8i32"; + case MVT::v9i32: return "MVT::v9i32"; + case MVT::v10i32: return "MVT::v10i32"; + case MVT::v11i32: return "MVT::v11i32"; + case MVT::v12i32: return "MVT::v12i32"; case MVT::v16i32: return "MVT::v16i32"; case MVT::v32i32: return "MVT::v32i32"; case MVT::v64i32: return "MVT::v64i32"; @@ -169,6 +176,10 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v6f32: return "MVT::v6f32"; case MVT::v7f32: return "MVT::v7f32"; case MVT::v8f32: return "MVT::v8f32"; + case MVT::v9f32: return "MVT::v9f32"; + case MVT::v10f32: return "MVT::v10f32"; + case MVT::v11f32: return "MVT::v11f32"; + case MVT::v12f32: return "MVT::v12f32"; case MVT::v16f32: return "MVT::v16f32"; case MVT::v32f32: return "MVT::v32f32"; case MVT::v64f32: return "MVT::v64f32"; @@ -358,11 +369,9 @@ CodeGenRegBank &CodeGenTarget::getRegBank() const { return *RegBank; } -Optional<CodeGenRegisterClass *> -CodeGenTarget::getSuperRegForSubReg(const ValueTypeByHwMode &ValueTy, - CodeGenRegBank &RegBank, - const CodeGenSubRegIndex *SubIdx, - bool MustBeAllocatable) const { +std::optional<CodeGenRegisterClass *> CodeGenTarget::getSuperRegForSubReg( + const ValueTypeByHwMode &ValueTy, CodeGenRegBank &RegBank, + const CodeGenSubRegIndex *SubIdx, bool MustBeAllocatable) const { std::vector<CodeGenRegisterClass *> Candidates; auto &RegClasses = RegBank.getRegClasses(); @@ -389,7 +398,7 @@ CodeGenTarget::getSuperRegForSubReg(const ValueTypeByHwMode &ValueTy, // If we didn't find anything, we're done. if (Candidates.empty()) - return None; + return std::nullopt; // Find and return the largest of our candidate classes. llvm::stable_sort(Candidates, [&](const CodeGenRegisterClass *A, @@ -482,7 +491,7 @@ static const char *FixedInstrs[] = { nullptr}; unsigned CodeGenTarget::getNumFixedInstructions() { - return array_lengthof(FixedInstrs) - 1; + return std::size(FixedInstrs) - 1; } /// Return all of the instructions defined by the target, ordered by @@ -665,7 +674,6 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R, TheDef = R; std::string DefName = std::string(R->getName()); ArrayRef<SMLoc> DefLoc = R->getLoc(); - ModRef = ReadWriteMem; Properties = 0; isOverloaded = false; isCommutative = false; @@ -823,7 +831,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R, Properties = parseSDPatternOperatorProperties(R); // Sort the argument attributes for later benefit. - llvm::sort(ArgumentAttributes); + for (auto &Attrs : ArgumentAttributes) + llvm::sort(Attrs); } void CodeGenIntrinsic::setDefaultProperties( @@ -838,26 +847,25 @@ void CodeGenIntrinsic::setDefaultProperties( void CodeGenIntrinsic::setProperty(Record *R) { if (R->getName() == "IntrNoMem") - ModRef = NoMem; + ME = MemoryEffects::none(); else if (R->getName() == "IntrReadMem") { - if (!(ModRef & MR_Ref)) + if (ME.onlyWritesMemory()) PrintFatalError(TheDef->getLoc(), Twine("IntrReadMem cannot be used after IntrNoMem or " "IntrWriteMem. Default is ReadWrite")); - ModRef = ModRefBehavior(ModRef & ~MR_Mod); + ME &= MemoryEffects::readOnly(); } else if (R->getName() == "IntrWriteMem") { - if (!(ModRef & MR_Mod)) + if (ME.onlyReadsMemory()) PrintFatalError(TheDef->getLoc(), Twine("IntrWriteMem cannot be used after IntrNoMem or " "IntrReadMem. Default is ReadWrite")); - ModRef = ModRefBehavior(ModRef & ~MR_Ref); + ME &= MemoryEffects::writeOnly(); } else if (R->getName() == "IntrArgMemOnly") - ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_ArgMem); + ME &= MemoryEffects::argMemOnly(); else if (R->getName() == "IntrInaccessibleMemOnly") - ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_InaccessibleMem); + ME &= MemoryEffects::inaccessibleMemOnly(); else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly") - ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_ArgMem | - MR_InaccessibleMem); + ME &= MemoryEffects::inaccessibleOrArgMemOnly(); else if (R->getName() == "Commutative") isCommutative = true; else if (R->getName() == "Throws") @@ -886,32 +894,35 @@ void CodeGenIntrinsic::setProperty(Record *R) { hasSideEffects = true; else if (R->isSubClassOf("NoCapture")) { unsigned ArgNo = R->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, NoCapture, 0); + addArgAttribute(ArgNo, NoCapture); } else if (R->isSubClassOf("NoAlias")) { unsigned ArgNo = R->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, NoAlias, 0); + addArgAttribute(ArgNo, NoAlias); } else if (R->isSubClassOf("NoUndef")) { unsigned ArgNo = R->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, NoUndef, 0); + addArgAttribute(ArgNo, NoUndef); + } else if (R->isSubClassOf("NonNull")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + addArgAttribute(ArgNo, NonNull); } else if (R->isSubClassOf("Returned")) { unsigned ArgNo = R->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, Returned, 0); + addArgAttribute(ArgNo, Returned); } else if (R->isSubClassOf("ReadOnly")) { unsigned ArgNo = R->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, ReadOnly, 0); + addArgAttribute(ArgNo, ReadOnly); } else if (R->isSubClassOf("WriteOnly")) { unsigned ArgNo = R->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, WriteOnly, 0); + addArgAttribute(ArgNo, WriteOnly); } else if (R->isSubClassOf("ReadNone")) { unsigned ArgNo = R->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, ReadNone, 0); + addArgAttribute(ArgNo, ReadNone); } else if (R->isSubClassOf("ImmArg")) { unsigned ArgNo = R->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, ImmArg, 0); + addArgAttribute(ArgNo, ImmArg); } else if (R->isSubClassOf("Align")) { unsigned ArgNo = R->getValueAsInt("ArgNo"); uint64_t Align = R->getValueAsInt("Align"); - ArgumentAttributes.emplace_back(ArgNo, Alignment, Align); + addArgAttribute(ArgNo, Alignment, Align); } else llvm_unreachable("Unknown property!"); } @@ -925,7 +936,17 @@ bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const { bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const { // Convert argument index to attribute index starting from `FirstArgIndex`. - ArgAttribute Val{ParamIdx + 1, ImmArg, 0}; - return std::binary_search(ArgumentAttributes.begin(), - ArgumentAttributes.end(), Val); + ++ParamIdx; + if (ParamIdx >= ArgumentAttributes.size()) + return false; + ArgAttribute Val{ImmArg, 0}; + return std::binary_search(ArgumentAttributes[ParamIdx].begin(), + ArgumentAttributes[ParamIdx].end(), Val); +} + +void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK, + uint64_t V) { + if (Idx >= ArgumentAttributes.size()) + ArgumentAttributes.resize(Idx + 1); + ArgumentAttributes[Idx].emplace_back(AK, V); } diff --git a/llvm/utils/TableGen/CodeGenTarget.h b/llvm/utils/TableGen/CodeGenTarget.h index f14828f2c347..6846e6b5c77a 100644 --- a/llvm/utils/TableGen/CodeGenTarget.h +++ b/llvm/utils/TableGen/CodeGenTarget.h @@ -108,7 +108,7 @@ public: /// Return the largest register class on \p RegBank which supports \p Ty and /// covers \p SubIdx if it exists. - Optional<CodeGenRegisterClass *> + std::optional<CodeGenRegisterClass *> getSuperRegForSubReg(const ValueTypeByHwMode &Ty, CodeGenRegBank &RegBank, const CodeGenSubRegIndex *SubIdx, bool MustBeAllocatable = false) const; diff --git a/llvm/utils/TableGen/CompressInstEmitter.cpp b/llvm/utils/TableGen/CompressInstEmitter.cpp index 1fd85939e74e..a18d6a6b8854 100644 --- a/llvm/utils/TableGen/CompressInstEmitter.cpp +++ b/llvm/utils/TableGen/CompressInstEmitter.cpp @@ -45,20 +45,16 @@ // instructions, plus some helper functions: // // bool compressInst(MCInst &OutInst, const MCInst &MI, -// const MCSubtargetInfo &STI, -// MCContext &Context); +// const MCSubtargetInfo &STI); // // bool uncompressInst(MCInst &OutInst, const MCInst &MI, -// const MCRegisterInfo &MRI, // const MCSubtargetInfo &STI); // // In addition, it exports a function for checking whether // an instruction is compressable: // // bool isCompressibleInst(const MachineInstr& MI, -// const <TargetName>Subtarget *Subtarget, -// const MCRegisterInfo &MRI, -// const MCSubtargetInfo &STI); +// const <TargetName>Subtarget &STI); // // The clients that include this auto-generated header file and // invoke these functions can compress an instruction before emitting @@ -595,7 +591,6 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, std::string FH; raw_string_ostream Func(F); raw_string_ostream FuncH(FH); - bool NeedMRI = false; if (EType == EmitterType::Compress) o << "\n#ifdef GEN_COMPRESS_INSTR\n" @@ -610,18 +605,14 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, if (EType == EmitterType::Compress) { FuncH << "static bool compressInst(MCInst &OutInst,\n"; FuncH.indent(25) << "const MCInst &MI,\n"; - FuncH.indent(25) << "const MCSubtargetInfo &STI,\n"; - FuncH.indent(25) << "MCContext &Context) {\n"; + FuncH.indent(25) << "const MCSubtargetInfo &STI) {\n"; } else if (EType == EmitterType::Uncompress) { FuncH << "static bool uncompressInst(MCInst &OutInst,\n"; FuncH.indent(27) << "const MCInst &MI,\n"; - FuncH.indent(27) << "const MCRegisterInfo &MRI,\n"; FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n"; } else if (EType == EmitterType::CheckCompress) { FuncH << "static bool isCompressibleInst(const MachineInstr &MI,\n"; - FuncH.indent(27) << "const " << TargetName << "Subtarget *Subtarget,\n"; - FuncH.indent(27) << "const MCRegisterInfo &MRI,\n"; - FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n"; + FuncH.indent(31) << "const " << TargetName << "Subtarget &STI) {\n"; } if (CompressPatterns.empty()) { @@ -647,6 +638,12 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, EType == EmitterType::Compress || EType == EmitterType::CheckCompress; bool CompressOrUncompress = EType == EmitterType::Compress || EType == EmitterType::Uncompress; + std::string ValidatorName = + CompressOrUncompress + ? (TargetName + "ValidateMCOperandFor" + + (EType == EmitterType::Compress ? "Compress" : "Uncompress")) + .str() + : ""; for (auto &CompressPat : CompressPatterns) { if (EType == EmitterType::Uncompress && CompressPat.IsCompressOnly) @@ -716,7 +713,10 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, if (SourceOperandMap[OpNo].TiedOpIdx != -1) { if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass")) CondStream.indent(6) - << "(MI.getOperand(" << OpNo << ").getReg() == MI.getOperand(" + << "(MI.getOperand(" << OpNo << ").isReg()) && (MI.getOperand(" + << SourceOperandMap[OpNo].TiedOpIdx << ").isReg()) &&\n" + << " (MI.getOperand(" << OpNo + << ").getReg() == MI.getOperand(" << SourceOperandMap[OpNo].TiedOpIdx << ").getReg()) &&\n"; else PrintFatalError("Unexpected tied operand types!\n"); @@ -735,7 +735,8 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, case OpData::Reg: { Record *Reg = SourceOperandMap[OpNo].Data.Reg; CondStream.indent(6) - << "(MI.getOperand(" << OpNo << ").getReg() == " << TargetName + << "(MI.getOperand(" << OpNo << ").isReg()) &&\n" + << " (MI.getOperand(" << OpNo << ").getReg() == " << TargetName << "::" << Reg->getName() << ") &&\n"; break; } @@ -753,16 +754,21 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, unsigned OpIdx = DestOperandMap[OpNo].Data.Operand; // Check that the operand in the Source instruction fits // the type for the Dest instruction. - if (DestOperand.Rec->isSubClassOf("RegisterClass")) { - NeedMRI = true; + if (DestOperand.Rec->isSubClassOf("RegisterClass") || + DestOperand.Rec->isSubClassOf("RegisterOperand")) { + auto *ClassRec = DestOperand.Rec->isSubClassOf("RegisterClass") + ? DestOperand.Rec + : DestOperand.Rec->getValueAsDef("RegClass"); // This is a register operand. Check the register class. // Don't check register class if this is a tied operand, it was done // for the operand its tied to. if (DestOperand.getTiedRegister() == -1) - CondStream.indent(6) << "(MRI.getRegClass(" << TargetName - << "::" << DestOperand.Rec->getName() - << "RegClassID).contains(MI.getOperand(" - << OpIdx << ").getReg())) &&\n"; + CondStream.indent(6) + << "(MI.getOperand(" << OpIdx << ").isReg()) &&\n" + << " (" << TargetName << "MCRegisterClasses[" + << TargetName << "::" << ClassRec->getName() + << "RegClassID].contains(MI.getOperand(" << OpIdx + << ").getReg())) &&\n"; if (CompressOrUncompress) CodeStream.indent(6) @@ -774,7 +780,7 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, getPredicates(MCOpPredicateMap, MCOpPredicates, DestOperand.Rec, "MCOperandPredicate"); CondStream.indent(6) - << TargetName << "ValidateMCOperand(" + << ValidatorName << "(" << "MI.getOperand(" << OpIdx << "), STI, " << Entry << ") &&\n"; } else { unsigned Entry = @@ -784,7 +790,7 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, << "MI.getOperand(" << OpIdx << ").isImm() &&\n"; CondStream.indent(6) << TargetName << "ValidateMachineOperand(" << "MI.getOperand(" << OpIdx - << "), Subtarget, " << Entry << ") &&\n"; + << "), &STI, " << Entry << ") &&\n"; } if (CompressOrUncompress) CodeStream.indent(6) @@ -797,7 +803,7 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, unsigned Entry = getPredicates(MCOpPredicateMap, MCOpPredicates, DestOperand.Rec, "MCOperandPredicate"); CondStream.indent(6) - << TargetName << "ValidateMCOperand(" + << ValidatorName << "(" << "MCOperand::createImm(" << DestOperandMap[OpNo].Data.Imm << "), STI, " << Entry << ") &&\n"; } else { @@ -806,7 +812,7 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, CondStream.indent(6) << TargetName << "ValidateMachineOperand(MachineOperand::CreateImm(" - << DestOperandMap[OpNo].Data.Imm << "), SubTarget, " << Entry + << DestOperandMap[OpNo].Data.Imm << "), &STI, " << Entry << ") &&\n"; } if (CompressOrUncompress) @@ -837,8 +843,7 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, Func.indent(2) << "return false;\n}\n"; if (!MCOpPredicates.empty()) { - o << "static bool " << TargetName - << "ValidateMCOperand(const MCOperand &MCOp,\n" + o << "static bool " << ValidatorName << "(const MCOperand &MCOp,\n" << " const MCSubtargetInfo &STI,\n" << " unsigned PredicateIndex) {\n" << " switch (PredicateIndex) {\n" @@ -870,8 +875,6 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, } o << FuncH.str(); - if (NeedMRI && EType == EmitterType::Compress) - o.indent(2) << "const MCRegisterInfo &MRI = *Context.getRegisterInfo();\n"; o << Func.str(); if (EType == EmitterType::Compress) diff --git a/llvm/utils/TableGen/DFAEmitter.cpp b/llvm/utils/TableGen/DFAEmitter.cpp index f2d9165c5c8c..705908226fa1 100644 --- a/llvm/utils/TableGen/DFAEmitter.cpp +++ b/llvm/utils/TableGen/DFAEmitter.cpp @@ -35,6 +35,7 @@ #include <map> #include <set> #include <string> +#include <variant> #include <vector> #define DEBUG_TYPE "dfa-emitter" @@ -169,30 +170,8 @@ void DfaEmitter::printActionValue(action_type A, raw_ostream &OS) { OS << A; } //===----------------------------------------------------------------------===// namespace { -// FIXME: This entire discriminated union could be removed with c++17: -// using Action = std::variant<Record *, unsigned, std::string>; -struct Action { - Record *R = nullptr; - unsigned I = 0; - std::string S; - - Action() = default; - Action(Record *R, unsigned I, std::string S) : R(R), I(I), S(S) {} - - void print(raw_ostream &OS) const { - if (R) - OS << R->getName(); - else if (!S.empty()) - OS << '"' << S << '"'; - else - OS << I; - } - bool operator<(const Action &Other) const { - return std::make_tuple(R, I, S) < - std::make_tuple(Other.R, Other.I, Other.S); - } -}; +using Action = std::variant<Record *, unsigned, std::string>; using ActionTuple = std::vector<Action>; class Automaton; @@ -342,13 +321,13 @@ Transition::Transition(Record *R, Automaton *Parent) { for (StringRef A : Parent->getActionSymbolFields()) { RecordVal *SymbolV = R->getValue(A); if (auto *Ty = dyn_cast<RecordRecTy>(SymbolV->getType())) { - Actions.emplace_back(R->getValueAsDef(A), 0, ""); + Actions.emplace_back(R->getValueAsDef(A)); Types.emplace_back(Ty->getAsString()); } else if (isa<IntRecTy>(SymbolV->getType())) { - Actions.emplace_back(nullptr, R->getValueAsInt(A), ""); + Actions.emplace_back(static_cast<unsigned>(R->getValueAsInt(A))); Types.emplace_back("unsigned"); } else if (isa<StringRecTy>(SymbolV->getType())) { - Actions.emplace_back(nullptr, 0, std::string(R->getValueAsString(A))); + Actions.emplace_back(std::string(R->getValueAsString(A))); Types.emplace_back("std::string"); } else { report_fatal_error("Unhandled symbol type!"); @@ -380,7 +359,12 @@ void CustomDfaEmitter::printActionValue(action_type A, raw_ostream &OS) { ListSeparator LS; for (const auto &SingleAction : AT) { OS << LS; - SingleAction.print(OS); + if (const auto *R = std::get_if<Record *>(&SingleAction)) + OS << (*R)->getName(); + else if (const auto *S = std::get_if<std::string>(&SingleAction)) + OS << '"' << *S << '"'; + else + OS << std::get<unsigned>(SingleAction); } if (AT.size() > 1) OS << ")"; diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp index cd41fbaa6ca1..44c1df3e9ac4 100644 --- a/llvm/utils/TableGen/DXILEmitter.cpp +++ b/llvm/utils/TableGen/DXILEmitter.cpp @@ -21,7 +21,7 @@ #include "llvm/TableGen/Record.h" using namespace llvm; -using namespace llvm::DXIL; +using namespace llvm::dxil; namespace { @@ -144,7 +144,7 @@ static std::string parameterKindToString(ParameterKind Kind) { case ParameterKind::DXIL_HANDLE: return "DXIL_HANDLE"; } - llvm_unreachable("Unknown llvm::DXIL::ParameterKind enum"); + llvm_unreachable("Unknown llvm::dxil::ParameterKind enum"); } static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) { @@ -238,14 +238,14 @@ static void emitDXILIntrinsicMap(std::vector<DXILOperationData> &DXILOps, raw_ostream &OS) { OS << "\n"; // FIXME: use array instead of SmallDenseMap. - OS << "static const SmallDenseMap<Intrinsic::ID, DXIL::OpCode> LowerMap = " + OS << "static const SmallDenseMap<Intrinsic::ID, dxil::OpCode> LowerMap = " "{\n"; for (auto &DXILOp : DXILOps) { if (DXILOp.Intrinsic.empty()) continue; - // {Intrinsic::sin, DXIL::OpCode::Sin}, + // {Intrinsic::sin, dxil::OpCode::Sin}, OS << " { Intrinsic::" << DXILOp.Intrinsic - << ", DXIL::OpCode::" << DXILOp.DXILOp << "},\n"; + << ", dxil::OpCode::" << DXILOp.DXILOp << "},\n"; } OS << "};\n"; OS << "\n"; @@ -340,16 +340,16 @@ static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps, Parameters.layout(); // Emit the DXIL operation table. - //{DXIL::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary, + //{dxil::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary, // OpCodeClassNameIndex, // OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone, 0, // 3, ParameterTableOffset}, - OS << "static const OpCodeProperty *getOpCodeProperty(DXIL::OpCode DXILOp) " + OS << "static const OpCodeProperty *getOpCodeProperty(dxil::OpCode DXILOp) " "{\n"; OS << " static const OpCodeProperty OpCodeProps[] = {\n"; for (auto &DXILOp : DXILOps) { - OS << " { DXIL::OpCode::" << DXILOp.DXILOp << ", " + OS << " { dxil::OpCode::" << DXILOp.DXILOp << ", " << OpStrings.get(DXILOp.DXILOp.str()) << ", OpCodeClass::" << DXILOp.DXILClass << ", " << OpClassStrings.get(getDXILOpClassName(DXILOp.DXILClass)) << ", " @@ -375,7 +375,7 @@ static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps, OS << "}\n\n"; // Emit the string tables. - OS << "static const char *getOpCodeName(DXIL::OpCode DXILOp) {\n\n"; + OS << "static const char *getOpCodeName(dxil::OpCode DXILOp) {\n\n"; OpStrings.emitStringLiteralDef(OS, " static const char DXILOpCodeNameTable[]"); 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 diff --git a/llvm/utils/TableGen/DisassemblerEmitter.cpp b/llvm/utils/TableGen/DisassemblerEmitter.cpp index 297d12c5d0e9..dfa4b30ee569 100644 --- a/llvm/utils/TableGen/DisassemblerEmitter.cpp +++ b/llvm/utils/TableGen/DisassemblerEmitter.cpp @@ -96,10 +96,7 @@ using namespace llvm::X86Disassembler; namespace llvm { extern 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); + const std::string &PredicateNamespace); void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { CodeGenTarget Target(Records); @@ -132,23 +129,10 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { return; } - // ARM and Thumb have a CHECK() macro to deal with DecodeStatuses. - if (Target.getName() == "ARM" || Target.getName() == "Thumb" || - Target.getName() == "AArch64" || Target.getName() == "ARM64") { - std::string PredicateNamespace = std::string(Target.getName()); - if (PredicateNamespace == "Thumb") - PredicateNamespace = "ARM"; - - EmitDecoder(Records, OS, PredicateNamespace, "if (!Check(S, ", "))", "S", - "MCDisassembler::Fail", - " MCDisassembler::DecodeStatus S = " - "MCDisassembler::Success;\n(void)S;"); - return; - } - - EmitDecoder(Records, OS, std::string(Target.getName()), "if (", - " == MCDisassembler::Fail)", "MCDisassembler::Success", - "MCDisassembler::Fail", ""); + std::string PredicateNamespace = std::string(Target.getName()); + if (PredicateNamespace == "Thumb") + PredicateNamespace = "ARM"; + EmitDecoder(Records, OS, PredicateNamespace); } } // end namespace llvm diff --git a/llvm/utils/TableGen/FastISelEmitter.cpp b/llvm/utils/TableGen/FastISelEmitter.cpp index 49c2ead468e3..0a88f67be168 100644 --- a/llvm/utils/TableGen/FastISelEmitter.cpp +++ b/llvm/utils/TableGen/FastISelEmitter.cpp @@ -381,14 +381,9 @@ class FastISelMap { OperandsOpcodeTypeRetPredMap SimplePatterns; // This is used to check that there are no duplicate predicates - typedef std::multimap<std::string, bool> PredCheckMap; - typedef std::map<MVT::SimpleValueType, PredCheckMap> RetPredCheckMap; - typedef std::map<MVT::SimpleValueType, RetPredCheckMap> TypeRetPredCheckMap; - typedef std::map<std::string, TypeRetPredCheckMap> OpcodeTypeRetPredCheckMap; - typedef std::map<OperandsSignature, OpcodeTypeRetPredCheckMap> - OperandsOpcodeTypeRetPredCheckMap; - - OperandsOpcodeTypeRetPredCheckMap SimplePatternsCheck; + std::set<std::tuple<OperandsSignature, std::string, MVT::SimpleValueType, + MVT::SimpleValueType, std::string>> + SimplePatternsCheck; std::map<OperandsSignature, std::vector<OperandsSignature> > SignaturesWithConstantForms; @@ -587,16 +582,15 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) { int complexity = Pattern.getPatternComplexity(CGP); - if (SimplePatternsCheck[Operands][OpcodeName][VT] - [RetVT].count(PredicateCheck)) { + auto inserted_simple_pattern = SimplePatternsCheck.insert( + std::make_tuple(Operands, OpcodeName, VT, RetVT, PredicateCheck)); + if (!inserted_simple_pattern.second) { PrintFatalError(Pattern.getSrcRecord()->getLoc(), "Duplicate predicate in FastISel table!"); } - SimplePatternsCheck[Operands][OpcodeName][VT][RetVT].insert( - std::make_pair(PredicateCheck, true)); - // Note: Instructions with the same complexity will appear in the order - // that they are encountered. + // Note: Instructions with the same complexity will appear in the order + // that they are encountered. SimplePatterns[Operands][OpcodeName][VT][RetVT].emplace(complexity, std::move(Memo)); @@ -655,7 +649,7 @@ void FastISelMap::emitInstructionCode(raw_ostream &OS, for (unsigned i = 0; i < Memo.PhysRegs.size(); ++i) { if (Memo.PhysRegs[i] != "") - OS << " BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, " + OS << " BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, " << "TII.get(TargetOpcode::COPY), " << Memo.PhysRegs[i] << ").addReg(Op" << i << ");\n"; } diff --git a/llvm/utils/TableGen/GICombinerEmitter.cpp b/llvm/utils/TableGen/GICombinerEmitter.cpp index 77e05aebf53a..2ae313081a6f 100644 --- a/llvm/utils/TableGen/GICombinerEmitter.cpp +++ b/llvm/utils/TableGen/GICombinerEmitter.cpp @@ -636,7 +636,7 @@ void GICombinerEmitter::emitNameMatcher(raw_ostream &OS) const { std::make_pair(std::string(EnumeratedRule.getName()), Code)); } - OS << "static Optional<uint64_t> getRuleIdxForIdentifier(StringRef " + OS << "static std::optional<uint64_t> getRuleIdxForIdentifier(StringRef " "RuleIdentifier) {\n" << " uint64_t I;\n" << " // getAtInteger(...) returns false on success\n" @@ -647,7 +647,7 @@ void GICombinerEmitter::emitNameMatcher(raw_ostream &OS) const { StringMatcher Matcher("RuleIdentifier", Cases, OS); Matcher.Emit(); OS << "#endif // ifndef NDEBUG\n\n" - << " return None;\n" + << " return std::nullopt;\n" << "}\n"; } @@ -764,6 +764,29 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS, OS << Indent << " if (1\n"; + // Emit code for C++ Predicates. + if (RuleDef.getValue("Predicates")) { + ListInit *Preds = RuleDef.getValueAsListInit("Predicates"); + for (Init *I : Preds->getValues()) { + if (DefInit *Pred = dyn_cast<DefInit>(I)) { + Record *Def = Pred->getDef(); + if (!Def->isSubClassOf("Predicate")) { + PrintError(Def->getLoc(), "Unknown 'Predicate' Type"); + return; + } + + StringRef CondString = Def->getValueAsString("CondString"); + if (CondString.empty()) + continue; + + OS << Indent << " && (\n" + << Indent << " // Predicate: " << Def->getName() << "\n" + << Indent << " " << CondString << "\n" + << Indent << " )\n"; + } + } + } + // Attempt to emit code for any untested predicates left over. Note that // isFullyTested() will remain false even if we succeed here and therefore // combine rule elision will not be performed. This is because we do not @@ -800,16 +823,19 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS, << Indent << " " << CodeExpander(Rule->getMatchingFixupCode()->getValue(), Expansions, RuleDef.getLoc(), ShowExpansions) - << "\n" + << '\n' << Indent << " return true;\n" << Indent << " }()"; } - OS << ") {\n" << Indent << " "; + OS << Indent << " ) {\n" << Indent << " "; if (const StringInit *Code = dyn_cast<StringInit>(Applyer->getArg(0))) { - OS << CodeExpander(Code->getAsUnquotedString(), Expansions, + OS << " LLVM_DEBUG(dbgs() << \"Applying rule '" + << RuleDef.getName() + << "'\\n\");\n" + << CodeExpander(Code->getAsUnquotedString(), Expansions, RuleDef.getLoc(), ShowExpansions) - << "\n" + << '\n' << Indent << " return true;\n" << Indent << " }\n"; } else { @@ -842,7 +868,7 @@ static void emitAdditionalHelperMethodArguments(raw_ostream &OS, Record *Combiner) { for (Record *Arg : Combiner->getValueAsListOfDefs("AdditionalArguments")) OS << ",\n " << Arg->getValueAsString("Type") - << Arg->getValueAsString("Name"); + << " " << Arg->getValueAsString("Name"); } void GICombinerEmitter::run(raw_ostream &OS) { @@ -924,7 +950,7 @@ void GICombinerEmitter::run(raw_ostream &OS) { emitNameMatcher(OS); - OS << "static Optional<std::pair<uint64_t, uint64_t>> " + OS << "static std::optional<std::pair<uint64_t, uint64_t>> " "getRuleRangeForIdentifier(StringRef RuleIdentifier) {\n" << " std::pair<StringRef, StringRef> RangePair = " "RuleIdentifier.split('-');\n" @@ -934,7 +960,7 @@ void GICombinerEmitter::run(raw_ostream &OS) { << " const auto Last = " "getRuleIdxForIdentifier(RangePair.second);\n" << " if (!First || !Last)\n" - << " return None;\n" + << " return std::nullopt;\n" << " if (First >= Last)\n" << " report_fatal_error(\"Beginning of range should be before " "end of range\");\n" @@ -945,7 +971,7 @@ void GICombinerEmitter::run(raw_ostream &OS) { << " }\n" << " const auto I = getRuleIdxForIdentifier(RangePair.first);\n" << " if (!I)\n" - << " return None;\n" + << " return std::nullopt;\n" << " return {{*I, *I + 1}};\n" << "}\n\n"; diff --git a/llvm/utils/TableGen/GlobalISel/CodeExpansions.h b/llvm/utils/TableGen/GlobalISel/CodeExpansions.h index bb890ec8f57e..f536e801b27f 100644 --- a/llvm/utils/TableGen/GlobalISel/CodeExpansions.h +++ b/llvm/utils/TableGen/GlobalISel/CodeExpansions.h @@ -24,9 +24,9 @@ protected: public: void declare(StringRef Name, StringRef Expansion) { - bool Inserted = Expansions.try_emplace(Name, Expansion).second; - assert(Inserted && "Declared variable twice"); - (void)Inserted; + // Duplicates are not inserted. The expansion refers to different + // MachineOperands using the same virtual register. + Expansions.try_emplace(Name, Expansion); } std::string lookup(StringRef Variable) const { diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp index 42055ad4f608..d98884493e84 100644 --- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp +++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp @@ -580,6 +580,10 @@ void GIMatchTreeOpcodePartitioner::applyForPartition( } } for (auto &Leaf : NewLeaves) { + // Skip any leaves that don't care about this instruction. + if (!Leaf.getInstrInfo(InstrID)) + continue; + for (unsigned OpIdx : ReferencedOperands.set_bits()) { Leaf.declareOperand(InstrID, OpIdx); } @@ -697,8 +701,10 @@ void GIMatchTreeVRegDefPartitioner::repartition( for (const auto &Leaf : enumerate(Leaves)) { GIMatchTreeInstrInfo *InstrInfo = Leaf.value().getInstrInfo(InstrID); if (!InstrInfo) - for (auto &Partition : Partitions) + for (auto &Partition : Partitions) { + Partition.second.resize(Leaf.index() + 1); Partition.second.set(Leaf.index()); + } } } @@ -762,17 +768,18 @@ void GIMatchTreeVRegDefPartitioner::emitPartitionResults( void GIMatchTreeVRegDefPartitioner::generatePartitionSelectorCode( raw_ostream &OS, StringRef Indent) const { - OS << Indent << "Partition = -1\n" - << Indent << "if (MIs.size() <= NewInstrID) MIs.resize(NewInstrID + 1);\n" + OS << Indent << "Partition = -1;\n" + << Indent << "if (MIs.size() <= " << NewInstrID << ") MIs.resize(" + << (NewInstrID + 1) << ");\n" << Indent << "MIs[" << NewInstrID << "] = nullptr;\n" - << Indent << "if (MIs[" << InstrID << "].getOperand(" << OpIdx - << ").isReg()))\n" + << Indent << "if (MIs[" << InstrID << "]->getOperand(" << OpIdx + << ").isReg())\n" << Indent << " MIs[" << NewInstrID << "] = MRI.getVRegDef(MIs[" << InstrID - << "].getOperand(" << OpIdx << ").getReg()));\n"; + << "]->getOperand(" << OpIdx << ").getReg());\n"; for (const auto &Pair : ResultToPartition) OS << Indent << "if (MIs[" << NewInstrID << "] " - << (Pair.first ? "==" : "!=") + << (Pair.first ? "!=" : "==") << " nullptr) Partition = " << Pair.second << ";\n"; OS << Indent << "if (Partition == -1) return false;\n"; diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h index 55a86259661d..0ce4060fe7b4 100644 --- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h +++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h @@ -24,12 +24,12 @@ class GIMatchTreeVariableBinding { StringRef Name; // The matched instruction it is bound to. unsigned InstrID; - // The matched operand (if appropriate) it is bound to. - Optional<unsigned> OpIdx; + // The matched operand (if appropriate) it is bound to. + std::optional<unsigned> OpIdx; public: GIMatchTreeVariableBinding(StringRef Name, unsigned InstrID, - Optional<unsigned> OpIdx = None) + std::optional<unsigned> OpIdx = std::nullopt) : Name(Name), InstrID(InstrID), OpIdx(OpIdx) {} bool isInstr() const { return !OpIdx; } diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index 4b47cda41567..c79c79948a80 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -32,7 +32,6 @@ #include "CodeGenDAGPatterns.h" #include "CodeGenInstruction.h" #include "SubtargetFeatureInfo.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CodeGenCoverage.h" #include "llvm/Support/CommandLine.h" @@ -184,11 +183,12 @@ public: "Unexpected mismatch of scalable property"); return Ty.isVector() ? std::make_tuple(Ty.isScalable(), - Ty.getSizeInBits().getKnownMinSize()) < - std::make_tuple(Other.Ty.isScalable(), - Other.Ty.getSizeInBits().getKnownMinSize()) - : Ty.getSizeInBits().getFixedSize() < - Other.Ty.getSizeInBits().getFixedSize(); + Ty.getSizeInBits().getKnownMinValue()) < + std::make_tuple( + Other.Ty.isScalable(), + Other.Ty.getSizeInBits().getKnownMinValue()) + : Ty.getSizeInBits().getFixedValue() < + Other.Ty.getSizeInBits().getFixedValue(); } bool operator==(const LLTCodeGen &B) const { return Ty == B.Ty; } @@ -200,7 +200,7 @@ std::set<LLTCodeGen> KnownTypes; class InstructionMatcher; /// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for /// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...). -static Optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) { +static std::optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) { MVT VT(SVT); if (VT.isVector() && !VT.getVectorElementCount().isScalar()) @@ -210,7 +210,7 @@ static Optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) { if (VT.isInteger() || VT.isFloatingPoint()) return LLTCodeGen(LLT::scalar(VT.getSizeInBits())); - return None; + return std::nullopt; } static std::string explainPredicates(const TreePatternNode *N) { @@ -466,7 +466,7 @@ public: /// The actual run-time value, if known int64_t RawValue; - MatchTableRecord(Optional<unsigned> LabelID_, StringRef EmitStr, + MatchTableRecord(std::optional<unsigned> LabelID_, StringRef EmitStr, unsigned NumElements, unsigned Flags, int64_t RawValue = std::numeric_limits<int64_t>::min()) : LabelID(LabelID_.value_or(~0u)), EmitStr(EmitStr), @@ -518,7 +518,8 @@ class MatchTable { public: static MatchTableRecord LineBreak; static MatchTableRecord Comment(StringRef Comment) { - return MatchTableRecord(None, Comment, 0, MatchTableRecord::MTRF_Comment); + return MatchTableRecord(std::nullopt, Comment, 0, + MatchTableRecord::MTRF_Comment); } static MatchTableRecord Opcode(StringRef Opcode, int IndentAdjust = 0) { unsigned ExtraFlags = 0; @@ -527,29 +528,29 @@ public: if (IndentAdjust < 0) ExtraFlags |= MatchTableRecord::MTRF_Outdent; - return MatchTableRecord(None, Opcode, 1, + return MatchTableRecord(std::nullopt, Opcode, 1, MatchTableRecord::MTRF_CommaFollows | ExtraFlags); } static MatchTableRecord NamedValue(StringRef NamedValue) { - return MatchTableRecord(None, NamedValue, 1, + return MatchTableRecord(std::nullopt, NamedValue, 1, MatchTableRecord::MTRF_CommaFollows); } static MatchTableRecord NamedValue(StringRef NamedValue, int64_t RawValue) { - return MatchTableRecord(None, NamedValue, 1, + return MatchTableRecord(std::nullopt, NamedValue, 1, MatchTableRecord::MTRF_CommaFollows, RawValue); } static MatchTableRecord NamedValue(StringRef Namespace, StringRef NamedValue) { - return MatchTableRecord(None, (Namespace + "::" + NamedValue).str(), 1, - MatchTableRecord::MTRF_CommaFollows); + return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(), + 1, MatchTableRecord::MTRF_CommaFollows); } static MatchTableRecord NamedValue(StringRef Namespace, StringRef NamedValue, int64_t RawValue) { - return MatchTableRecord(None, (Namespace + "::" + NamedValue).str(), 1, - MatchTableRecord::MTRF_CommaFollows, RawValue); + return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(), + 1, MatchTableRecord::MTRF_CommaFollows, RawValue); } static MatchTableRecord IntValue(int64_t IntValue) { - return MatchTableRecord(None, llvm::to_string(IntValue), 1, + return MatchTableRecord(std::nullopt, llvm::to_string(IntValue), 1, MatchTableRecord::MTRF_CommaFollows); } static MatchTableRecord Label(unsigned LabelID) { @@ -625,7 +626,7 @@ public: }; MatchTableRecord MatchTable::LineBreak = { - None, "" /* Emit String */, 0 /* Elements */, + std::nullopt, "" /* Emit String */, 0 /* Elements */, MatchTableRecord::MTRF_LineBreakFollows}; void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis, @@ -965,11 +966,11 @@ public: return Error::success(); } - Optional<DefinedComplexPatternSubOperand> + std::optional<DefinedComplexPatternSubOperand> getComplexSubOperand(StringRef SymbolicName) const { const auto &I = ComplexSubOperands.find(SymbolicName); if (I == ComplexSubOperands.end()) - return None; + return std::nullopt; return I->second; } @@ -1642,9 +1643,9 @@ public: /// Construct a new operand predicate and add it to the matcher. template <class Kind, class... Args> - Optional<Kind *> addPredicate(Args &&... args) { + std::optional<Kind *> addPredicate(Args &&...args) { if (isSameAsAnotherOperand()) - return None; + return std::nullopt; Predicates.emplace_back(std::make_unique<Kind>( getInsnVarID(), getOpIdx(), std::forward<Args>(args)...)); return static_cast<Kind *>(Predicates.back().get()); @@ -2301,7 +2302,7 @@ public: /// Construct a new instruction predicate and add it to the matcher. template <class Kind, class... Args> - Optional<Kind *> addPredicate(Args &&... args) { + std::optional<Kind *> addPredicate(Args &&...args) { Predicates.emplace_back( std::make_unique<Kind>(getInsnVarID(), std::forward<Args>(args)...)); return static_cast<Kind *>(Predicates.back().get()); @@ -2522,6 +2523,12 @@ public: return true; return false; } + + /// Report the maximum number of temporary operands needed by the predicate + /// matcher. + unsigned countRendererFns() const override { + return InsnMatcher->countRendererFns(); + } }; void InstructionMatcher::optimize() { @@ -2944,7 +2951,7 @@ private: unsigned RendererID; /// When provided, this is the suboperand of the ComplexPattern operand to /// render. Otherwise all the suboperands will be rendered. - Optional<unsigned> SubOperand; + std::optional<unsigned> SubOperand; unsigned getNumOperands() const { return TheDef.getValueAsDag("Operands")->getNumArgs(); @@ -2953,7 +2960,7 @@ private: public: RenderComplexPatternOperand(unsigned InsnID, const Record &TheDef, StringRef SymbolicName, unsigned RendererID, - Optional<unsigned> SubOperand = None) + std::optional<unsigned> SubOperand = std::nullopt) : OperandRenderer(OR_ComplexPattern), InsnID(InsnID), TheDef(TheDef), SymbolicName(SymbolicName), RendererID(RendererID), SubOperand(SubOperand) {} @@ -2970,7 +2977,7 @@ public: << MatchTable::IntValue(RendererID); if (SubOperand) Table << MatchTable::Comment("SubOperand") - << MatchTable::IntValue(SubOperand.value()); + << MatchTable::IntValue(*SubOperand); Table << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak; } }; @@ -3135,7 +3142,7 @@ public: << MatchTable::LineBreak; if (!I->ImplicitDefs.empty() || !I->ImplicitUses.empty()) { - for (auto Def : I->ImplicitDefs) { + for (auto *Def : I->ImplicitDefs) { auto Namespace = Def->getValue("Namespace") ? Def->getValueAsString("Namespace") : ""; @@ -3144,7 +3151,7 @@ public: << MatchTable::NamedValue(Namespace, Def->getName()) << MatchTable::LineBreak; } - for (auto Use : I->ImplicitUses) { + for (auto *Use : I->ImplicitUses) { auto Namespace = Use->getValue("Namespace") ? Use->getValueAsString("Namespace") : ""; @@ -3545,7 +3552,7 @@ static Expected<LLTCodeGen> getInstResultType(const TreePatternNode *Dst) { if (ChildTypes.size() != 1) return failedImport("Dst pattern child has multiple results"); - Optional<LLTCodeGen> MaybeOpTy; + std::optional<LLTCodeGen> MaybeOpTy; if (ChildTypes.front().isMachineValueType()) { MaybeOpTy = MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy); @@ -3591,7 +3598,7 @@ private: SubtargetFeatureInfoMap SubtargetFeatures; // Rule coverage information. - Optional<CodeGenCoverage> RuleCoverage; + std::optional<CodeGenCoverage> RuleCoverage; /// Variables used to help with collecting of named operands for predicates /// with 'let PredicateCodeUsesOperands = 1'. WaitingForNamedOperands is set @@ -3675,31 +3682,31 @@ private: /// Infer a CodeGenRegisterClass for the type of \p SuperRegNode. The returned /// CodeGenRegisterClass will support the CodeGenRegisterClass of /// \p SubRegNode, and the subregister index defined by \p SubRegIdxNode. - /// If no register class is found, return None. - Optional<const CodeGenRegisterClass *> + /// If no register class is found, return std::nullopt. + std::optional<const CodeGenRegisterClass *> inferSuperRegisterClassForNode(const TypeSetByHwMode &Ty, TreePatternNode *SuperRegNode, TreePatternNode *SubRegIdxNode); - Optional<CodeGenSubRegIndex *> + std::optional<CodeGenSubRegIndex *> inferSubRegIndexForNode(TreePatternNode *SubRegIdxNode); /// Infer a CodeGenRegisterClass which suppoorts \p Ty and \p SubRegIdxNode. - /// Return None if no such class exists. - Optional<const CodeGenRegisterClass *> + /// Return std::nullopt if no such class exists. + std::optional<const CodeGenRegisterClass *> inferSuperRegisterClass(const TypeSetByHwMode &Ty, TreePatternNode *SubRegIdxNode); /// Return the CodeGenRegisterClass associated with \p Leaf if it has one. - Optional<const CodeGenRegisterClass *> + std::optional<const CodeGenRegisterClass *> getRegClassFromLeaf(TreePatternNode *Leaf); - /// Return a CodeGenRegisterClass for \p N if one can be found. Return None - /// otherwise. - Optional<const CodeGenRegisterClass *> + /// Return a CodeGenRegisterClass for \p N if one can be found. Return + /// std::nullopt otherwise. + std::optional<const CodeGenRegisterClass *> inferRegClassFromPattern(TreePatternNode *N); /// Return the size of the MemoryVT in this predicate, if possible. - Optional<unsigned> + std::optional<unsigned> getMemSizeBitsFromPredicate(const TreePredicateFn &Predicate); // Add builtin predicates. @@ -3816,12 +3823,13 @@ Error GlobalISelEmitter::importRulePredicates(RuleMatcher &M, return Error::success(); } -Optional<unsigned> GlobalISelEmitter::getMemSizeBitsFromPredicate(const TreePredicateFn &Predicate) { - Optional<LLTCodeGen> MemTyOrNone = +std::optional<unsigned> GlobalISelEmitter::getMemSizeBitsFromPredicate( + const TreePredicateFn &Predicate) { + std::optional<LLTCodeGen> MemTyOrNone = MVTToLLT(getValueType(Predicate.getMemoryVT())); if (!MemTyOrNone) - return None; + return std::nullopt; // Align so unusual types like i1 don't get rounded down. return llvm::alignTo( @@ -4007,8 +4015,10 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( for (const TypeSetByHwMode &VTy : Src->getExtTypes()) { // Results don't have a name unless they are the root node. The caller will // set the name if appropriate. + const bool OperandIsAPointer = + SrcGIOrNull && SrcGIOrNull->isOutOperandAPointer(OpIdx); OperandMatcher &OM = InsnMatcher.addOperand(OpIdx++, "", TempOpIdx); - if (auto Error = OM.addTypeCheckPredicate(VTy, false /* OperandIsAPointer */)) + if (auto Error = OM.addTypeCheckPredicate(VTy, OperandIsAPointer)) return failedImport(toString(std::move(Error)) + " for result of Src pattern operator"); } @@ -4156,13 +4166,13 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( // argument that is required to be an immediate, we should not emit an LLT // type check, and should not be looking for a G_CONSTANT defined // register. - bool OperandIsImmArg = SrcGIOrNull->isOperandImmArg(i); + bool OperandIsImmArg = SrcGIOrNull->isInOperandImmArg(i); // SelectionDAG allows pointers to be represented with iN since it doesn't // distinguish between pointers and integers but they are different types in GlobalISel. // Coerce integers to pointers to address space 0 if the context indicates a pointer. // - bool OperandIsAPointer = SrcGIOrNull->isOperandAPointer(i); + bool OperandIsAPointer = SrcGIOrNull->isInOperandAPointer(i); if (IsIntrinsic) { // For G_INTRINSIC/G_INTRINSIC_W_SIDE_EFFECTS, the operand immediately @@ -4414,7 +4424,7 @@ Error GlobalISelEmitter::importChildMatcher( // Treat G_BUILD_VECTOR as the canonical opcode, and G_BUILD_VECTOR_TRUNC // as an alternative. InsnOperand.getInsnMatcher().addPredicate<InstructionOpcodeMatcher>( - makeArrayRef({&BuildVector, &BuildVectorTrunc})); + ArrayRef({&BuildVector, &BuildVectorTrunc})); // TODO: Handle both G_BUILD_VECTOR and G_BUILD_VECTOR_TRUNC We could // theoretically not emit any opcode check, but getOpcodeMatcher currently @@ -4536,7 +4546,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer( if (ChildTypes.size() != 1) return failedImport("Dst pattern child has multiple results"); - Optional<LLTCodeGen> OpTyOrNone = None; + std::optional<LLTCodeGen> OpTyOrNone; if (ChildTypes.front().isMachineValueType()) OpTyOrNone = MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy); if (!OpTyOrNone) @@ -4650,7 +4660,7 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer( if (!SubClass) return failedImport( "Cannot infer register class from INSERT_SUBREG operand #1"); - Optional<const CodeGenRegisterClass *> SuperClass = + std::optional<const CodeGenRegisterClass *> SuperClass = inferSuperRegisterClassForNode(Dst->getExtType(0), Dst->getChild(0), Dst->getChild(2)); if (!SuperClass) @@ -4968,7 +4978,7 @@ Error GlobalISelEmitter::importDefaultOperandRenderers( action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder, DagInit *DefaultOps) const { for (const auto *DefaultOp : DefaultOps->getArgs()) { - Optional<LLTCodeGen> OpTyOrNone = None; + std::optional<LLTCodeGen> OpTyOrNone; // Look through ValueType operators. if (const DagInit *DefaultDagOp = dyn_cast<DagInit>(DefaultOp)) { @@ -4986,7 +4996,7 @@ Error GlobalISelEmitter::importDefaultOperandRenderers( auto Def = DefaultDefOp->getDef(); if (Def->getName() == "undef_tied_input") { unsigned TempRegID = M.allocateTempRegID(); - M.insertAction<MakeTempRegisterAction>(InsertPt, OpTyOrNone.value(), + M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTyOrNone, TempRegID); InsertPt = M.insertAction<BuildMIAction>( InsertPt, M.allocateOutputInsnID(), @@ -5020,23 +5030,23 @@ Error GlobalISelEmitter::importImplicitDefRenderers( return Error::success(); } -Optional<const CodeGenRegisterClass *> +std::optional<const CodeGenRegisterClass *> GlobalISelEmitter::getRegClassFromLeaf(TreePatternNode *Leaf) { assert(Leaf && "Expected node?"); assert(Leaf->isLeaf() && "Expected leaf?"); Record *RCRec = getInitValueAsRegClass(Leaf->getLeafValue()); if (!RCRec) - return None; + return std::nullopt; CodeGenRegisterClass *RC = CGRegs.getRegClass(RCRec); if (!RC) - return None; + return std::nullopt; return RC; } -Optional<const CodeGenRegisterClass *> +std::optional<const CodeGenRegisterClass *> GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) { if (!N) - return None; + return std::nullopt; if (N->isLeaf()) return getRegClassFromLeaf(N); @@ -5046,18 +5056,18 @@ GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) { // Only handle things that produce a single type. if (N->getNumTypes() != 1) - return None; + return std::nullopt; Record *OpRec = N->getOperator(); // We only want instructions. if (!OpRec->isSubClassOf("Instruction")) - return None; + return std::nullopt; // Don't want to try and infer things when there could potentially be more // than one candidate register class. auto &Inst = Target.getInstruction(OpRec); if (Inst.Operands.NumDefs > 1) - return None; + return std::nullopt; // Handle any special-case instructions which we can safely infer register // classes from. @@ -5068,7 +5078,7 @@ GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) { // has the desired register class as the first child. TreePatternNode *RCChild = N->getChild(IsRegSequence ? 0 : 1); if (!RCChild->isLeaf()) - return None; + return std::nullopt; return getRegClassFromLeaf(RCChild); } if (InstName == "INSERT_SUBREG") { @@ -5098,21 +5108,21 @@ GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) { return &RC; } - return None; + return std::nullopt; } -Optional<const CodeGenRegisterClass *> +std::optional<const CodeGenRegisterClass *> GlobalISelEmitter::inferSuperRegisterClass(const TypeSetByHwMode &Ty, TreePatternNode *SubRegIdxNode) { assert(SubRegIdxNode && "Expected subregister index node!"); // We need a ValueTypeByHwMode for getSuperRegForSubReg. if (!Ty.isValueTypeByHwMode(false)) - return None; + return std::nullopt; if (!SubRegIdxNode->isLeaf()) - return None; + return std::nullopt; DefInit *SubRegInit = dyn_cast<DefInit>(SubRegIdxNode->getLeafValue()); if (!SubRegInit) - return None; + return std::nullopt; CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef()); // Use the information we found above to find a minimal register class which @@ -5121,11 +5131,11 @@ GlobalISelEmitter::inferSuperRegisterClass(const TypeSetByHwMode &Ty, Target.getSuperRegForSubReg(Ty.getValueTypeByHwMode(), CGRegs, SubIdx, /* MustBeAllocatable */ true); if (!RC) - return None; + return std::nullopt; return *RC; } -Optional<const CodeGenRegisterClass *> +std::optional<const CodeGenRegisterClass *> GlobalISelEmitter::inferSuperRegisterClassForNode( const TypeSetByHwMode &Ty, TreePatternNode *SuperRegNode, TreePatternNode *SubRegIdxNode) { @@ -5135,20 +5145,20 @@ GlobalISelEmitter::inferSuperRegisterClassForNode( // from the subregister index node. We can assume that whoever wrote the // pattern in the first place made sure that the super register and // subregister are compatible. - if (Optional<const CodeGenRegisterClass *> SuperRegisterClass = + if (std::optional<const CodeGenRegisterClass *> SuperRegisterClass = inferRegClassFromPattern(SuperRegNode)) return *SuperRegisterClass; return inferSuperRegisterClass(Ty, SubRegIdxNode); } -Optional<CodeGenSubRegIndex *> +std::optional<CodeGenSubRegIndex *> GlobalISelEmitter::inferSubRegIndexForNode(TreePatternNode *SubRegIdxNode) { if (!SubRegIdxNode->isLeaf()) - return None; + return std::nullopt; DefInit *SubRegInit = dyn_cast<DefInit>(SubRegIdxNode->getLeafValue()); if (!SubRegInit) - return None; + return std::nullopt; return CGRegs.getSubRegIdx(SubRegInit->getDef()); } @@ -5673,11 +5683,11 @@ void GlobalISelEmitter::run(raw_ostream &OS) { auto RuleCoverageBufOrErr = MemoryBuffer::getFile(UseCoverageFile); if (!RuleCoverageBufOrErr) { PrintWarning(SMLoc(), "Missing rule coverage data"); - RuleCoverage = None; + RuleCoverage = std::nullopt; } else { if (!RuleCoverage->parse(*RuleCoverageBufOrErr.get(), Target.getName())) { PrintWarning(SMLoc(), "Ignoring invalid or missing rule coverage data"); - RuleCoverage = None; + RuleCoverage = std::nullopt; } } } @@ -5849,6 +5859,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) { // Emit a table containing the PredicateBitsets objects needed by the matcher // and an enum for the matcher to reference them with. std::vector<std::vector<Record *>> FeatureBitsets; + FeatureBitsets.reserve(Rules.size()); for (auto &Rule : Rules) FeatureBitsets.push_back(Rule.getRequiredFeatures()); llvm::sort(FeatureBitsets, [&](const std::vector<Record *> &A, diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp index da8d0a0096fd..564c3ed64e26 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -117,9 +117,9 @@ private: static void PrintDefList(const std::vector<Record*> &Uses, unsigned Num, raw_ostream &OS) { OS << "static const MCPhysReg ImplicitList" << Num << "[] = { "; - for (Record *U : Uses) - OS << getQualifiedName(U) << ", "; - OS << "0 };\n"; + for (auto [Idx, U] : enumerate(Uses)) + OS << (Idx ? ", " : "") << getQualifiedName(U); + OS << " };\n"; } //===----------------------------------------------------------------------===// @@ -907,16 +907,14 @@ void InstrInfoEmitter::run(raw_ostream &OS) { // Emit all of the instruction's implicit uses and defs. Records.startTimer("Emit uses/defs"); for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) { - Record *Inst = II->TheDef; - std::vector<Record*> Uses = Inst->getValueAsListOfDefs("Uses"); - if (!Uses.empty()) { - unsigned &IL = EmittedLists[Uses]; - if (!IL) PrintDefList(Uses, IL = ++ListNumber, OS); - } - std::vector<Record*> Defs = Inst->getValueAsListOfDefs("Defs"); - if (!Defs.empty()) { - unsigned &IL = EmittedLists[Defs]; - if (!IL) PrintDefList(Defs, IL = ++ListNumber, OS); + std::vector<Record *> ImplicitOps = II->ImplicitUses; + llvm::append_range(ImplicitOps, II->ImplicitDefs); + if (!ImplicitOps.empty()) { + unsigned &IL = EmittedLists[ImplicitOps]; + if (!IL) { + IL = ++ListNumber; + PrintDefList(ImplicitOps, IL, OS); + } } } @@ -926,20 +924,19 @@ void InstrInfoEmitter::run(raw_ostream &OS) { Records.startTimer("Emit operand info"); EmitOperandInfo(OS, OperandInfoIDs); - // Emit all of the MCInstrDesc records in their ENUM ordering. - // + // Emit all of the MCInstrDesc records in reverse ENUM ordering. Records.startTimer("Emit InstrDesc records"); OS << "\nextern const MCInstrDesc " << TargetName << "Insts[] = {\n"; ArrayRef<const CodeGenInstruction*> NumberedInstructions = Target.getInstructionsByEnumValue(); SequenceToOffsetTable<std::string> InstrNames; - unsigned Num = 0; - for (const CodeGenInstruction *Inst : NumberedInstructions) { + unsigned Num = NumberedInstructions.size(); + for (const CodeGenInstruction *Inst : reverse(NumberedInstructions)) { // Keep a list of the instruction names. InstrNames.add(std::string(Inst->TheDef->getName())); // Emit the record into the table. - emitRecord(*Inst, Num++, InstrInfo, EmittedLists, OperandInfoIDs, OS); + emitRecord(*Inst, --Num, InstrInfo, EmittedLists, OperandInfoIDs, OS); } OS << "};\n\n"; @@ -1032,7 +1029,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "namespace llvm {\n"; OS << "struct " << ClassName << " : public TargetInstrInfo {\n" << " explicit " << ClassName - << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1, int ReturnOpcode = -1);\n" + << "(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u, " + "unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u);\n" << " ~" << ClassName << "() override = default;\n"; @@ -1065,8 +1063,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "extern const MCInstrInfo::ComplexDeprecationPredicate " << TargetName << "InstrComplexDeprecationInfos[];\n"; OS << ClassName << "::" << ClassName - << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode, int " - "ReturnOpcode)\n" + << "(unsigned CFSetupOpcode, unsigned CFDestroyOpcode, unsigned " + "CatchRetOpcode, unsigned ReturnOpcode)\n" << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, " "ReturnOpcode) {\n" << " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName @@ -1118,7 +1116,9 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, OS << Num << ",\t" << MinOperands << ",\t" << Inst.Operands.NumDefs << ",\t" << Inst.TheDef->getValueAsInt("Size") << ",\t" - << SchedModels.getSchedClassIdx(Inst) << ",\t0"; + << SchedModels.getSchedClassIdx(Inst) << ",\t" + << Inst.ImplicitUses.size() << ",\t" + << Inst.ImplicitDefs.size() << ",\t0"; CodeGenTarget &Target = CDP.getTargetInfo(); @@ -1183,18 +1183,13 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, OS.write_hex(Value); OS << "ULL, "; - // Emit the implicit uses and defs lists... - std::vector<Record*> UseList = Inst.TheDef->getValueAsListOfDefs("Uses"); - if (UseList.empty()) - OS << "nullptr, "; - else - OS << "ImplicitList" << EmittedLists[UseList] << ", "; - - std::vector<Record*> DefList = Inst.TheDef->getValueAsListOfDefs("Defs"); - if (DefList.empty()) + // Emit the implicit use/def list... + std::vector<Record *> ImplicitOps = Inst.ImplicitUses; + llvm::append_range(ImplicitOps, Inst.ImplicitDefs); + if (ImplicitOps.empty()) OS << "nullptr, "; else - OS << "ImplicitList" << EmittedLists[DefList] << ", "; + OS << "ImplicitList" << EmittedLists[ImplicitOps] << ", "; // Emit the operand info. std::vector<std::string> OperandInfo = GetOperandInfo(Inst); diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp index fca2bc34e09a..946a58417594 100644 --- a/llvm/utils/TableGen/IntrinsicEmitter.cpp +++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -361,10 +361,10 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes, unsigned Tmp = 0; switch (VT) { default: break; - case MVT::iPTRAny: ++Tmp; LLVM_FALLTHROUGH; - case MVT::vAny: ++Tmp; LLVM_FALLTHROUGH; - case MVT::fAny: ++Tmp; LLVM_FALLTHROUGH; - case MVT::iAny: ++Tmp; LLVM_FALLTHROUGH; + case MVT::iPTRAny: ++Tmp; [[fallthrough]]; + case MVT::vAny: ++Tmp; [[fallthrough]]; + case MVT::fAny: ++Tmp; [[fallthrough]]; + case MVT::iAny: ++Tmp; [[fallthrough]]; case MVT::Any: { // If this is an "any" valuetype, then the type is the type of the next // type in the list specified to getIntrinsic(). @@ -444,16 +444,16 @@ static void UpdateArgCodes(Record *R, std::vector<unsigned char> &ArgCodes, break; case MVT::iPTRAny: ++Tmp; - LLVM_FALLTHROUGH; + [[fallthrough]]; case MVT::vAny: ++Tmp; - LLVM_FALLTHROUGH; + [[fallthrough]]; case MVT::fAny: ++Tmp; - LLVM_FALLTHROUGH; + [[fallthrough]]; case MVT::iAny: ++Tmp; - LLVM_FALLTHROUGH; + [[fallthrough]]; case MVT::Any: unsigned OriginalIdx = ArgCodes.size() - NumInserted; assert(OriginalIdx >= Mapping.size()); @@ -601,49 +601,64 @@ void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints, } namespace { -struct AttributeComparator { - bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const { - // Sort throwing intrinsics after non-throwing intrinsics. - if (L->canThrow != R->canThrow) - return R->canThrow; +std::optional<bool> compareFnAttributes(const CodeGenIntrinsic *L, + const CodeGenIntrinsic *R) { + // Sort throwing intrinsics after non-throwing intrinsics. + if (L->canThrow != R->canThrow) + return R->canThrow; + + if (L->isNoDuplicate != R->isNoDuplicate) + return R->isNoDuplicate; - if (L->isNoDuplicate != R->isNoDuplicate) - return R->isNoDuplicate; + if (L->isNoMerge != R->isNoMerge) + return R->isNoMerge; - if (L->isNoMerge != R->isNoMerge) - return R->isNoMerge; + if (L->isNoReturn != R->isNoReturn) + return R->isNoReturn; - if (L->isNoReturn != R->isNoReturn) - return R->isNoReturn; + if (L->isNoCallback != R->isNoCallback) + return R->isNoCallback; - if (L->isNoCallback != R->isNoCallback) - return R->isNoCallback; + if (L->isNoSync != R->isNoSync) + return R->isNoSync; - if (L->isNoSync != R->isNoSync) - return R->isNoSync; + if (L->isNoFree != R->isNoFree) + return R->isNoFree; - if (L->isNoFree != R->isNoFree) - return R->isNoFree; + if (L->isWillReturn != R->isWillReturn) + return R->isWillReturn; - if (L->isWillReturn != R->isWillReturn) - return R->isWillReturn; + if (L->isCold != R->isCold) + return R->isCold; - if (L->isCold != R->isCold) - return R->isCold; + if (L->isConvergent != R->isConvergent) + return R->isConvergent; - if (L->isConvergent != R->isConvergent) - return R->isConvergent; + if (L->isSpeculatable != R->isSpeculatable) + return R->isSpeculatable; - if (L->isSpeculatable != R->isSpeculatable) - return R->isSpeculatable; + if (L->hasSideEffects != R->hasSideEffects) + return R->hasSideEffects; + + // Try to order by readonly/readnone attribute. + uint32_t LK = L->ME.toIntValue(); + uint32_t RK = R->ME.toIntValue(); + if (LK != RK) return (LK > RK); + + return std::nullopt; +} - if (L->hasSideEffects != R->hasSideEffects) - return R->hasSideEffects; +struct FnAttributeComparator { + bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const { + return compareFnAttributes(L, R).value_or(false); + } +}; + +struct AttributeComparator { + bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const { + if (std::optional<bool> Res = compareFnAttributes(L, R)) + return *Res; - // Try to order by readonly/readnone attribute. - CodeGenIntrinsic::ModRefBehavior LK = L->ModRef; - CodeGenIntrinsic::ModRefBehavior RK = R->ModRef; - if (LK != RK) return (LK > RK); // Order by argument attributes. // This is reliable because each side is already sorted internally. return (L->ArgumentAttributes < R->ArgumentAttributes); @@ -656,6 +671,118 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { OS << "// Add parameter attributes that are not common to all intrinsics.\n"; OS << "#ifdef GET_INTRINSIC_ATTRIBUTES\n"; + + // Compute unique argument attribute sets. + std::map<SmallVector<CodeGenIntrinsic::ArgAttribute, 0>, unsigned> + UniqArgAttributes; + OS << "static AttributeSet getIntrinsicArgAttributeSet(" + << "LLVMContext &C, unsigned ID) {\n" + << " switch (ID) {\n" + << " default: llvm_unreachable(\"Invalid attribute set number\");\n"; + for (const CodeGenIntrinsic &Int : Ints) { + for (auto &Attrs : Int.ArgumentAttributes) { + if (Attrs.empty()) + continue; + + unsigned ID = UniqArgAttributes.size(); + if (!UniqArgAttributes.try_emplace(Attrs, ID).second) + continue; + + assert(is_sorted(Attrs) && + "Argument attributes are not sorted"); + + OS << " case " << ID << ":\n"; + OS << " return AttributeSet::get(C, {\n"; + for (const CodeGenIntrinsic::ArgAttribute &Attr : Attrs) { + switch (Attr.Kind) { + case CodeGenIntrinsic::NoCapture: + OS << " Attribute::get(C, Attribute::NoCapture),\n"; + break; + case CodeGenIntrinsic::NoAlias: + OS << " Attribute::get(C, Attribute::NoAlias),\n"; + break; + case CodeGenIntrinsic::NoUndef: + OS << " Attribute::get(C, Attribute::NoUndef),\n"; + break; + case CodeGenIntrinsic::NonNull: + OS << " Attribute::get(C, Attribute::NonNull),\n"; + break; + case CodeGenIntrinsic::Returned: + OS << " Attribute::get(C, Attribute::Returned),\n"; + break; + case CodeGenIntrinsic::ReadOnly: + OS << " Attribute::get(C, Attribute::ReadOnly),\n"; + break; + case CodeGenIntrinsic::WriteOnly: + OS << " Attribute::get(C, Attribute::WriteOnly),\n"; + break; + case CodeGenIntrinsic::ReadNone: + OS << " Attribute::get(C, Attribute::ReadNone),\n"; + break; + case CodeGenIntrinsic::ImmArg: + OS << " Attribute::get(C, Attribute::ImmArg),\n"; + break; + case CodeGenIntrinsic::Alignment: + OS << " Attribute::get(C, Attribute::Alignment, " + << Attr.Value << "),\n"; + break; + } + } + OS << " });\n"; + } + } + OS << " }\n"; + OS << "}\n\n"; + + // Compute unique function attribute sets. + std::map<const CodeGenIntrinsic*, unsigned, FnAttributeComparator> + UniqFnAttributes; + OS << "static AttributeSet getIntrinsicFnAttributeSet(" + << "LLVMContext &C, unsigned ID) {\n" + << " switch (ID) {\n" + << " default: llvm_unreachable(\"Invalid attribute set number\");\n"; + for (const CodeGenIntrinsic &Intrinsic : Ints) { + unsigned ID = UniqFnAttributes.size(); + if (!UniqFnAttributes.try_emplace(&Intrinsic, ID).second) + continue; + + OS << " case " << ID << ":\n" + << " return AttributeSet::get(C, {\n"; + if (!Intrinsic.canThrow) + OS << " Attribute::get(C, Attribute::NoUnwind),\n"; + if (Intrinsic.isNoReturn) + OS << " Attribute::get(C, Attribute::NoReturn),\n"; + if (Intrinsic.isNoCallback) + OS << " Attribute::get(C, Attribute::NoCallback),\n"; + if (Intrinsic.isNoSync) + OS << " Attribute::get(C, Attribute::NoSync),\n"; + if (Intrinsic.isNoFree) + OS << " Attribute::get(C, Attribute::NoFree),\n"; + if (Intrinsic.isWillReturn) + OS << " Attribute::get(C, Attribute::WillReturn),\n"; + if (Intrinsic.isCold) + OS << " Attribute::get(C, Attribute::Cold),\n"; + if (Intrinsic.isNoDuplicate) + OS << " Attribute::get(C, Attribute::NoDuplicate),\n"; + if (Intrinsic.isNoMerge) + OS << " Attribute::get(C, Attribute::NoMerge),\n"; + if (Intrinsic.isConvergent) + OS << " Attribute::get(C, Attribute::Convergent),\n"; + if (Intrinsic.isSpeculatable) + OS << " Attribute::get(C, Attribute::Speculatable),\n"; + + MemoryEffects ME = Intrinsic.ME; + // TODO: IntrHasSideEffects should affect not only readnone intrinsics. + if (ME.doesNotAccessMemory() && Intrinsic.hasSideEffects) + ME = MemoryEffects::unknown(); + if (ME != MemoryEffects::unknown()) { + OS << " Attribute::getWithMemoryEffects(C, " + << "MemoryEffects::createFromIntValue(" << ME.toIntValue() << ")),\n"; + } + OS << " });\n"; + } + OS << " }\n"; + OS << "}\n\n"; OS << "AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id) {\n"; // Compute the maximum number of attribute arguments and the map @@ -686,7 +813,7 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, } OS << " };\n\n"; - OS << " AttributeList AS[" << maxArgAttrs + 1 << "];\n"; + OS << " std::pair<unsigned, AttributeSet> AS[" << maxArgAttrs + 1 << "];\n"; OS << " unsigned NumAttrs = 0;\n"; OS << " if (id != 0) {\n"; OS << " switch(IntrinsicsToAttributesMap[id - 1]) {\n"; @@ -699,182 +826,41 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, // Keep track of the number of attributes we're writing out. unsigned numAttrs = 0; - // The argument attributes are alreadys sorted by argument index. - unsigned Ai = 0, Ae = Intrinsic.ArgumentAttributes.size(); - if (Ae) { - while (Ai != Ae) { - unsigned AttrIdx = Intrinsic.ArgumentAttributes[Ai].Index; - - OS << " const Attribute::AttrKind AttrParam" << AttrIdx << "[]= {"; - ListSeparator LS(","); - - bool AllValuesAreZero = true; - SmallVector<uint64_t, 8> Values; - do { - switch (Intrinsic.ArgumentAttributes[Ai].Kind) { - case CodeGenIntrinsic::NoCapture: - OS << LS << "Attribute::NoCapture"; - break; - case CodeGenIntrinsic::NoAlias: - OS << LS << "Attribute::NoAlias"; - break; - case CodeGenIntrinsic::NoUndef: - OS << LS << "Attribute::NoUndef"; - break; - case CodeGenIntrinsic::Returned: - OS << LS << "Attribute::Returned"; - break; - case CodeGenIntrinsic::ReadOnly: - OS << LS << "Attribute::ReadOnly"; - break; - case CodeGenIntrinsic::WriteOnly: - OS << LS << "Attribute::WriteOnly"; - break; - case CodeGenIntrinsic::ReadNone: - OS << LS << "Attribute::ReadNone"; - break; - case CodeGenIntrinsic::ImmArg: - OS << LS << "Attribute::ImmArg"; - break; - case CodeGenIntrinsic::Alignment: - OS << LS << "Attribute::Alignment"; - break; - } - uint64_t V = Intrinsic.ArgumentAttributes[Ai].Value; - Values.push_back(V); - AllValuesAreZero &= (V == 0); - - ++Ai; - } while (Ai != Ae && Intrinsic.ArgumentAttributes[Ai].Index == AttrIdx); - OS << "};\n"; - - // Generate attribute value array if not all attribute values are zero. - if (!AllValuesAreZero) { - OS << " const uint64_t AttrValParam" << AttrIdx << "[]= {"; - ListSeparator LSV(","); - for (const auto V : Values) - OS << LSV << V; - OS << "};\n"; - } + for (const auto &[AttrIdx, Attrs] : + enumerate(Intrinsic.ArgumentAttributes)) { + if (Attrs.empty()) + continue; - OS << " AS[" << numAttrs++ << "] = AttributeList::get(C, " - << AttrIdx << ", AttrParam" << AttrIdx; - if (!AllValuesAreZero) - OS << ", AttrValParam" << AttrIdx; - OS << ");\n"; - } + unsigned ID = UniqArgAttributes.find(Attrs)->second; + OS << " AS[" << numAttrs++ << "] = {" << AttrIdx + << ", getIntrinsicArgAttributeSet(C, " << ID << ")};\n"; } if (!Intrinsic.canThrow || - (Intrinsic.ModRef != CodeGenIntrinsic::ReadWriteMem && + (Intrinsic.ME != MemoryEffects::unknown() && !Intrinsic.hasSideEffects) || Intrinsic.isNoReturn || Intrinsic.isNoCallback || Intrinsic.isNoSync || Intrinsic.isNoFree || Intrinsic.isWillReturn || Intrinsic.isCold || Intrinsic.isNoDuplicate || Intrinsic.isNoMerge || Intrinsic.isConvergent || Intrinsic.isSpeculatable) { - OS << " const Attribute::AttrKind Atts[] = {"; - ListSeparator LS(","); - if (!Intrinsic.canThrow) - OS << LS << "Attribute::NoUnwind"; - if (Intrinsic.isNoReturn) - OS << LS << "Attribute::NoReturn"; - if (Intrinsic.isNoCallback) - OS << LS << "Attribute::NoCallback"; - if (Intrinsic.isNoSync) - OS << LS << "Attribute::NoSync"; - if (Intrinsic.isNoFree) - OS << LS << "Attribute::NoFree"; - if (Intrinsic.isWillReturn) - OS << LS << "Attribute::WillReturn"; - if (Intrinsic.isCold) - OS << LS << "Attribute::Cold"; - if (Intrinsic.isNoDuplicate) - OS << LS << "Attribute::NoDuplicate"; - if (Intrinsic.isNoMerge) - OS << LS << "Attribute::NoMerge"; - if (Intrinsic.isConvergent) - OS << LS << "Attribute::Convergent"; - if (Intrinsic.isSpeculatable) - OS << LS << "Attribute::Speculatable"; - - switch (Intrinsic.ModRef) { - case CodeGenIntrinsic::NoMem: - if (Intrinsic.hasSideEffects) - break; - OS << LS; - OS << "Attribute::ReadNone"; - break; - case CodeGenIntrinsic::ReadArgMem: - OS << LS; - OS << "Attribute::ReadOnly,"; - OS << "Attribute::ArgMemOnly"; - break; - case CodeGenIntrinsic::ReadMem: - OS << LS; - OS << "Attribute::ReadOnly"; - break; - case CodeGenIntrinsic::ReadInaccessibleMem: - OS << LS; - OS << "Attribute::ReadOnly,"; - OS << "Attribute::InaccessibleMemOnly"; - break; - case CodeGenIntrinsic::ReadInaccessibleMemOrArgMem: - OS << LS; - OS << "Attribute::ReadOnly,"; - OS << "Attribute::InaccessibleMemOrArgMemOnly"; - break; - case CodeGenIntrinsic::WriteArgMem: - OS << LS; - OS << "Attribute::WriteOnly,"; - OS << "Attribute::ArgMemOnly"; - break; - case CodeGenIntrinsic::WriteMem: - OS << LS; - OS << "Attribute::WriteOnly"; - break; - case CodeGenIntrinsic::WriteInaccessibleMem: - OS << LS; - OS << "Attribute::WriteOnly,"; - OS << "Attribute::InaccessibleMemOnly"; - break; - case CodeGenIntrinsic::WriteInaccessibleMemOrArgMem: - OS << LS; - OS << "Attribute::WriteOnly,"; - OS << "Attribute::InaccessibleMemOrArgMemOnly"; - break; - case CodeGenIntrinsic::ReadWriteArgMem: - OS << LS; - OS << "Attribute::ArgMemOnly"; - break; - case CodeGenIntrinsic::ReadWriteInaccessibleMem: - OS << LS; - OS << "Attribute::InaccessibleMemOnly"; - break; - case CodeGenIntrinsic::ReadWriteInaccessibleMemOrArgMem: - OS << LS; - OS << "Attribute::InaccessibleMemOrArgMemOnly"; - break; - case CodeGenIntrinsic::ReadWriteMem: - break; - } - OS << "};\n"; - OS << " AS[" << numAttrs++ << "] = AttributeList::get(C, " - << "AttributeList::FunctionIndex, Atts);\n"; + unsigned ID = UniqFnAttributes.find(&Intrinsic)->second; + OS << " AS[" << numAttrs++ << "] = {AttributeList::FunctionIndex, " + << "getIntrinsicFnAttributeSet(C, " << ID << ")};\n"; } if (numAttrs) { OS << " NumAttrs = " << numAttrs << ";\n"; OS << " break;\n"; - OS << " }\n"; + OS << " }\n"; } else { OS << " return AttributeList();\n"; - OS << " }\n"; + OS << " }\n"; } } OS << " }\n"; OS << " }\n"; - OS << " return AttributeList::get(C, makeArrayRef(AS, NumAttrs));\n"; + OS << " return AttributeList::get(C, ArrayRef(AS, NumAttrs));\n"; OS << "}\n"; OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n"; } diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp index 182cd0076090..d363191bd9b8 100644 --- a/llvm/utils/TableGen/OptParserEmitter.cpp +++ b/llvm/utils/TableGen/OptParserEmitter.cpp @@ -54,9 +54,10 @@ static std::string getOptionSpelling(const Record &R) { static void emitNameUsingSpelling(raw_ostream &OS, const Record &R) { size_t PrefixLength; - OS << "&"; - write_cstring(OS, StringRef(getOptionSpelling(R, PrefixLength))); - OS << "[" << PrefixLength << "]"; + OS << "llvm::StringLiteral("; + write_cstring( + OS, StringRef(getOptionSpelling(R, PrefixLength)).substr(PrefixLength)); + OS << ")"; } class MarshallingInfo { @@ -129,7 +130,7 @@ struct SimpleEnumValueTable { OS << TableIndex; } - Optional<StringRef> emitValueTable(raw_ostream &OS) const { + std::optional<StringRef> emitValueTable(raw_ostream &OS) const { if (TableIndex == -1) return {}; OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n"; @@ -236,8 +237,14 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { CurPrefix = NewPrefix; } - // Dump prefixes. + DenseSet<StringRef> PrefixesUnionSet; + for (const auto &Prefix : Prefixes) + PrefixesUnionSet.insert(Prefix.first.begin(), Prefix.first.end()); + SmallVector<StringRef> PrefixesUnion(PrefixesUnionSet.begin(), + PrefixesUnionSet.end()); + array_pod_sort(PrefixesUnion.begin(), PrefixesUnion.end()); + // Dump prefixes. OS << "/////////\n"; OS << "// Prefixes\n\n"; OS << "#ifdef PREFIX\n"; @@ -251,12 +258,42 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { // Prefix values. OS << ", {"; for (const auto &PrefixKey : Prefix.first) - OS << "\"" << PrefixKey << "\" COMMA "; - OS << "nullptr})\n"; + OS << "llvm::StringLiteral(\"" << PrefixKey << "\") COMMA "; + // Append an empty element to avoid ending up with an empty array. + OS << "llvm::StringLiteral(\"\")})\n"; } OS << "#undef COMMA\n"; OS << "#endif // PREFIX\n\n"; + // Dump prefix unions. + OS << "/////////\n"; + OS << "// Prefix Union\n\n"; + OS << "#ifdef PREFIX_UNION\n"; + OS << "#define COMMA ,\n"; + OS << "PREFIX_UNION({\n"; + for (const auto &Prefix : PrefixesUnion) { + OS << "llvm::StringLiteral(\"" << Prefix << "\") COMMA "; + } + OS << "llvm::StringLiteral(\"\")})\n"; + OS << "#undef COMMA\n"; + OS << "#endif // PREFIX_UNION\n\n"; + + // Dump groups. + OS << "/////////\n"; + OS << "// ValuesCode\n\n"; + OS << "#ifdef OPTTABLE_VALUES_CODE\n"; + for (const Record &R : llvm::make_pointee_range(Opts)) { + // The option values, if any; + if (!isa<UnsetInit>(R.getValueInit("ValuesCode"))) { + assert(isa<UnsetInit>(R.getValueInit("Values")) && + "Cannot choose between Values and ValuesCode"); + OS << "#define VALUES_CODE " << getOptionName(R) << "_Values\n"; + OS << R.getValueAsString("ValuesCode") << "\n"; + OS << "#undef VALUES_CODE\n"; + } + } + OS << "#endif\n"; + OS << "/////////\n"; OS << "// Groups\n\n"; OS << "#ifdef OPTION\n"; @@ -265,7 +302,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << "OPTION("; // The option prefix; - OS << "nullptr"; + OS << "llvm::ArrayRef<llvm::StringLiteral>()"; // The option string. OS << ", \"" << R.getValueAsString("Name") << '"'; @@ -386,6 +423,9 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << ", "; if (!isa<UnsetInit>(R.getValueInit("Values"))) write_cstring(OS, R.getValueAsString("Values")); + else if (!isa<UnsetInit>(R.getValueInit("ValuesCode"))) { + OS << getOptionName(R) << "_Values"; + } else OS << "nullptr"; }; @@ -424,6 +464,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { CmpMarshallingOpts); std::vector<MarshallingInfo> MarshallingInfos; + MarshallingInfos.reserve(OptsWithMarshalling.size()); for (const auto *R : OptsWithMarshalling) MarshallingInfos.push_back(createMarshallingInfo(*R)); @@ -448,40 +489,14 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << MarshallingInfo::ValueTablesDecl << "{"; for (auto ValueTableName : ValueTableNames) - OS << "{" << ValueTableName << ", sizeof(" << ValueTableName - << ") / sizeof(SimpleEnumValue)" - << "},\n"; + OS << "{" << ValueTableName << ", std::size(" << ValueTableName << ")},\n"; OS << "};\n"; OS << "static const unsigned SimpleEnumValueTablesSize = " - "sizeof(SimpleEnumValueTables) / sizeof(SimpleEnumValueTable);\n"; + "std::size(SimpleEnumValueTables);\n"; OS << "#endif // SIMPLE_ENUM_VALUE_TABLE\n"; OS << "\n"; OS << "\n"; - OS << "#ifdef OPTTABLE_ARG_INIT\n"; - OS << "//////////\n"; - OS << "// Option Values\n\n"; - for (const Record &R : llvm::make_pointee_range(Opts)) { - if (isa<UnsetInit>(R.getValueInit("ValuesCode"))) - continue; - OS << "{\n"; - OS << "bool ValuesWereAdded;\n"; - OS << R.getValueAsString("ValuesCode"); - OS << "\n"; - for (StringRef Prefix : R.getValueAsListOfStrings("Prefixes")) { - OS << "ValuesWereAdded = Opt.addValues("; - std::string S(Prefix); - S += R.getValueAsString("Name"); - write_cstring(OS, S); - OS << ", Values);\n"; - OS << "(void)ValuesWereAdded;\n"; - OS << "assert(ValuesWereAdded && \"Couldn't add values to " - "OptTable!\");\n"; - } - OS << "}\n"; - } - OS << "\n"; - OS << "#endif // OPTTABLE_ARG_INIT\n"; } } // end namespace llvm diff --git a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp index dc04174217fb..6a1e1332d767 100644 --- a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp +++ b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp @@ -300,8 +300,7 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) { void PseudoLoweringEmitter::run(raw_ostream &o) { StringRef Classes[] = {"PseudoInstExpansion", "Instruction"}; - std::vector<Record *> Insts = - Records.getAllDerivedDefinitions(makeArrayRef(Classes)); + std::vector<Record *> Insts = Records.getAllDerivedDefinitions(Classes); // Process the pseudo expansion definitions, validating them as we do so. Records.startTimer("Process definitions"); diff --git a/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp b/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp new file mode 100644 index 000000000000..fa6508cbfc69 --- /dev/null +++ b/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp @@ -0,0 +1,82 @@ +//===- RISCVTargetDefEmitter.cpp - Generate lists of RISCV CPUs -----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits the include file needed by the target +// parser to parse the RISC-V CPUs. +// +//===----------------------------------------------------------------------===// + +#include "TableGenBackends.h" +#include "llvm/Support/RISCVISAInfo.h" +#include "llvm/TableGen/Record.h" + +using namespace llvm; + +using ISAInfoTy = llvm::Expected<std::unique_ptr<RISCVISAInfo>>; + +// We can generate march string from target features as what has been described +// in RISCV ISA specification (version 20191213) 'Chapter 27. ISA Extension +// Naming Conventions'. +// +// This is almost the same as RISCVFeatures::parseFeatureBits, except that we +// get feature name from feature records instead of feature bits. +static std::string getMArch(const Record &Rec) { + std::vector<std::string> FeatureVector; + int XLen = 32; + + // Convert features to FeatureVector. + for (auto *Feature : Rec.getValueAsListOfDefs("Features")) { + StringRef FeatureName = Feature->getValueAsString("Name"); + if (llvm::RISCVISAInfo::isSupportedExtensionFeature(FeatureName)) + FeatureVector.push_back((Twine("+") + FeatureName).str()); + else if (FeatureName == "64bit") + XLen = 64; + } + + ISAInfoTy ISAInfo = llvm::RISCVISAInfo::parseFeatures(XLen, FeatureVector); + if (!ISAInfo) + report_fatal_error("Invalid features"); + + // RISCVISAInfo::toString will generate a march string with all the extensions + // we have added to it. + return (*ISAInfo)->toString(); +} + +void llvm::EmitRISCVTargetDef(const RecordKeeper &RK, raw_ostream &OS) { + OS << "#ifndef PROC\n" + << "#define PROC(ENUM, NAME, DEFAULT_MARCH)\n" + << "#endif\n\n"; + + OS << "PROC(INVALID, {\"invalid\"}, {\"\"})\n"; + // Iterate on all definition records. + for (const Record *Rec : RK.getAllDerivedDefinitions("RISCVProcessorModel")) { + std::string MArch = Rec->getValueAsString("DefaultMarch").str(); + + // Compute MArch from features if we don't specify it. + if (MArch.empty()) + MArch = getMArch(*Rec); + + OS << "PROC(" << Rec->getName() << ", " + << "{\"" << Rec->getValueAsString("Name") << "\"}, " + << "{\"" << MArch << "\"})\n"; + } + OS << "\n#undef PROC\n"; + OS << "\n"; + OS << "#ifndef TUNE_PROC\n" + << "#define TUNE_PROC(ENUM, NAME)\n" + << "#endif\n\n"; + OS << "TUNE_PROC(GENERIC, \"generic\")\n"; + + for (const Record *Rec : + RK.getAllDerivedDefinitions("RISCVTuneProcessorModel")) { + OS << "TUNE_PROC(" << Rec->getName() << ", " + << "\"" << Rec->getValueAsString("Name") << "\")\n"; + } + + OS << "\n#undef TUNE_PROC\n"; +} diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp index 3a0fa564074e..113cebf8a08e 100644 --- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp +++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp @@ -440,7 +440,7 @@ void RegisterInfoEmitter::EmitRegMappingTables( OS << "extern const unsigned " << Namespace << (j == 0 ? "DwarfFlavour" : "EHFlavour") << I << "Dwarf2LSize"; if (!isCtor) - OS << " = array_lengthof(" << Namespace + OS << " = std::size(" << Namespace << (j == 0 ? "DwarfFlavour" : "EHFlavour") << I << "Dwarf2L);\n\n"; else OS << ";\n\n"; @@ -498,7 +498,7 @@ void RegisterInfoEmitter::EmitRegMappingTables( OS << "extern const unsigned " << Namespace << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i << "L2DwarfSize"; if (!isCtor) - OS << " = array_lengthof(" << Namespace + OS << " = std::size(" << Namespace << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i << "L2Dwarf);\n\n"; else OS << ";\n\n"; @@ -1169,6 +1169,8 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, << " LaneBitmask reverseComposeSubRegIndexLaneMaskImpl" << "(unsigned, LaneBitmask) const override;\n" << " const TargetRegisterClass *getSubClassWithSubReg" + << "(const TargetRegisterClass *, unsigned) const override;\n" + << " const TargetRegisterClass *getSubRegisterClass" << "(const TargetRegisterClass *, unsigned) const override;\n"; } OS << " const RegClassWeight &getRegClassWeight(" @@ -1190,12 +1192,17 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, << "MCRegister) const override;\n" << " bool isArgumentRegister(const MachineFunction &, " << "MCRegister) const override;\n" + << " bool isConstantPhysReg(MCRegister PhysReg) const override final;\n" << " /// Devirtualized TargetFrameLowering.\n" << " static const " << TargetName << "FrameLowering *getFrameLowering(\n" - << " const MachineFunction &MF);\n" - << "};\n\n"; + << " const MachineFunction &MF);\n"; const auto &RegisterClasses = RegBank.getRegClasses(); + if (llvm::any_of(RegisterClasses, [](const auto &RC) { return RC.getBaseClassOrder(); })) { + OS << " const TargetRegisterClass *getPhysRegBaseClass(MCRegister Reg) const override;\n"; + } + + OS << "};\n\n"; if (!RegisterClasses.empty()) { OS << "namespace " << RegisterClasses.front().Namespace @@ -1401,12 +1408,12 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, OS << " const MCRegisterClass &MCR = " << Target.getName() << "MCRegisterClasses[" << RC.getQualifiedName() + "RegClassID];\n" << " const ArrayRef<MCPhysReg> Order[] = {\n" - << " makeArrayRef(MCR.begin(), MCR.getNumRegs()"; + << " ArrayRef(MCR.begin(), MCR.getNumRegs()"; for (unsigned oi = 1, oe = RC.getNumOrders(); oi != oe; ++oi) if (RC.getOrder(oi).empty()) OS << "),\n ArrayRef<MCPhysReg>("; else - OS << "),\n makeArrayRef(AltOrder" << oi; + OS << "),\n ArrayRef(AltOrder" << oi; OS << ")\n };\n const unsigned Select = " << RC.getName() << "AltOrderSelect(MF);\n assert(Select < " << RC.getNumOrders() << ");\n return Order[Select];\n}\n"; @@ -1425,10 +1432,11 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, << SuperRegIdxSeqs.get(SuperRegIdxLists[RC.EnumValue]) << ",\n "; printMask(OS, RC.LaneMask); OS << ",\n " << (unsigned)RC.AllocationPriority << ",\n " + << (RC.GlobalPriority ? "true" : "false") << ",\n " << format("0x%02x", RC.TSFlags) << ", /* TSFlags */\n " - << (RC.HasDisjunctSubRegs?"true":"false") + << (RC.HasDisjunctSubRegs ? "true" : "false") << ", /* HasDisjunctSubRegs */\n " - << (RC.CoveredBySubRegs?"true":"false") + << (RC.CoveredBySubRegs ? "true" : "false") << ", /* CoveredBySubRegs */\n "; if (RC.getSuperClasses().empty()) OS << "NullRegClasses,\n "; @@ -1510,16 +1518,16 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, emitComposeSubRegIndexLaneMask(OS, RegBank, ClassName); } - // Emit getSubClassWithSubReg. if (!SubRegIndices.empty()) { + // Emit getSubClassWithSubReg. OS << "const TargetRegisterClass *" << ClassName << "::getSubClassWithSubReg(const TargetRegisterClass *RC, unsigned Idx)" << " const {\n"; // Use the smallest type that can hold a regclass ID with room for a // sentinel. - if (RegisterClasses.size() < UINT8_MAX) + if (RegisterClasses.size() <= UINT8_MAX) OS << " static const uint8_t Table["; - else if (RegisterClasses.size() < UINT16_MAX) + else if (RegisterClasses.size() <= UINT16_MAX) OS << " static const uint16_t Table["; else PrintFatalError("Too many register classes."); @@ -1540,10 +1548,105 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, << " assert(Idx < " << SubRegIndicesSize << " && \"Bad subreg\");\n" << " unsigned TV = Table[RC->getID()][Idx];\n" << " return TV ? getRegClass(TV - 1) : nullptr;\n}\n\n"; + + // Emit getSubRegisterClass + OS << "const TargetRegisterClass *" << ClassName + << "::getSubRegisterClass(const TargetRegisterClass *RC, unsigned Idx)" + << " const {\n"; + + // Use the smallest type that can hold a regclass ID with room for a + // sentinel. + if (RegisterClasses.size() <= UINT8_MAX) + OS << " static const uint8_t Table["; + else if (RegisterClasses.size() <= UINT16_MAX) + OS << " static const uint16_t Table["; + else + PrintFatalError("Too many register classes."); + + OS << RegisterClasses.size() << "][" << SubRegIndicesSize << "] = {\n"; + + for (const auto &RC : RegisterClasses) { + OS << " {\t// " << RC.getName() << '\n'; + for (auto &Idx : SubRegIndices) { + std::optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>> + MatchingSubClass = RC.getMatchingSubClassWithSubRegs(RegBank, &Idx); + + unsigned EnumValue = 0; + if (MatchingSubClass) { + CodeGenRegisterClass *SubRegClass = MatchingSubClass->second; + EnumValue = SubRegClass->EnumValue + 1; + } + + OS << " " << EnumValue << ",\t// " + << RC.getName() << ':' << Idx.getName(); + + if (MatchingSubClass) { + CodeGenRegisterClass *SubRegClass = MatchingSubClass->second; + OS << " -> " << SubRegClass->getName(); + } + + OS << '\n'; + } + + OS << " },\n"; + } + OS << " };\n assert(RC && \"Missing regclass\");\n" + << " if (!Idx) return RC;\n --Idx;\n" + << " assert(Idx < " << SubRegIndicesSize << " && \"Bad subreg\");\n" + << " unsigned TV = Table[RC->getID()][Idx];\n" + << " return TV ? getRegClass(TV - 1) : nullptr;\n}\n\n"; } EmitRegUnitPressure(OS, RegBank, ClassName); + // Emit register base class mapper + if (!RegisterClasses.empty()) { + // Collect base classes + SmallVector<const CodeGenRegisterClass*> BaseClasses; + for (const auto &RC : RegisterClasses) { + if (RC.getBaseClassOrder()) + BaseClasses.push_back(&RC); + } + if (!BaseClasses.empty()) { + // Represent class indexes with uint8_t and allocate one index for nullptr + assert(BaseClasses.size() <= UINT8_MAX && "Too many base register classes"); + + // Apply order + struct BaseClassOrdering { + bool operator()(const CodeGenRegisterClass *LHS, const CodeGenRegisterClass *RHS) const { + return std::pair(*LHS->getBaseClassOrder(), LHS->EnumValue) + < std::pair(*RHS->getBaseClassOrder(), RHS->EnumValue); + } + }; + llvm::stable_sort(BaseClasses, BaseClassOrdering()); + + // Build mapping for Regs (+1 for NoRegister) + std::vector<uint8_t> Mapping(Regs.size() + 1, 0); + for (int RCIdx = BaseClasses.size() - 1; RCIdx >= 0; --RCIdx) { + for (const auto Reg : BaseClasses[RCIdx]->getMembers()) + Mapping[Reg->EnumValue] = RCIdx + 1; + } + + OS << "\n// Register to base register class mapping\n\n"; + OS << "\n"; + OS << "const TargetRegisterClass *" << ClassName + << "::getPhysRegBaseClass(MCRegister Reg)" + << " const {\n"; + OS << " static const TargetRegisterClass *BaseClasses[" << (BaseClasses.size() + 1) << "] = {\n"; + OS << " nullptr,\n"; + for (const auto RC : BaseClasses) + OS << " &" << RC->getQualifiedName() << "RegClass,\n"; + OS << " };\n"; + OS << " static const uint8_t Mapping[" << Mapping.size() << "] = {\n "; + for (const uint8_t Value : Mapping) + OS << (unsigned)Value << ","; + OS << " };\n\n"; + OS << " assert(Reg < sizeof(Mapping));\n"; + OS << " return BaseClasses[Mapping[Reg]];\n"; + OS << "}\n"; + } + } + // Emit the constructor of the class... OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n"; OS << "extern const MCPhysReg " << TargetName << "RegDiffLists[];\n"; @@ -1614,6 +1717,15 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, ArrayRef<Record*>(OPSet.begin(), OPSet.end())); } + // Add all constant physical registers to the preserved mask: + SetTheory::RecSet ConstantSet; + for (auto &Reg : RegBank.getRegisters()) { + if (Reg.Constant) + ConstantSet.insert(Reg.TheDef); + } + Covered |= RegBank.computeCoveredRegisters( + ArrayRef<Record *>(ConstantSet.begin(), ConstantSet.end())); + OS << "static const uint32_t " << CSRSet->getName() << "_RegMask[] = { "; printBitVectorAsHex(OS, Covered, 32); @@ -1628,9 +1740,9 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, for (Record *CSRSet : CSRSets) OS << " " << CSRSet->getName() << "_RegMask,\n"; OS << " };\n"; - OS << " return makeArrayRef(Masks);\n"; + OS << " return ArrayRef(Masks);\n"; } else { - OS << " return None;\n"; + OS << " return std::nullopt;\n"; } OS << "}\n\n"; @@ -1678,6 +1790,15 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, OS << " false;\n"; OS << "}\n\n"; + OS << "bool " << ClassName << "::\n" + << "isConstantPhysReg(MCRegister PhysReg) const {\n" + << " return\n"; + for (const auto &Reg : Regs) + if (Reg.Constant) + OS << " PhysReg == " << getQualifiedName(Reg.TheDef) << " ||\n"; + OS << " false;\n"; + OS << "}\n\n"; + OS << "ArrayRef<const char *> " << ClassName << "::getRegMaskNames() const {\n"; if (!CSRSets.empty()) { @@ -1685,9 +1806,9 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, for (Record *CSRSet : CSRSets) OS << " " << '"' << CSRSet->getName() << '"' << ",\n"; OS << " };\n"; - OS << " return makeArrayRef(Names);\n"; + OS << " return ArrayRef(Names);\n"; } else { - OS << " return None;\n"; + OS << " return std::nullopt;\n"; } OS << "}\n\n"; @@ -1767,6 +1888,7 @@ void RegisterInfoEmitter::debugDump(raw_ostream &OS) { OS << "SubRegIndex " << SRI.getName() << ":\n"; OS << "\tLaneMask: " << PrintLaneMask(SRI.LaneMask) << '\n'; OS << "\tAllSuperRegsCovered: " << SRI.AllSuperRegsCovered << '\n'; + OS << "\tOffset, Size: " << SRI.Offset << ", " << SRI.Size << '\n'; } for (const CodeGenRegister &R : RegBank.getRegisters()) { diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp index 327c53e93a41..c88a2db55502 100644 --- a/llvm/utils/TableGen/SearchableTableEmitter.cpp +++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp @@ -378,7 +378,7 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, } if (IsContiguous) { - OS << " auto Table = makeArrayRef(" << IndexName << ");\n"; + OS << " auto Table = ArrayRef(" << IndexName << ");\n"; OS << " size_t Idx = " << Index.Fields[0].Name << ";\n"; OS << " return Idx >= Table.size() ? nullptr : "; if (IsPrimary) @@ -423,7 +423,7 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, } OS << "};\n"; - OS << " auto Table = makeArrayRef(" << IndexName << ");\n"; + OS << " auto Table = ArrayRef(" << IndexName << ");\n"; OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n"; OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n"; @@ -574,7 +574,7 @@ std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex( void SearchableTableEmitter::collectEnumEntries( GenericEnum &Enum, StringRef NameField, StringRef ValueField, const std::vector<Record *> &Items) { - for (auto EntryRec : Items) { + for (auto *EntryRec : Items) { StringRef Name; if (NameField.empty()) Name = EntryRec->getName(); @@ -607,7 +607,7 @@ void SearchableTableEmitter::collectTableEntries( PrintFatalError(Table.Locs, Twine("Table '") + Table.Name + "' has no entries"); - for (auto EntryRec : Items) { + for (auto *EntryRec : Items) { for (auto &Field : Table.Fields) { auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name)); if (!TI || !TI->isComplete()) { @@ -662,7 +662,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) { DenseMap<Record *, GenericTable *> TableMap; // Collect all definitions first. - for (auto EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) { + for (auto *EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) { StringRef NameField; if (!EnumRec->isValueUnset("NameField")) NameField = EnumRec->getValueAsString("NameField"); @@ -688,7 +688,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) { Enums.emplace_back(std::move(Enum)); } - for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) { + for (auto *TableRec : Records.getAllDerivedDefinitions("GenericTable")) { auto Table = std::make_unique<GenericTable>(); Table->Name = std::string(TableRec->getName()); Table->Locs = TableRec->getLoc(); diff --git a/llvm/utils/TableGen/SequenceToOffsetTable.h b/llvm/utils/TableGen/SequenceToOffsetTable.h index 1b3451c24cb0..77a404d07b7d 100644 --- a/llvm/utils/TableGen/SequenceToOffsetTable.h +++ b/llvm/utils/TableGen/SequenceToOffsetTable.h @@ -26,48 +26,6 @@ namespace llvm { extern llvm::cl::opt<bool> EmitLongStrLiterals; -// Helper function for SequenceToOffsetTable<string>. -static inline void printStrLitEscChar(raw_ostream &OS, char C) { - const char *Escapes[] = { - "\\000", "\\001", "\\002", "\\003", "\\004", "\\005", "\\006", "\\007", - "\\010", "\\t", "\\n", "\\013", "\\014", "\\r", "\\016", "\\017", - "\\020", "\\021", "\\022", "\\023", "\\024", "\\025", "\\026", "\\027", - "\\030", "\\031", "\\032", "\\033", "\\034", "\\035", "\\036", "\\037", - " ", "!", "\\\"", "#", "$", "%", "&", "'", - "(", ")", "*", "+", ",", "-", ".", "/", - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", ":", ";", "<", "=", ">", "?", - "@", "A", "B", "C", "D", "E", "F", "G", - "H", "I", "J", "K", "L", "M", "N", "O", - "P", "Q", "R", "S", "T", "U", "V", "W", - "X", "Y", "Z", "[", "\\\\", "]", "^", "_", - "`", "a", "b", "c", "d", "e", "f", "g", - "h", "i", "j", "k", "l", "m", "n", "o", - "p", "q", "r", "s", "t", "u", "v", "w", - "x", "y", "z", "{", "|", "}", "~", "\\177", - "\\200", "\\201", "\\202", "\\203", "\\204", "\\205", "\\206", "\\207", - "\\210", "\\211", "\\212", "\\213", "\\214", "\\215", "\\216", "\\217", - "\\220", "\\221", "\\222", "\\223", "\\224", "\\225", "\\226", "\\227", - "\\230", "\\231", "\\232", "\\233", "\\234", "\\235", "\\236", "\\237", - "\\240", "\\241", "\\242", "\\243", "\\244", "\\245", "\\246", "\\247", - "\\250", "\\251", "\\252", "\\253", "\\254", "\\255", "\\256", "\\257", - "\\260", "\\261", "\\262", "\\263", "\\264", "\\265", "\\266", "\\267", - "\\270", "\\271", "\\272", "\\273", "\\274", "\\275", "\\276", "\\277", - "\\300", "\\301", "\\302", "\\303", "\\304", "\\305", "\\306", "\\307", - "\\310", "\\311", "\\312", "\\313", "\\314", "\\315", "\\316", "\\317", - "\\320", "\\321", "\\322", "\\323", "\\324", "\\325", "\\326", "\\327", - "\\330", "\\331", "\\332", "\\333", "\\334", "\\335", "\\336", "\\337", - "\\340", "\\341", "\\342", "\\343", "\\344", "\\345", "\\346", "\\347", - "\\350", "\\351", "\\352", "\\353", "\\354", "\\355", "\\356", "\\357", - "\\360", "\\361", "\\362", "\\363", "\\364", "\\365", "\\366", "\\367", - "\\370", "\\371", "\\372", "\\373", "\\374", "\\375", "\\376", "\\377"}; - - static_assert(sizeof Escapes / sizeof Escapes[0] == - std::numeric_limits<unsigned char>::max() + 1, - "unsupported character type"); - OS << Escapes[static_cast<unsigned char>(C)]; -} - static inline void printChar(raw_ostream &OS, char C) { unsigned char UC(C); if (isalnum(UC) || ispunct(UC)) { @@ -184,9 +142,7 @@ public: << Decl << " = {\n"; for (auto I : Seqs) { OS << " /* " << I.second << " */ \""; - for (auto C : I.first) { - printStrLitEscChar(OS, C); - } + OS.write_escaped(I.first); OS << "\\0\"\n"; } OS << "};\n" diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index 88827607b517..8afe6d37d0e0 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenTarget.h" #include "CodeGenSchedule.h" +#include "CodeGenTarget.h" #include "PredicateExpander.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" @@ -1862,7 +1862,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { if (NumFeatures) OS << Target << "FeatureKV, "; else - OS << "None, "; + OS << "std::nullopt, "; if (NumProcs) OS << Target << "SubTypeKV, "; else @@ -1953,11 +1953,11 @@ void SubtargetEmitter::run(raw_ostream &OS) { << "StringRef TuneCPU, StringRef FS)\n" << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, "; if (NumFeatures) - OS << "makeArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), "; + OS << "ArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), "; else - OS << "None, "; + OS << "std::nullopt, "; if (NumProcs) - OS << "makeArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), "; + OS << "ArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), "; else OS << "None, "; OS << '\n'; OS.indent(24); diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp index efd641887232..746e2dd1db16 100644 --- a/llvm/utils/TableGen/TableGen.cpp +++ b/llvm/utils/TableGen/TableGen.cpp @@ -58,6 +58,7 @@ enum ActionType { GenDirectivesEnumDecl, GenDirectivesEnumImpl, GenDXILOperation, + GenRISCVTargetDef, }; namespace llvm { @@ -141,8 +142,9 @@ cl::opt<ActionType> Action( clEnumValN(GenDirectivesEnumImpl, "gen-directive-impl", "Generate directive related implementation code"), clEnumValN(GenDXILOperation, "gen-dxil-operation", - "Generate DXIL operation information"))); - + "Generate DXIL operation information"), + clEnumValN(GenRISCVTargetDef, "gen-riscv-target-def", + "Generate the list of CPU for RISCV"))); cl::OptionCategory PrintEnumsCat("Options for -print-enums"); cl::opt<std::string> Class("class", cl::desc("Print Enum list for this class"), cl::value_desc("class name"), @@ -278,6 +280,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenDXILOperation: EmitDXILOperation(Records, OS); break; + case GenRISCVTargetDef: + EmitRISCVTargetDef(Records, OS); + break; } return false; diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h index 4dff13095696..ac44babb1261 100644 --- a/llvm/utils/TableGen/TableGenBackends.h +++ b/llvm/utils/TableGen/TableGenBackends.h @@ -94,6 +94,7 @@ void EmitAutomata(RecordKeeper &RK, raw_ostream &OS); void EmitDirectivesDecl(RecordKeeper &RK, raw_ostream &OS); void EmitDirectivesImpl(RecordKeeper &RK, raw_ostream &OS); void EmitDXILOperation(RecordKeeper &RK, raw_ostream &OS); +void EmitRISCVTargetDef(const RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp index a6bbe2f7ff37..2c1acd8d910c 100644 --- a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp +++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp @@ -83,9 +83,35 @@ public: void run(raw_ostream &OS); }; - } // end anonymous namespace +// Get the name of custom encoder or decoder, if there is any. +// Returns `{encoder name, decoder name}`. +static std::pair<StringRef, StringRef> getCustomCoders(ArrayRef<Init *> Args) { + std::pair<StringRef, StringRef> Result; + for (const auto *Arg : Args) { + const auto *DI = dyn_cast<DagInit>(Arg); + if (!DI) + continue; + const Init *Op = DI->getOperator(); + if (!isa<DefInit>(Op)) + continue; + // syntax: `(<encoder | decoder> "function name")` + StringRef OpName = cast<DefInit>(Op)->getDef()->getName(); + if (OpName != "encoder" && OpName != "decoder") + continue; + if (!DI->getNumArgs() || !isa<StringInit>(DI->getArg(0))) + PrintFatalError("expected '" + OpName + + "' directive to be followed by a custom function name."); + StringRef FuncName = cast<StringInit>(DI->getArg(0))->getValue(); + if (OpName == "encoder") + Result.first = FuncName; + else + Result.second = FuncName; + } + return Result; +} + VarLenInst::VarLenInst(const DagInit *DI, const RecordVal *TheDef) : TheDef(TheDef), NumBits(0U) { buildRec(DI); @@ -123,7 +149,8 @@ void VarLenInst::buildRec(const DagInit *DI) { } } } else if (Op == "operand") { - // (operand <operand name>, <# of bits>, [(encoder <custom encoder>)]) + // (operand <operand name>, <# of bits>, + // [(encoder <custom encoder>)][, (decoder <custom decoder>)]) if (DI->getNumArgs() < 2) PrintFatalError(TheDef->getLoc(), "Expecting at least 2 arguments for `operand`"); @@ -136,14 +163,13 @@ void VarLenInst::buildRec(const DagInit *DI) { if (NumBitsVal <= 0) PrintFatalError(TheDef->getLoc(), "Invalid number of bits for `operand`"); - StringRef CustomEncoder; - if (DI->getNumArgs() >= 3) - CustomEncoder = getCustomEncoderName(DI->getArg(2)); - Segments.push_back( - {static_cast<unsigned>(NumBitsVal), OperandName, CustomEncoder}); + auto [CustomEncoder, CustomDecoder] = + getCustomCoders(DI->getArgs().slice(2)); + Segments.push_back({static_cast<unsigned>(NumBitsVal), OperandName, + CustomEncoder, CustomDecoder}); } else if (Op == "slice") { // (slice <operand name>, <high / low bit>, <low / high bit>, - // [(encoder <custom encoder>)]) + // [(encoder <custom encoder>)][, (decoder <custom decoder>)]) if (DI->getNumArgs() < 3) PrintFatalError(TheDef->getLoc(), "Expecting at least 3 arguments for `slice`"); @@ -167,18 +193,17 @@ void VarLenInst::buildRec(const DagInit *DI) { NumBits = static_cast<unsigned>(HiBitVal - LoBitVal + 1); } - StringRef CustomEncoder; - if (DI->getNumArgs() >= 4) - CustomEncoder = getCustomEncoderName(DI->getArg(3)); + auto [CustomEncoder, CustomDecoder] = + getCustomCoders(DI->getArgs().slice(3)); if (NeedSwap) { // Normalization: Hi bit should always be the second argument. Init *const NewArgs[] = {OperandName, LoBit, HiBit}; Segments.push_back({NumBits, DagInit::get(DI->getOperator(), nullptr, NewArgs, {}), - CustomEncoder}); + CustomEncoder, CustomDecoder}); } else { - Segments.push_back({NumBits, DI, CustomEncoder}); + Segments.push_back({NumBits, DI, CustomEncoder, CustomDecoder}); } } } @@ -449,7 +474,8 @@ std::string VarLenCodeEmitterGen::getInstructionCaseForEncoding( auto OpIdx = CGI.Operands.ParseOperandName(OperandName); unsigned FlatOpIdx = CGI.Operands.getFlattenedOperandNumber(OpIdx); - StringRef CustomEncoder = CGI.Operands[OpIdx.first].EncoderMethodName; + StringRef CustomEncoder = + CGI.Operands[OpIdx.first].EncoderMethodNames[OpIdx.second]; if (ES.CustomEncoder.size()) CustomEncoder = ES.CustomEncoder; diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.h b/llvm/utils/TableGen/VarLenCodeEmitterGen.h index 5bdedee1dd51..2b55fd1720aa 100644 --- a/llvm/utils/TableGen/VarLenCodeEmitterGen.h +++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.h @@ -22,6 +22,7 @@ struct EncodingSegment { unsigned BitWidth; const Init *Value; StringRef CustomEncoder = ""; + StringRef CustomDecoder = ""; }; class VarLenInst { @@ -35,14 +36,6 @@ class VarLenInst { void buildRec(const DagInit *DI); - StringRef getCustomEncoderName(const Init *EI) const { - if (const auto *DI = dyn_cast<DagInit>(EI)) { - if (DI->getNumArgs() && isa<StringInit>(DI->getArg(0))) - return cast<StringInit>(DI->getArg(0))->getValue(); - } - return ""; - } - public: VarLenInst() : TheDef(nullptr), NumBits(0U), HasDynamicSegment(false) {} diff --git a/llvm/utils/TableGen/X86DisassemblerTables.cpp b/llvm/utils/TableGen/X86DisassemblerTables.cpp index 2fa8fce81422..601591d9f53d 100644 --- a/llvm/utils/TableGen/X86DisassemblerTables.cpp +++ b/llvm/utils/TableGen/X86DisassemblerTables.cpp @@ -16,7 +16,6 @@ #include "X86DisassemblerTables.h" #include "X86DisassemblerShared.h" #include "X86ModRMFilters.h" -#include "llvm/ADT/STLArrayExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" @@ -653,7 +652,7 @@ static const char* stringForDecisionType(ModRMDecisionType dt) { } DisassemblerTables::DisassemblerTables() { - for (unsigned i = 0; i < llvm::array_lengthof(Tables); i++) + for (unsigned i = 0; i < std::size(Tables); i++) Tables[i] = std::make_unique<ContextDecision>(); HasConflicts = false; @@ -763,7 +762,7 @@ void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2, } if (index == 256) { // If all 256 entries are MODRM_ONEENTRY, omit output. - static_assert(MODRM_ONEENTRY == 0, ""); + static_assert(MODRM_ONEENTRY == 0); --i2; o2 << "},\n"; } else { diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp index 9afde66fe6f3..e5c1e53936f6 100644 --- a/llvm/utils/TableGen/X86RecognizableInstr.cpp +++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp @@ -546,6 +546,18 @@ void RecognizableInstr::emitInstructionSpecifier() { HANDLE_OPERAND(roRegister) HANDLE_OPTIONAL(immediate) break; + case X86Local::MRMDestMem4VOp3CC: + // Operand 1 is a register operand in the Reg/Opcode field. + // Operand 2 is a register operand in the R/M field. + // Operand 3 is VEX.vvvv + // Operand 4 is condition code. + assert(numPhysicalOperands == 4 && + "Unexpected number of operands for MRMDestMem4VOp3CC"); + HANDLE_OPERAND(roRegister) + HANDLE_OPERAND(memory) + HANDLE_OPERAND(vvvvRegister) + HANDLE_OPERAND(opcodeModifier) + break; case X86Local::MRMDestMem: case X86Local::MRMDestMemFSIB: // Operand 1 is a memory operand (possibly SIB-extended) @@ -767,7 +779,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { #define MAP(from, to) \ case X86Local::MRM_##from: - llvm::Optional<OpcodeType> opcodeType; + std::optional<OpcodeType> opcodeType; switch (OpMap) { default: llvm_unreachable("Invalid map!"); case X86Local::OB: opcodeType = ONEBYTE; break; @@ -808,6 +820,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { filter = std::make_unique<ModFilter>(true); break; case X86Local::MRMDestMem: + case X86Local::MRMDestMem4VOp3CC: case X86Local::MRMDestMemFSIB: case X86Local::MRMSrcMem: case X86Local::MRMSrcMemFSIB: @@ -858,7 +871,8 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { if (Form == X86Local::AddRegFrm || Form == X86Local::MRMSrcRegCC || Form == X86Local::MRMSrcMemCC || Form == X86Local::MRMXrCC || - Form == X86Local::MRMXmCC || Form == X86Local::AddCCFrm) { + Form == X86Local::MRMXmCC || Form == X86Local::AddCCFrm || + Form == X86Local::MRMDestMem4VOp3CC) { uint8_t Count = Form == X86Local::AddRegFrm ? 8 : 16; assert(((opcodeToSet % Count) == 0) && "ADDREG_FRM opcode not aligned"); diff --git a/llvm/utils/TableGen/X86RecognizableInstr.h b/llvm/utils/TableGen/X86RecognizableInstr.h index 67aba26a142b..ea56a9d7d994 100644 --- a/llvm/utils/TableGen/X86RecognizableInstr.h +++ b/llvm/utils/TableGen/X86RecognizableInstr.h @@ -106,6 +106,7 @@ namespace X86Local { RawFrmImm16 = 8, AddCCFrm = 9, PrefixByte = 10, + MRMDestMem4VOp3CC = 20, MRMr0 = 21, MRMSrcMemFSIB = 22, MRMDestMemFSIB = 23, diff --git a/llvm/utils/split-file/split-file.cpp b/llvm/utils/split-file/split-file.cpp new file mode 100644 index 000000000000..4a92c1be78a2 --- /dev/null +++ b/llvm/utils/split-file/split-file.cpp @@ -0,0 +1,178 @@ +//===- split-file.cpp - Input splitting utility ---------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Split input into multipe parts separated by regex '^(.|//)--- ' and extract +// the specified part. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/LineIterator.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/WithColor.h" +#include <string> +#include <system_error> + +using namespace llvm; + +static cl::OptionCategory cat("split-file Options"); + +static cl::opt<std::string> input(cl::Positional, cl::desc("filename"), + cl::cat(cat)); + +static cl::opt<std::string> output(cl::Positional, cl::desc("directory"), + cl::value_desc("directory"), cl::cat(cat)); + +static cl::opt<bool> leadingLines("leading-lines", + cl::desc("Preserve line numbers"), + cl::cat(cat)); + +static cl::opt<bool> noLeadingLines("no-leading-lines", + cl::desc("Don't preserve line numbers (default)"), + cl::cat(cat)); + +static StringRef toolName; +static int errorCount; + +[[noreturn]] static void fatal(StringRef filename, const Twine &message) { + if (filename.empty()) + WithColor::error(errs(), toolName) << message << '\n'; + else + WithColor::error(errs(), toolName) << filename << ": " << message << '\n'; + exit(1); +} + +static void error(StringRef filename, int64_t line, const Twine &message) { + ++errorCount; + errs() << filename << ':' << line << ": "; + WithColor::error(errs()) << message << '\n'; +} + +namespace { +struct Part { + const char *begin = nullptr; + const char *end = nullptr; + int64_t leadingLines = 0; +}; +} // namespace + +static int handle(MemoryBuffer &inputBuf, StringRef input) { + DenseMap<StringRef, Part> partToBegin; + StringRef lastPart, separator; + StringRef EOL = inputBuf.getBuffer().detectEOL(); + for (line_iterator i(inputBuf, /*SkipBlanks=*/false, '\0'); !i.is_at_eof();) { + const int64_t lineNo = i.line_number(); + const StringRef line = *i++; + const size_t markerLen = line.startswith("//") ? 6 : 5; + if (!(line.size() >= markerLen && + line.substr(markerLen - 4).startswith("--- "))) + continue; + separator = line.substr(0, markerLen); + const StringRef partName = line.substr(markerLen); + if (partName.empty()) { + error(input, lineNo, "empty part name"); + continue; + } + if (isSpace(partName.front()) || isSpace(partName.back())) { + error(input, lineNo, "part name cannot have leading or trailing space"); + continue; + } + + auto res = partToBegin.try_emplace(partName); + if (!res.second) { + error(input, lineNo, + "'" + separator + partName + "' occurs more than once"); + continue; + } + if (!lastPart.empty()) + partToBegin[lastPart].end = line.data(); + Part &cur = res.first->second; + if (!i.is_at_eof()) + cur.begin = i->data(); + // If --leading-lines is specified, numEmptyLines is 0. Append newlines so + // that the extracted part preserves line numbers. + cur.leadingLines = leadingLines ? i.line_number() - 1 : 0; + + lastPart = partName; + } + if (lastPart.empty()) + fatal(input, "no part separator was found"); + if (errorCount) + return 1; + partToBegin[lastPart].end = inputBuf.getBufferEnd(); + + std::vector<std::unique_ptr<ToolOutputFile>> outputFiles; + SmallString<256> partPath; + for (auto &keyValue : partToBegin) { + partPath.clear(); + sys::path::append(partPath, output, keyValue.first); + std::error_code ec = + sys::fs::create_directories(sys::path::parent_path(partPath)); + if (ec) + fatal(input, ec.message()); + auto f = std::make_unique<ToolOutputFile>(partPath.str(), ec, + llvm::sys::fs::OF_None); + if (!f) + fatal(input, ec.message()); + + Part &part = keyValue.second; + for (int64_t i = 0; i != part.leadingLines; ++i) + (*f).os() << EOL; + if (part.begin) + (*f).os().write(part.begin, part.end - part.begin); + outputFiles.push_back(std::move(f)); + } + + for (std::unique_ptr<ToolOutputFile> &outputFile : outputFiles) + outputFile->keep(); + return 0; +} + +int main(int argc, const char **argv) { + toolName = sys::path::stem(argv[0]); + cl::HideUnrelatedOptions({&cat}); + cl::ParseCommandLineOptions( + argc, argv, + "Split input into multiple parts separated by regex '^(.|//)--- ' and " + "extract the part specified by '^(.|//)--- <part>'\n", + nullptr, + /*EnvVar=*/nullptr, + /*LongOptionsUseDoubleDash=*/true); + + if (input.empty()) + fatal("", "input filename is not specified"); + if (output.empty()) + fatal("", "output directory is not specified"); + ErrorOr<std::unique_ptr<MemoryBuffer>> bufferOrErr = + MemoryBuffer::getFileOrSTDIN(input); + if (std::error_code ec = bufferOrErr.getError()) + fatal(input, ec.message()); + + // Delete output if it is a file or an empty directory, so that we can create + // a directory. + sys::fs::file_status status; + if (std::error_code ec = sys::fs::status(output, status)) + if (ec.value() != static_cast<int>(std::errc::no_such_file_or_directory)) + fatal(output, ec.message()); + if (status.type() != sys::fs::file_type::file_not_found && + status.type() != sys::fs::file_type::directory_file && + status.type() != sys::fs::file_type::regular_file) + fatal(output, "output cannot be a special file"); + if (std::error_code ec = sys::fs::remove(output, /*IgnoreNonExisting=*/true)) + if (ec.value() != static_cast<int>(std::errc::directory_not_empty) && + ec.value() != static_cast<int>(std::errc::file_exists)) + fatal(output, ec.message()); + return handle(**bufferOrErr, input); +} |