Index: include/llvm/CodeGen/GlobalISel/InstructionSelector.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -17,20 +17,48 @@ #define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H #include +#include namespace llvm { class MachineInstr; +class MachineFunction; class MachineOperand; class MachineRegisterInfo; class RegisterBankInfo; class TargetInstrInfo; class TargetRegisterInfo; +/// Container class for CodeGen predicate results. +/// This is convenient because std::bitset does not have a constructor +/// with an initializer list of set bits. +/// +/// Each InstructionSelector subclass should define a PredicateBitset class with: +/// const unsigned MAX_SUBTARGET_PREDICATES = 192; +/// using PredicateBitset = PredicateBitsetImpl; +/// and updating the constant to suit the target. +template +class PredicateBitsetImpl : public std::bitset { +public: + // Cannot inherit constructors because it's not supported by VC++.. + PredicateBitsetImpl() = default; + + PredicateBitsetImpl(const std::bitset &B) + : std::bitset(B) {} + + PredicateBitsetImpl(std::initializer_list Init) { + for (auto I : Init) + std::bitset::set(I); + } +}; + /// Provides the logic to select generic machine instructions. class InstructionSelector { public: virtual ~InstructionSelector() {} + /// This is executed before selecting a function. + virtual void beginFunction(const MachineFunction &MF) {} + /// Select the (possibly generic) instruction \p I to only use target-specific /// opcodes. It is OK to insert multiple instructions, but they cannot be /// generic pre-isel instructions. Index: include/llvm/Target/GlobalISel/Target.td =================================================================== --- include/llvm/Target/GlobalISel/Target.td +++ include/llvm/Target/GlobalISel/Target.td @@ -154,10 +154,14 @@ // === Rules === // Defines a GlobalISel matcher rule. -class GIRule insnmatchers, list actions> { +class GIRule insnmatchers, list actions, + list predicates = []> { // A list of instruction matchers. These form the roots of the match. list InsnMatchers = insnmatchers; // A list of actions to take in response to the rule. list Actions = actions; + + // A list of predicates that must be satisfied for the rule to be attempted. + list Predicates = predicates; } Index: lib/Target/AArch64/AArch64InstructionSelector.h =================================================================== --- lib/Target/AArch64/AArch64InstructionSelector.h +++ lib/Target/AArch64/AArch64InstructionSelector.h @@ -31,12 +31,16 @@ class MachineFunction; class MachineRegisterInfo; +const unsigned MAX_SUBTARGET_PREDICATES = 32; +using PredicateBitset = PredicateBitsetImpl; + class AArch64InstructionSelector : public InstructionSelector { public: AArch64InstructionSelector(const AArch64TargetMachine &TM, const AArch64Subtarget &STI, const AArch64RegisterBankInfo &RBI); + void beginFunction(const MachineFunction &MF) override; bool select(MachineInstr &I) const override; private: @@ -57,6 +61,13 @@ const AArch64InstrInfo &TII; const AArch64RegisterInfo &TRI; const AArch64RegisterBankInfo &RBI; + bool ForCodeSize; + + PredicateBitset AvailableFeatures; + PredicateBitset getAvailableFeatures() const { return AvailableFeatures; } + PredicateBitset + computeAvailableFeatures(const MachineFunction *MF, + const AArch64Subtarget *Subtarget) const; // We declare the temporaries used by selectImpl() in the class to minimize the // cost of constructing placeholder values. Index: lib/Target/AArch64/AArch64InstructionSelector.cpp =================================================================== --- lib/Target/AArch64/AArch64InstructionSelector.cpp +++ lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -45,7 +45,7 @@ const AArch64TargetMachine &TM, const AArch64Subtarget &STI, const AArch64RegisterBankInfo &RBI) : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()), - TRI(*STI.getRegisterInfo()), RBI(RBI) + TRI(*STI.getRegisterInfo()), RBI(RBI), ForCodeSize(), AvailableFeatures() #define GET_GLOBALISEL_TEMPORARIES_INIT #include "AArch64GenGlobalISel.inc" #undef GET_GLOBALISEL_TEMPORARIES_INIT @@ -480,6 +480,12 @@ return true; } +void AArch64InstructionSelector::beginFunction( + const MachineFunction &MF) { + ForCodeSize = MF.getFunction()->optForSize(); + AvailableFeatures = computeAvailableFeatures(&MF, &STI); +} + bool AArch64InstructionSelector::select(MachineInstr &I) const { assert(I.getParent() && "Instruction should be in a basic block!"); assert(I.getParent()->getParent() && "Instruction should be in a function!"); Index: lib/Target/X86/X86InstructionSelector.h =================================================================== --- lib/Target/X86/X86InstructionSelector.h +++ lib/Target/X86/X86InstructionSelector.h @@ -29,11 +29,15 @@ class MachineRegisterInfo; class MachineFunction; +const unsigned MAX_SUBTARGET_PREDICATES = 192; +using PredicateBitset = PredicateBitsetImpl; + class X86InstructionSelector : public InstructionSelector { public: - X86InstructionSelector(const X86Subtarget &STI, + X86InstructionSelector(const X86TargetMachine &TM, const X86Subtarget &STI, const X86RegisterBankInfo &RBI); + void beginFunction(const MachineFunction &MF) override; bool select(MachineInstr &I) const override; private: @@ -54,10 +58,18 @@ bool selectLoadStoreOp(MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) const; + const X86TargetMachine &TM; const X86Subtarget &STI; const X86InstrInfo &TII; const X86RegisterInfo &TRI; const X86RegisterBankInfo &RBI; + bool OptForSize; + bool OptForMinSize; + + PredicateBitset AvailableFeatures; + PredicateBitset getAvailableFeatures() const { return AvailableFeatures; } + PredicateBitset computeAvailableFeatures(const MachineFunction *MF, + const X86Subtarget *Subtarget) const; #define GET_GLOBALISEL_TEMPORARIES_DECL #include "X86GenGlobalISel.inc" Index: lib/Target/X86/X86InstructionSelector.cpp =================================================================== --- lib/Target/X86/X86InstructionSelector.cpp +++ lib/Target/X86/X86InstructionSelector.cpp @@ -40,10 +40,12 @@ #include "X86GenGlobalISel.inc" #undef GET_GLOBALISEL_IMPL -X86InstructionSelector::X86InstructionSelector(const X86Subtarget &STI, +X86InstructionSelector::X86InstructionSelector(const X86TargetMachine &TM, + const X86Subtarget &STI, const X86RegisterBankInfo &RBI) - : InstructionSelector(), STI(STI), TII(*STI.getInstrInfo()), - TRI(*STI.getRegisterInfo()), RBI(RBI) + : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()), + TRI(*STI.getRegisterInfo()), RBI(RBI), OptForSize(false), + OptForMinSize(false), AvailableFeatures() #define GET_GLOBALISEL_TEMPORARIES_INIT #include "X86GenGlobalISel.inc" #undef GET_GLOBALISEL_TEMPORARIES_INIT @@ -131,6 +133,12 @@ return true; } +void X86InstructionSelector::beginFunction(const MachineFunction &MF) { + OptForSize = MF.getFunction()->optForSize(); + OptForMinSize = MF.getFunction()->optForMinSize(); + AvailableFeatures = computeAvailableFeatures(&MF, &STI); +} + bool X86InstructionSelector::select(MachineInstr &I) const { assert(I.getParent() && "Instruction should be in a basic block!"); assert(I.getParent()->getParent() && "Instruction should be in a function!"); Index: lib/Target/X86/X86TargetMachine.cpp =================================================================== --- lib/Target/X86/X86TargetMachine.cpp +++ lib/Target/X86/X86TargetMachine.cpp @@ -287,7 +287,7 @@ auto *RBI = new X86RegisterBankInfo(*I->getRegisterInfo()); GISel->RegBankInfo.reset(RBI); - GISel->InstSelector.reset(new X86InstructionSelector(*I, *RBI)); + GISel->InstSelector.reset(new X86InstructionSelector(*this, *I, *RBI)); #endif I->setGISelAccessor(*GISel); Index: test/TableGen/GlobalISelEmitter-GIRule.td =================================================================== --- test/TableGen/GlobalISelEmitter-GIRule.td +++ test/TableGen/GlobalISelEmitter-GIRule.td @@ -25,7 +25,31 @@ def m1 : OperandWithDefaultOps ; def Z : OperandWithDefaultOps ; -//===- Test the function definition boilerplate. --------------------------===// +def HasA : Predicate<"Subtarget->hasA()">; +def HasB : Predicate<"Subtarget->hasB()">; + +//===- Test the function boilerplate. -------------------------------------===// + +// CHECK-LABEL: enum SubtargetFeatureBits : uint8_t { +// CHECK-NEXT: Feature_HasABit = 0, +// CHECK-NEXT: Feature_HasBBit = 1, +// CHECK-NEXT: }; + +// CHECK-LABEL: static const char *SubtargetFeatureNames[] = { +// CHECK-NEXT: "Feature_HasA", +// CHECK-NEXT: "Feature_HasB", +// CHECK-NEXT: nullptr +// CHECK-NEXT: }; + +// CHECK-LABEL: PredicateBitset MyTargetInstructionSelector:: +// CHECK-NEXT: computeAvailableFeatures(const MachineFunction *MF, const MyTargetSubtarget *Subtarget) const { +// CHECK-NEXT: PredicateBitset Features; +// CHECK-NEXT: if (Subtarget->hasA()) +// CHECK-NEXT: Features[Feature_HasABit] = 1; +// CHECK-NEXT: if (Subtarget->hasB()) +// CHECK-NEXT: Features[Feature_HasBBit] = 1; +// CHECK-NEXT: return Features; +// CHECK-NEXT: } // CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I) const { // CHECK: MachineFunction &MF = *I.getParent()->getParent(); @@ -113,6 +137,9 @@ //===- Test a nested instruction match. -----------------------------------===// // CHECK-LABEL: if ([&]() { +// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit}; +// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures) +// CHECK-NEXT: return false; // CHECK-NEXT: MachineInstr &MI0 = I; // CHECK-NEXT: if (MI0.getNumOperands() < 3) // CHECK-NEXT: return false; @@ -150,6 +177,9 @@ // We also get a second rule by commutativity. // CHECK-LABEL: if ([&]() { +// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit}; +// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures) +// CHECK-NEXT: return false; // CHECK-NEXT: MachineInstr &MI0 = I; // CHECK-NEXT: if (MI0.getNumOperands() < 3) // CHECK-NEXT: return false; @@ -202,7 +232,7 @@ GICopyOperand<"src1">, GICopyOperand<"src2">, GICopyOperand<"src3">]> - ]>; + ], [HasA]>; // Commutativity is manual at the moment. def Rule3X: GIRule< @@ -220,11 +250,14 @@ GICopyOperand<"src1">, GICopyOperand<"src2">, GICopyOperand<"src3">]> - ]>; + ], [HasA]>; //===- Test another simple pattern with regclass operands. ----------------===// // CHECK-LABEL: if ([&]() { +// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit, Feature_HasBBit}; +// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures) +// CHECK-NEXT: return false; // CHECK-NEXT: MachineInstr &MI0 = I; // CHECK-NEXT: if (MI0.getNumOperands() < 3) // CHECK-NEXT: return false; @@ -257,7 +290,8 @@ GIMatchOperand<"src1", [GIMatchLLT, GIMatchRegBankForClass]>, GIMatchOperand<"src2", [GIMatchLLT, GIMatchRegBankForClass]>]> ], - [GIBuildMI, GICopyOperand<"src2">, GICopyOperand<"src1">]>]>; + [GIBuildMI, GICopyOperand<"src2">, GICopyOperand<"src1">]>], + [HasA, HasB]>; //===- Test a pattern with ComplexPattern operands. -----------------------===// // Index: test/TableGen/GlobalISelEmitter.td =================================================================== --- test/TableGen/GlobalISelEmitter.td +++ test/TableGen/GlobalISelEmitter.td @@ -28,7 +28,31 @@ def m1 : OperandWithDefaultOps ; def Z : OperandWithDefaultOps ; -//===- Test the function definition boilerplate. --------------------------===// +def HasA : Predicate<"Subtarget->hasA()">; +def HasB : Predicate<"Subtarget->hasB()">; + +//===- Test the function boilerplate. -------------------------------------===// + +// CHECK-LABEL: enum SubtargetFeatureBits : uint8_t { +// CHECK-NEXT: Feature_HasABit = 0, +// CHECK-NEXT: Feature_HasBBit = 1, +// CHECK-NEXT: }; + +// CHECK-LABEL: static const char *SubtargetFeatureNames[] = { +// CHECK-NEXT: "Feature_HasA", +// CHECK-NEXT: "Feature_HasB", +// CHECK-NEXT: nullptr +// CHECK-NEXT: }; + +// CHECK-LABEL: PredicateBitset MyTargetInstructionSelector:: +// CHECK-NEXT: computeAvailableFeatures(const MachineFunction *MF, const MyTargetSubtarget *Subtarget) const { +// CHECK-NEXT: PredicateBitset Features; +// CHECK-NEXT: if (Subtarget->hasA()) +// CHECK-NEXT: Features[Feature_HasABit] = 1; +// CHECK-NEXT: if (Subtarget->hasB()) +// CHECK-NEXT: Features[Feature_HasBBit] = 1; +// CHECK-NEXT: return Features; +// CHECK-NEXT: } // CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I) const { // CHECK: MachineFunction &MF = *I.getParent()->getParent(); @@ -100,6 +124,9 @@ //===- Test a nested instruction match. -----------------------------------===// // CHECK-LABEL: if ([&]() { +// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit}; +// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures) +// CHECK-NEXT: return false; // CHECK-NEXT: MachineInstr &MI0 = I; // CHECK-NEXT: if (MI0.getNumOperands() < 3) // CHECK-NEXT: return false; @@ -137,6 +164,9 @@ // We also get a second rule by commutativity. // CHECK-LABEL: if ([&]() { +// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit}; +// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures) +// CHECK-NEXT: return false; // CHECK-NEXT: MachineInstr &MI0 = I; // CHECK-NEXT: if (MI0.getNumOperands() < 3) // CHECK-NEXT: return false; @@ -174,11 +204,15 @@ def MULADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3), [(set GPR32:$dst, - (mul (add GPR32:$src1, GPR32:$src2), GPR32:$src3))]>; + (mul (add GPR32:$src1, GPR32:$src2), GPR32:$src3))]>, + Requires<[HasA]>; //===- Test another simple pattern with regclass operands. ----------------===// // CHECK-LABEL: if ([&]() { +// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit, Feature_HasBBit}; +// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures) +// CHECK-NEXT: return false; // CHECK-NEXT: MachineInstr &MI0 = I; // CHECK-NEXT: if (MI0.getNumOperands() < 3) // CHECK-NEXT: return false; @@ -204,7 +238,8 @@ // CHECK-NEXT: }()) { return true; } def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1), - [(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>; + [(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>, + Requires<[HasA, HasB]>; //===- Test a pattern with ComplexPattern operands. -----------------------===// // Index: utils/TableGen/AsmMatcherEmitter.cpp =================================================================== --- utils/TableGen/AsmMatcherEmitter.cpp +++ utils/TableGen/AsmMatcherEmitter.cpp @@ -2858,7 +2858,7 @@ emitValidateOperandClass(Info, OS); // Emit the available features compute function. - SubtargetFeatureInfo::emitComputeAvailableFeatures( + SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( Info.Target.getName(), ClassName, "ComputeAvailableFeatures", Info.SubtargetFeatures, OS); Index: utils/TableGen/CodeEmitterGen.cpp =================================================================== --- utils/TableGen/CodeEmitterGen.cpp +++ utils/TableGen/CodeEmitterGen.cpp @@ -336,7 +336,7 @@ o << "#endif // NDEBUG\n"; // Emit the available features compute function. - SubtargetFeatureInfo::emitComputeAvailableFeatures( + SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( Target.getName(), "MCCodeEmitter", "computeAvailableFeatures", SubtargetFeatures, o); Index: utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- utils/TableGen/GlobalISelEmitter.cpp +++ utils/TableGen/GlobalISelEmitter.cpp @@ -31,6 +31,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenDAGPatterns.h" +#include "SubtargetFeatureInfo.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/SmallSet.h" @@ -161,20 +162,6 @@ return Explanation; } -static std::string explainRulePredicates(const ArrayRef Predicates) { - std::string Explanation = ""; - StringRef Separator = ""; - for (const auto *P : Predicates) { - Explanation += Separator; - - if (const DefInit *PDef = dyn_cast(P)) { - Explanation += PDef->getDef()->getName(); - } else - Explanation += ""; - } - return Explanation; -} - static bool isTrivialOperatorNode(const TreePatternNode *N, std::string &Explanation) { std::string Separator = ""; @@ -220,6 +207,8 @@ /// ID for the next instruction variable defined with defineInsnVar() unsigned NextInsnVarID; + std::vector RequiredFeatures; + public: RuleMatcher() : Matchers(), Actions(), InsnVariableNames(), NextInsnVarID(0) {} @@ -227,6 +216,7 @@ RuleMatcher &operator=(RuleMatcher &&Other) = default; InstructionMatcher &addInstructionMatcher(); + void addRequiredFeature(Record *Feature); template Kind &addAction(Args &&... args); @@ -237,7 +227,9 @@ void emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr); void emitTblgen(raw_ostream &OS, IndentStr Indent); - void emit(raw_ostream &OS); + void emit(raw_ostream &OS, + std::map + SubtargetFeatures); /// Compare the priority of this object and B. /// @@ -1216,6 +1208,10 @@ return *Matchers.back(); } +void RuleMatcher::addRequiredFeature(Record *Feature) { + RequiredFeatures.push_back(Feature); +} + template Kind &RuleMatcher::addAction(Args &&... args) { Actions.emplace_back(llvm::make_unique(std::forward(args)...)); @@ -1255,11 +1251,16 @@ OS << Indent << "], [\n"; for (const auto &Action : Actions) Action->emitTblgen(OS, Indent + 1); + OS << Indent << "], [\n"; + for (const auto &RequiredFeature : RequiredFeatures) + OS << Indent << " " << RequiredFeature->getName() << ","; OS << Indent << "]>\n"; OS << "#endif // 0\n"; } -void RuleMatcher::emit(raw_ostream &OS) { +void RuleMatcher::emit(raw_ostream &OS, + std::map + SubtargetFeatures) { if (Matchers.empty()) llvm_unreachable("Unexpected empty matcher!"); @@ -1273,7 +1274,22 @@ // %elt0(s32), %elt1(s32) = TGT_LOAD_PAIR %ptr // on some targets but we don't need to make use of that yet. assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet"); - OS << "if ([&]() {\n"; + + OS << "if ("; + OS << "[&]() {\n"; + if (!RequiredFeatures.empty()) { + OS << " PredicateBitset ExpectedFeatures = {"; + StringRef Separator = ""; + for (const auto &Predicate : RequiredFeatures) { + const auto &I = SubtargetFeatures.find(Predicate); + assert(I != SubtargetFeatures.end() && "Didn't import predicate?"); + OS << Separator << I->second.getEnumBitName(); + Separator = ", "; + } + OS << "};\n"; + OS << "if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)\n" + << " return false;\n"; + } emitCxxCaptureStmts(OS, "I"); @@ -1388,11 +1404,14 @@ /// GIComplexPatternEquiv. DenseMap ComplexPatternEquivs; + // Map of predicates to their subtarget features. + std::map SubtargetFeatures; + void gatherNodeEquivs(); const CodeGenInstruction *findNodeEquiv(Record *N) const; Expected importRulePredicates(RuleMatcher &M, - ArrayRef Predicates) const; + ArrayRef Predicates); Expected importSelDAGMatcher(InstructionMatcher &InsnMatcher, const TreePatternNode *Src) const; @@ -1424,6 +1443,8 @@ /// Analyze pattern \p P, returning a matcher for it if possible. /// Otherwise, return an Error explaining why we don't support it. Expected runOnPattern(const PatternToMatch &P); + + void declareSubtargetFeature(Record *Predicate); }; void GlobalISelEmitter::gatherNodeEquivs() { @@ -1457,10 +1478,13 @@ Expected GlobalISelEmitter::importRulePredicates(RuleMatcher &M, - ArrayRef Predicates) const { - if (!Predicates.empty()) - return failedImport("Pattern has a rule predicate (" + - explainRulePredicates(Predicates) + ")"); + ArrayRef Predicates) { + for (const Init *Predicate : Predicates) { + const DefInit *PredicateDef = static_cast(Predicate); + declareSubtargetFeature(PredicateDef->getDef()); + M.addRequiredFeature(PredicateDef->getDef()); + } + return true; } @@ -1782,6 +1806,8 @@ " => " + llvm::to_string(*P.getDstPattern())); + // Import any rule predicates for the rule. We do this last so that rejected + // rules don't use up precious feature bits. auto TrueOrError = importRulePredicates(M, P.getPredicates()->getValues()); if (auto Error = TrueOrError.takeError()) return std::move(Error); @@ -2037,6 +2063,11 @@ PrintFatalError(ActionDef->getLoc(), "Action was not a GIAction"); } + for (Record *Predicate : RuleDef->getValueAsListOfDefs("Predicates")) { + declareSubtargetFeature(Predicate); + Matcher.addRequiredFeature(Predicate); + } + Rules.push_back(std::move(Matcher)); } @@ -2065,15 +2096,22 @@ OS << ", TempOp" << I << "(MachineOperand::CreatePlaceholder())\n"; OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n"; - OS << "#ifdef GET_GLOBALISEL_IMPL\n" - << "bool " << Target.getName() + OS << "#ifdef GET_GLOBALISEL_IMPL\n"; + SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures, + OS); + SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, OS); + SubtargetFeatureInfo::emitComputeAvailableFeatures( + Target.getName(), "InstructionSelector", "computeAvailableFeatures", + SubtargetFeatures, OS); + + OS << "bool " << Target.getName() << "InstructionSelector::selectImpl(MachineInstr &I) const {\n" << " MachineFunction &MF = *I.getParent()->getParent();\n" << " const MachineRegisterInfo &MRI = MF.getRegInfo();\n"; for (auto &Rule : Rules) { Rule.emitTblgen(OS, 0); - Rule.emit(OS); + Rule.emit(OS, SubtargetFeatures); ++NumPatternEmitted; } @@ -2082,6 +2120,12 @@ << "#endif // ifdef GET_GLOBALISEL_IMPL\n"; } +void GlobalISelEmitter::declareSubtargetFeature(Record *Predicate) { + if (SubtargetFeatures.count(Predicate) == 0) + SubtargetFeatures.emplace( + Predicate, SubtargetFeatureInfo(Predicate, SubtargetFeatures.size())); +} + } // end anonymous namespace //===----------------------------------------------------------------------===// Index: utils/TableGen/SubtargetFeatureInfo.h =================================================================== --- utils/TableGen/SubtargetFeatureInfo.h +++ utils/TableGen/SubtargetFeatureInfo.h @@ -37,6 +37,12 @@ return "Feature_" + TheDef->getName().str(); } + /// \brief The name of the enumerated constant identifying the bitnumber for + /// this feature. + std::string getEnumBitName() const { + return "Feature_" + TheDef->getName().str() + "Bit"; + } + void dump() const; static std::vector> getAll(const RecordKeeper &Records); @@ -47,6 +53,12 @@ &SubtargetFeatures, raw_ostream &OS); + /// Emit the subtarget feature flag definitions. + static void emitSubtargetFeatureBitEnumeration( + std::map + &SubtargetFeatures, + raw_ostream &OS); + static void emitNameTable(std::map &SubtargetFeatures, raw_ostream &OS); @@ -66,6 +78,22 @@ std::map &SubtargetFeatures, raw_ostream &OS); + + /// Emit the function to compute the list of available features given a + /// subtarget. + /// + /// \param TargetName The name of the target as used in class prefixes (e.g. + /// Subtarget) + /// \param ClassName The name of the class (without the prefix) + /// that will contain the generated functions. + /// \param FuncName The name of the function to emit. + /// \param SubtargetFeatures A map of TableGen records to the + /// SubtargetFeatureInfo equivalent. + static void emitComputeAssemblerAvailableFeatures( + StringRef TargetName, StringRef ClassName, StringRef FuncName, + std::map + &SubtargetFeatures, + raw_ostream &OS); }; } // end namespace llvm Index: utils/TableGen/SubtargetFeatureInfo.cpp =================================================================== --- utils/TableGen/SubtargetFeatureInfo.cpp +++ utils/TableGen/SubtargetFeatureInfo.cpp @@ -59,6 +59,20 @@ OS << "};\n\n"; } +void SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration( + std::map &SubtargetFeatures, + raw_ostream &OS) { + OS << "// Bits for subtarget features that participate in " + << "instruction matching.\n"; + OS << "enum SubtargetFeatureBits : " + << getMinimalTypeForRange(SubtargetFeatures.size()) << " {\n"; + for (const auto &SF : SubtargetFeatures) { + const SubtargetFeatureInfo &SFI = SF.second; + OS << " " << SFI.getEnumBitName() << " = " << SFI.Index << ",\n"; + } + OS << "};\n\n"; +} + void SubtargetFeatureInfo::emitNameTable( std::map &SubtargetFeatures, raw_ostream &OS) { @@ -90,6 +104,24 @@ StringRef TargetName, StringRef ClassName, StringRef FuncName, std::map &SubtargetFeatures, raw_ostream &OS) { + OS << "PredicateBitset " << TargetName << ClassName << "::\n" + << FuncName << "(const MachineFunction *MF, const " << TargetName + << "Subtarget *Subtarget) const {\n"; + OS << " PredicateBitset Features;\n"; + for (const auto &SF : SubtargetFeatures) { + const SubtargetFeatureInfo &SFI = SF.second; + + OS << " if (" << SFI.TheDef->getValueAsString("CondString") << ")\n"; + OS << " Features[" << SFI.getEnumBitName() << "] = 1;\n"; + } + OS << " return Features;\n"; + OS << "}\n\n"; +} + +void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( + StringRef TargetName, StringRef ClassName, StringRef FuncName, + std::map &SubtargetFeatures, + raw_ostream &OS) { OS << "uint64_t " << TargetName << ClassName << "::\n" << FuncName << "(const FeatureBitset& FB) const {\n"; OS << " uint64_t Features = 0;\n"; Index: utils/TableGen/Types.cpp =================================================================== --- utils/TableGen/Types.cpp +++ utils/TableGen/Types.cpp @@ -40,5 +40,6 @@ uint64_t MaxIndex = Size; if (MaxIndex > 0) MaxIndex--; + assert(MaxIndex <= 64 && "Too many bits"); return getMinimalTypeForRange(1ULL << MaxIndex); }