diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-26 19:45:00 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-26 19:45:00 +0000 |
commit | 12f3ca4cdb95b193af905a00e722a4dcb40b3de3 (patch) | |
tree | ae1a7fcfc24a8d4b23206c57121c3f361d4b7f84 /utils/TableGen/GlobalISelEmitter.cpp | |
parent | d99dafe2e4a385dd2a6c76da6d8258deb100657b (diff) |
Diffstat (limited to 'utils/TableGen/GlobalISelEmitter.cpp')
-rw-r--r-- | utils/TableGen/GlobalISelEmitter.cpp | 251 |
1 files changed, 119 insertions, 132 deletions
diff --git a/utils/TableGen/GlobalISelEmitter.cpp b/utils/TableGen/GlobalISelEmitter.cpp index 7acc65e349ea6..dcf10ab511da7 100644 --- a/utils/TableGen/GlobalISelEmitter.cpp +++ b/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" @@ -79,7 +80,7 @@ public: return; } if (Ty.isVector()) { - OS << "LLT::vector(" << Ty.getNumElements() << ", " << Ty.getSizeInBits() + OS << "LLT::vector(" << Ty.getNumElements() << ", " << Ty.getScalarSizeInBits() << ")"; return; } @@ -90,52 +91,6 @@ public: }; class InstructionMatcher; -class OperandPlaceholder { -private: - enum PlaceholderKind { - OP_MatchReference, - OP_Temporary, - } Kind; - - struct MatchReferenceData { - InstructionMatcher *InsnMatcher; - StringRef InsnVarName; - StringRef SymbolicName; - }; - - struct TemporaryData { - unsigned OpIdx; - }; - - union { - struct MatchReferenceData MatchReference; - struct TemporaryData Temporary; - }; - - OperandPlaceholder(PlaceholderKind Kind) : Kind(Kind) {} - -public: - ~OperandPlaceholder() {} - - static OperandPlaceholder - CreateMatchReference(InstructionMatcher *InsnMatcher, - StringRef InsnVarName, StringRef SymbolicName) { - OperandPlaceholder Result(OP_MatchReference); - Result.MatchReference.InsnMatcher = InsnMatcher; - Result.MatchReference.InsnVarName = InsnVarName; - Result.MatchReference.SymbolicName = SymbolicName; - return Result; - } - - static OperandPlaceholder CreateTemporary(unsigned OpIdx) { - OperandPlaceholder Result(OP_Temporary); - Result.Temporary.OpIdx = OpIdx; - return Result; - } - - void emitCxxValueExpr(raw_ostream &OS) const; -}; - /// 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) { @@ -161,20 +116,6 @@ static std::string explainPredicates(const TreePatternNode *N) { return Explanation; } -static std::string explainRulePredicates(const ArrayRef<Init *> Predicates) { - std::string Explanation = ""; - StringRef Separator = ""; - for (const auto *P : Predicates) { - Explanation += Separator; - - if (const DefInit *PDef = dyn_cast<DefInit>(P)) { - Explanation += PDef->getDef()->getName(); - } else - Explanation += "<unknown>"; - } - return Explanation; -} - std::string explainOperator(Record *Operator) { if (Operator->isSubClassOf("SDNode")) return " (" + Operator->getValueAsString("Opcode") + ")"; @@ -238,6 +179,8 @@ class RuleMatcher { /// ID for the next instruction variable defined with defineInsnVar() unsigned NextInsnVarID; + std::vector<Record *> RequiredFeatures; + public: RuleMatcher() : Matchers(), Actions(), InsnVariableNames(), NextInsnVarID(0) {} @@ -245,6 +188,7 @@ public: RuleMatcher &operator=(RuleMatcher &&Other) = default; InstructionMatcher &addInstructionMatcher(); + void addRequiredFeature(Record *Feature); template <class Kind, class... Args> Kind &addAction(Args &&... args); @@ -255,7 +199,9 @@ public: void emitCxxCapturedInsnList(raw_ostream &OS); void emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr); - void emit(raw_ostream &OS); + void emit(raw_ostream &OS, + std::map<Record *, SubtargetFeatureInfo, LessRecordByID> + SubtargetFeatures); /// Compare the priority of this object and B. /// @@ -264,7 +210,10 @@ public: /// Report the maximum number of temporary operands needed by the rule /// matcher. - unsigned countTemporaryOperands() const; + unsigned countRendererFns() const; + + // FIXME: Remove this as soon as possible + InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); } }; template <class PredicateTy> class PredicateListMatcher { @@ -369,7 +318,7 @@ public: /// Report the maximum number of temporary operands needed by the predicate /// matcher. - virtual unsigned countTemporaryOperands() const { return 0; } + virtual unsigned countRendererFns() const { return 0; } }; /// Generates code to check that an operand is a particular LLT. @@ -399,10 +348,6 @@ protected: const OperandMatcher &Operand; const Record &TheDef; - unsigned getNumOperands() const { - return TheDef.getValueAsDag("Operands")->getNumArgs(); - } - unsigned getAllocatedTemporariesBaseID() const; public: @@ -417,17 +362,13 @@ public: void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, StringRef OperandExpr) const override { - OS << TheDef.getValueAsString("MatcherFn") << "(" << OperandExpr; - for (unsigned I = 0; I < getNumOperands(); ++I) { - OS << ", "; - OperandPlaceholder::CreateTemporary(getAllocatedTemporariesBaseID() + I) - .emitCxxValueExpr(OS); - } - OS << ")"; + unsigned ID = getAllocatedTemporariesBaseID(); + OS << "(Renderer" << ID << " = " << TheDef.getValueAsString("MatcherFn") + << "(" << OperandExpr << "))"; } - unsigned countTemporaryOperands() const override { - return getNumOperands(); + unsigned countRendererFns() const override { + return 1; } }; @@ -496,7 +437,7 @@ protected: /// The index of the first temporary variable allocated to this operand. The /// number of allocated temporaries can be found with - /// countTemporaryOperands(). + /// countRendererFns(). unsigned AllocatedTemporariesBaseID; public: @@ -577,12 +518,12 @@ public: /// Report the maximum number of temporary operands needed by the operand /// matcher. - unsigned countTemporaryOperands() const { + unsigned countRendererFns() const { return std::accumulate( predicates().begin(), predicates().end(), 0, [](unsigned A, const std::unique_ptr<OperandPredicateMatcher> &Predicate) { - return A + Predicate->countTemporaryOperands(); + return A + Predicate->countRendererFns(); }); } @@ -631,7 +572,7 @@ public: /// Report the maximum number of temporary operands needed by the predicate /// matcher. - virtual unsigned countTemporaryOperands() const { return 0; } + virtual unsigned countRendererFns() const { return 0; } }; /// Generates code to check the opcode of an instruction. @@ -788,17 +729,17 @@ public: /// Report the maximum number of temporary operands needed by the instruction /// matcher. - unsigned countTemporaryOperands() const { + unsigned countRendererFns() const { return std::accumulate(predicates().begin(), predicates().end(), 0, [](unsigned A, const std::unique_ptr<InstructionPredicateMatcher> &Predicate) { - return A + Predicate->countTemporaryOperands(); + return A + Predicate->countRendererFns(); }) + std::accumulate( Operands.begin(), Operands.end(), 0, [](unsigned A, const std::unique_ptr<OperandMatcher> &Operand) { - return A + Operand->countTemporaryOperands(); + return A + Operand->countRendererFns(); }); } }; @@ -853,18 +794,6 @@ public: }; //===- Actions ------------------------------------------------------------===// -void OperandPlaceholder::emitCxxValueExpr(raw_ostream &OS) const { - switch (Kind) { - case OP_MatchReference: - OS << MatchReference.InsnMatcher->getOperand(MatchReference.SymbolicName) - .getOperandExpr(MatchReference.InsnVarName); - break; - case OP_Temporary: - OS << "TempOp" << Temporary.OpIdx; - break; - } -} - class OperandRenderer { public: enum RendererKind { OR_Copy, OR_Imm, OR_Register, OR_ComplexPattern }; @@ -950,31 +879,33 @@ public: } }; +/// Adds operands by calling a renderer function supplied by the ComplexPattern +/// matcher function. class RenderComplexPatternOperand : public OperandRenderer { private: const Record &TheDef; - std::vector<OperandPlaceholder> Sources; + /// The name of the operand. + const StringRef SymbolicName; + /// The renderer number. This must be unique within a rule since it's used to + /// identify a temporary variable to hold the renderer function. + unsigned RendererID; unsigned getNumOperands() const { return TheDef.getValueAsDag("Operands")->getNumArgs(); } public: - RenderComplexPatternOperand(const Record &TheDef, - const ArrayRef<OperandPlaceholder> Sources) - : OperandRenderer(OR_ComplexPattern), TheDef(TheDef), Sources(Sources) {} + RenderComplexPatternOperand(const Record &TheDef, StringRef SymbolicName, + unsigned RendererID) + : OperandRenderer(OR_ComplexPattern), TheDef(TheDef), + SymbolicName(SymbolicName), RendererID(RendererID) {} static bool classof(const OperandRenderer *R) { return R->getKind() == OR_ComplexPattern; } void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { - assert(Sources.size() == getNumOperands() && "Inconsistent number of operands"); - for (const auto &Source : Sources) { - OS << "MIB.add("; - Source.emitCxxValueExpr(OS); - OS << ");\n"; - } + OS << "Renderer" << RendererID << "(MIB);\n"; } }; @@ -1022,8 +953,9 @@ private: bool canMutate() const { for (const auto &Renderer : enumerate(OperandRenderers)) { if (const auto *Copy = dyn_cast<CopyRenderer>(&*Renderer.value())) { - if (Matched.getOperand(Copy->getSymbolicName()).getOperandIndex() != - Renderer.index()) + const OperandMatcher &OM = Matched.getOperand(Copy->getSymbolicName()); + if (&Matched != &OM.getInstructionMatcher() || + OM.getOperandIndex() != Renderer.index()) return false; } else return false; @@ -1092,6 +1024,10 @@ InstructionMatcher &RuleMatcher::addInstructionMatcher() { return *Matchers.back(); } +void RuleMatcher::addRequiredFeature(Record *Feature) { + RequiredFeatures.push_back(Feature); +} + template <class Kind, class... Args> Kind &RuleMatcher::addAction(Args &&... args) { Actions.emplace_back(llvm::make_unique<Kind>(std::forward<Args>(args)...)); @@ -1135,7 +1071,9 @@ void RuleMatcher::emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr) { Matchers.front()->emitCxxCaptureStmts(OS, *this, InsnVarName); } -void RuleMatcher::emit(raw_ostream &OS) { +void RuleMatcher::emit(raw_ostream &OS, + std::map<Record *, SubtargetFeatureInfo, LessRecordByID> + SubtargetFeatures) { if (Matchers.empty()) llvm_unreachable("Unexpected empty matcher!"); @@ -1149,7 +1087,22 @@ void RuleMatcher::emit(raw_ostream &OS) { // %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"); @@ -1235,11 +1188,11 @@ bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const { return false; } -unsigned RuleMatcher::countTemporaryOperands() const { +unsigned RuleMatcher::countRendererFns() const { return std::accumulate( Matchers.begin(), Matchers.end(), 0, [](unsigned A, const std::unique_ptr<InstructionMatcher> &Matcher) { - return A + Matcher->countTemporaryOperands(); + return A + Matcher->countRendererFns(); }); } @@ -1264,10 +1217,13 @@ private: /// GIComplexPatternEquiv. DenseMap<const Record *, const Record *> ComplexPatternEquivs; + // Map of predicates to their subtarget features. + std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatures; + void gatherNodeEquivs(); const CodeGenInstruction *findNodeEquiv(Record *N) const; - Error importRulePredicates(RuleMatcher &M, ArrayRef<Init *> Predicates) const; + Error importRulePredicates(RuleMatcher &M, ArrayRef<Init *> Predicates); Expected<InstructionMatcher &> createAndImportSelDAGMatcher(InstructionMatcher &InsnMatcher, const TreePatternNode *Src) const; @@ -1287,6 +1243,8 @@ private: /// Analyze pattern \p P, returning a matcher for it if possible. /// Otherwise, return an Error explaining why we don't support it. Expected<RuleMatcher> runOnPattern(const PatternToMatch &P); + + void declareSubtargetFeature(Record *Predicate); }; void GlobalISelEmitter::gatherNodeEquivs() { @@ -1315,10 +1273,13 @@ GlobalISelEmitter::GlobalISelEmitter(RecordKeeper &RK) Error GlobalISelEmitter::importRulePredicates(RuleMatcher &M, - ArrayRef<Init *> Predicates) const { - if (!Predicates.empty()) - return failedImport("Pattern has a rule predicate (" + - explainRulePredicates(Predicates) + ")"); + ArrayRef<Init *> Predicates) { + for (const Init *Predicate : Predicates) { + const DefInit *PredicateDef = static_cast<const DefInit *>(Predicate); + declareSubtargetFeature(PredicateDef->getDef()); + M.addRequiredFeature(PredicateDef->getDef()); + } + return Error::success(); } @@ -1423,6 +1384,12 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher, return Error::success(); } + if (ChildRec->isSubClassOf("RegisterOperand")) { + OM.addPredicate<RegisterBankOperandMatcher>( + Target.getRegisterClass(ChildRec->getValueAsDef("RegClass"))); + return Error::success(); + } + // Check for ComplexPattern's. if (ChildRec->isSubClassOf("ComplexPattern")) { const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec); @@ -1430,9 +1397,9 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher, return failedImport("SelectionDAG ComplexPattern (" + ChildRec->getName() + ") not mapped to GlobalISel"); - const auto &Predicate = OM.addPredicate<ComplexPatternOperandMatcher>( - OM, *ComplexPattern->second); - TempOpIdx += Predicate.countTemporaryOperands(); + OM.addPredicate<ComplexPatternOperandMatcher>(OM, + *ComplexPattern->second); + TempOpIdx++; return Error::success(); } @@ -1486,7 +1453,8 @@ Error GlobalISelEmitter::importExplicitUseRenderer( return Error::success(); } - if (ChildRec->isSubClassOf("RegisterClass")) { + if (ChildRec->isSubClassOf("RegisterClass") || + ChildRec->isSubClassOf("RegisterOperand")) { DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, DstChild->getName()); return Error::success(); } @@ -1497,13 +1465,10 @@ Error GlobalISelEmitter::importExplicitUseRenderer( return failedImport( "SelectionDAG ComplexPattern not mapped to GlobalISel"); - SmallVector<OperandPlaceholder, 2> RenderedOperands; const OperandMatcher &OM = InsnMatcher.getOperand(DstChild->getName()); - for (unsigned I = 0; I < OM.countTemporaryOperands(); ++I) - RenderedOperands.push_back(OperandPlaceholder::CreateTemporary( - OM.getAllocatedTemporariesBaseID() + I)); DstMIBuilder.addRenderer<RenderComplexPatternOperand>( - *ComplexPattern->second, RenderedOperands); + *ComplexPattern->second, DstChild->getName(), + OM.getAllocatedTemporariesBaseID()); return Error::success(); } @@ -1656,6 +1621,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { const auto &DstIOperand = DstI.Operands[OpIdx]; Record *DstIOpRec = DstIOperand.Rec; + if (DstIOpRec->isSubClassOf("RegisterOperand")) + DstIOpRec = DstIOpRec->getValueAsDef("RegClass"); if (!DstIOpRec->isSubClassOf("RegisterClass")) return failedImport("Dst MI def isn't a register class"); @@ -1723,26 +1690,40 @@ void GlobalISelEmitter::run(raw_ostream &OS) { unsigned MaxTemporaries = 0; for (const auto &Rule : Rules) - MaxTemporaries = std::max(MaxTemporaries, Rule.countTemporaryOperands()); + MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns()); + + OS << "#ifdef GET_GLOBALISEL_PREDICATE_BITSET\n" + << "const unsigned MAX_SUBTARGET_PREDICATES = " << SubtargetFeatures.size() + << ";\n" + << "using PredicateBitset = " + "llvm::PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;\n" + << "#endif // ifdef GET_GLOBALISEL_PREDICATE_BITSET\n\n"; OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n"; for (unsigned I = 0; I < MaxTemporaries; ++I) - OS << " mutable MachineOperand TempOp" << I << ";\n"; + OS << " mutable ComplexRendererFn Renderer" << I << ";\n"; OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n"; OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"; for (unsigned I = 0; I < MaxTemporaries; ++I) - OS << ", TempOp" << I << "(MachineOperand::CreatePlaceholder())\n"; + OS << ", Renderer" << I << "(nullptr)\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.emit(OS); + Rule.emit(OS, SubtargetFeatures); ++NumPatternEmitted; } @@ -1751,6 +1732,12 @@ void GlobalISelEmitter::run(raw_ostream &OS) { << "#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 //===----------------------------------------------------------------------===// |