Index: include/llvm/CodeGen/GlobalISel/InstructionSelector.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -18,20 +18,48 @@ #include "llvm/ADT/Optional.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.cpp =================================================================== --- lib/Target/AArch64/AArch64InstructionSelector.cpp +++ lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -40,12 +40,16 @@ namespace { +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: @@ -69,6 +73,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. @@ -87,7 +98,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 @@ -566,6 +577,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/X86.h =================================================================== --- lib/Target/X86/X86.h +++ lib/Target/X86/X86.h @@ -95,7 +95,8 @@ /// encoding when possible in order to reduce code size. FunctionPass *createX86EvexToVexInsts(); -InstructionSelector *createX86InstructionSelector(X86Subtarget &, +InstructionSelector *createX86InstructionSelector(const X86TargetMachine &TM, + X86Subtarget &, X86RegisterBankInfo &); void initializeEvexToVexInstPassPass(PassRegistry &); Index: lib/Target/X86/X86InstructionSelector.cpp =================================================================== --- lib/Target/X86/X86InstructionSelector.cpp +++ lib/Target/X86/X86InstructionSelector.cpp @@ -39,11 +39,15 @@ namespace { +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: @@ -66,10 +70,18 @@ bool selectFrameIndex(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" @@ -82,10 +94,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 @@ -173,6 +187,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!"); @@ -459,7 +479,8 @@ } InstructionSelector * -llvm::createX86InstructionSelector(X86Subtarget &Subtarget, +llvm::createX86InstructionSelector(const X86TargetMachine &TM, + X86Subtarget &Subtarget, X86RegisterBankInfo &RBI) { - return new X86InstructionSelector(Subtarget, RBI); + return new X86InstructionSelector(TM, Subtarget, RBI); } Index: lib/Target/X86/X86TargetMachine.cpp =================================================================== --- lib/Target/X86/X86TargetMachine.cpp +++ lib/Target/X86/X86TargetMachine.cpp @@ -286,7 +286,7 @@ auto *RBI = new X86RegisterBankInfo(*I->getRegisterInfo()); GISel->RegBankInfo.reset(RBI); - GISel->InstSelector.reset(createX86InstructionSelector(*I, *RBI)); + GISel->InstSelector.reset(createX86InstructionSelector(*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(); @@ -115,6 +139,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; @@ -154,6 +181,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; @@ -208,7 +238,7 @@ GICopyOperand<"src1">, GICopyOperand<"src2">, GICopyOperand<"src3">]> - ]>; + ], [HasA]>; // Commutativity is manual at the moment. def Rule3X: GIRule< @@ -226,11 +256,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; @@ -265,7 +298,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 @@ -29,7 +29,31 @@ def Z : OperandWithDefaultOps ; def m1Z : 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(); @@ -103,6 +127,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; @@ -142,6 +169,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; @@ -181,11 +211,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; @@ -213,7 +247,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 @@ -2861,7 +2861,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/SmallSet.h" #include "llvm/ADT/Statistic.h" @@ -163,20 +164,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; -} - std::string explainOperator(Record *Operator) { if (Operator->isSubClassOf("SDNode")) return " (" + Operator->getValueAsString("Opcode") + ")"; @@ -240,6 +227,8 @@ /// ID for the next instruction variable defined with defineInsnVar() unsigned NextInsnVarID; + std::vector RequiredFeatures; + public: RuleMatcher() : Matchers(), Actions(), InsnVariableNames(), NextInsnVarID(0) {} @@ -247,6 +236,7 @@ RuleMatcher &operator=(RuleMatcher &&Other) = default; InstructionMatcher &addInstructionMatcher(); + void addRequiredFeature(Record *Feature); template Kind &addAction(Args &&... args); @@ -258,7 +248,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. /// @@ -1237,6 +1229,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)...)); @@ -1289,11 +1285,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!"); @@ -1307,7 +1308,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"); @@ -1422,10 +1438,13 @@ /// GIComplexPatternEquiv. DenseMap ComplexPatternEquivs; + // Map of predicates to their subtarget features. + std::map SubtargetFeatures; + void gatherNodeEquivs(); const CodeGenInstruction *findNodeEquiv(Record *N) const; - Error importRulePredicates(RuleMatcher &M, ArrayRef Predicates) const; + Error importRulePredicates(RuleMatcher &M, ArrayRef Predicates); Expected createAndImportSelDAGMatcher(InstructionMatcher &InsnMatcher, const TreePatternNode *Src) const; @@ -1456,6 +1475,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() { @@ -1484,10 +1505,13 @@ Error 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 Error::success(); } @@ -2048,6 +2072,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)); } @@ -2076,15 +2105,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; } @@ -2093,6 +2129,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); }