diff options
| author | Daniel Sanders <daniel_l_sanders@apple.com> | 2017-08-23 12:14:18 +0000 |
|---|---|---|
| committer | Daniel Sanders <daniel_l_sanders@apple.com> | 2017-08-23 12:14:18 +0000 |
| commit | c3885c4589e476b99c5ee67ff9d5945b1d7ce8d3 (patch) | |
| tree | f599593ce9647ff4c6628dfd8e56db33be0f5f32 /llvm/utils | |
| parent | 5b9296009173b2a8c0582e0e88e0cab1ea4e5d27 (diff) | |
| download | bcm5719-llvm-c3885c4589e476b99c5ee67ff9d5945b1d7ce8d3.tar.gz bcm5719-llvm-c3885c4589e476b99c5ee67ff9d5945b1d7ce8d3.zip | |
[globalisel][tablegen] Add support for ImmLeaf without SDNodeXForm
Summary:
This patch adds support for predicates on imm nodes but only for ImmLeaf and not for PatLeaf or PatFrag and only where the value does not need to be transformed before being rendered into the instruction.
The limitation on PatLeaf/PatFrag/SDNodeXForm is due to differences in the necessary target-supplied C++ for GlobalISel.
Depends on D36085
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Reviewed By: rovka
Subscribers: kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D36086
llvm-svn: 311546
Diffstat (limited to 'llvm/utils')
| -rw-r--r-- | llvm/utils/TableGen/GlobalISelEmitter.cpp | 137 |
1 files changed, 124 insertions, 13 deletions
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index 9f53ac40e3a..17898beb7de 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -180,9 +180,19 @@ static Error failedImport(const Twine &Reason) { static Error isTrivialOperatorNode(const TreePatternNode *N) { std::string Explanation = ""; std::string Separator = ""; - if (N->hasAnyPredicate()) { + + bool HasUnsupportedPredicate = false; + for (const auto &Predicate : N->getPredicateFns()) { + if (Predicate.isAlwaysTrue()) + continue; + + if (Predicate.isImmediatePattern()) + continue; + + HasUnsupportedPredicate = true; Explanation = Separator + "Has a predicate (" + explainPredicates(N) + ")"; Separator = ", "; + break; } if (N->getTransformFn()) { @@ -190,7 +200,7 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) { Separator = ", "; } - if (!N->hasAnyPredicate() && !N->getTransformFn()) + if (!HasUnsupportedPredicate && !N->getTransformFn()) return Error::success(); return failedImport(Explanation); @@ -515,6 +525,10 @@ private: typedef std::vector<std::unique_ptr<PredicateTy>> PredicateVec; PredicateVec Predicates; + /// Template instantiations should specialize this to return a string to use + /// for the comment emitted when there are no predicates. + std::string getNoPredicateComment() const; + public: /// Construct a new operand predicate and add it to the matcher. template <class Kind, class... Args> @@ -541,7 +555,8 @@ public: template <class... Args> void emitPredicateListOpcodes(MatchTable &Table, Args &&... args) const { if (Predicates.empty()) { - Table << MatchTable::Comment("No predicates") << MatchTable::LineBreak; + Table << MatchTable::Comment(getNoPredicateComment()) + << MatchTable::LineBreak; return; } @@ -618,6 +633,12 @@ public: virtual unsigned countRendererFns() const { return 0; } }; +template <> +std::string +PredicateListMatcher<OperandPredicateMatcher>::getNoPredicateComment() const { + return "No operand predicates"; +} + /// Generates code to check that an operand is a particular LLT. class LLTOperandMatcher : public OperandPredicateMatcher { protected: @@ -915,6 +936,7 @@ protected: /// must be tested first. enum PredicateKind { IPM_Opcode, + IPM_ImmPredicate, }; PredicateKind Kind; @@ -943,6 +965,12 @@ public: virtual unsigned countRendererFns() const { return 0; } }; +template <> +std::string +PredicateListMatcher<InstructionPredicateMatcher>::getNoPredicateComment() const { + return "No instruction predicates"; +} + /// Generates code to check the opcode of an instruction. class InstructionOpcodeMatcher : public InstructionPredicateMatcher { protected: @@ -989,6 +1017,54 @@ public: } }; +/// Generates code to check that this instruction is a constant whose value +/// meets an immediate predicate. +/// +/// Immediates are slightly odd since they are typically used like an operand +/// but are represented as an operator internally. We typically write simm8:$src +/// in a tablegen pattern, but this is just syntactic sugar for +/// (imm:i32)<<P:Predicate_simm8>>:$imm which more directly describes the nodes +/// that will be matched and the predicate (which is attached to the imm +/// operator) that will be tested. In SelectionDAG this describes a +/// ConstantSDNode whose internal value will be tested using the simm8 predicate. +/// +/// The corresponding GlobalISel representation is %1 = G_CONSTANT iN Value. In +/// this representation, the immediate could be tested with an +/// InstructionMatcher, InstructionOpcodeMatcher, OperandMatcher, and a +/// OperandPredicateMatcher-subclass to check the Value meets the predicate but +/// there are two implementation issues with producing that matcher +/// configuration from the SelectionDAG pattern: +/// * ImmLeaf is a PatFrag whose root is an InstructionMatcher. This means that +/// were we to sink the immediate predicate to the operand we would have to +/// have two partial implementations of PatFrag support, one for immediates +/// and one for non-immediates. +/// * At the point we handle the predicate, the OperandMatcher hasn't been +/// created yet. If we were to sink the predicate to the OperandMatcher we +/// would also have to complicate (or duplicate) the code that descends and +/// creates matchers for the subtree. +/// Overall, it's simpler to handle it in the place it was found. +class InstructionImmPredicateMatcher : public InstructionPredicateMatcher { +protected: + TreePredicateFn Predicate; + +public: + InstructionImmPredicateMatcher(const TreePredicateFn &Predicate) + : InstructionPredicateMatcher(IPM_ImmPredicate), Predicate(Predicate) {} + + static bool classof(const InstructionPredicateMatcher *P) { + return P->getKind() == IPM_ImmPredicate; + } + + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, + unsigned InsnVarID) const override { + Table << MatchTable::Opcode("GIM_CheckImmPredicate") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("Predicate") + << MatchTable::NamedValue("GIPFP_" + Predicate.getFnName()) + << MatchTable::LineBreak; + } +}; + /// Generates code to check that a set of predicates and operands match for a /// particular instruction. /// @@ -1923,6 +1999,19 @@ GlobalISelEmitter::createAndImportSelDAGMatcher(InstructionMatcher &InsnMatcher, OM.addPredicate<LLTOperandMatcher>(*OpTyOrNone); } + for (const auto &Predicate : Src->getPredicateFns()) { + if (Predicate.isAlwaysTrue()) + continue; + + if (Predicate.isImmediatePattern()) { + InsnMatcher.addPredicate<InstructionImmPredicateMatcher>(Predicate); + continue; + } + + return failedImport("Src pattern child has predicate (" + + explainPredicates(Src) + ")"); + } + if (Src->isLeaf()) { Init *SrcInit = Src->getLeafValue(); if (IntInit *SrcIntInit = dyn_cast<IntInit>(SrcInit)) { @@ -1975,10 +2064,6 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher, OperandMatcher &OM = InsnMatcher.addOperand(OpIdx, SrcChild->getName(), TempOpIdx); - if (SrcChild->hasAnyPredicate()) - return failedImport("Src pattern child has predicate (" + - explainPredicates(SrcChild) + ")"); - ArrayRef<EEVT::TypeSet> ChildTypes = SrcChild->getExtTypes(); if (ChildTypes.size() != 1) return failedImport("Src pattern child has multiple results"); @@ -2058,6 +2143,11 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher, Error GlobalISelEmitter::importExplicitUseRenderer( BuildMIAction &DstMIBuilder, TreePatternNode *DstChild, const InstructionMatcher &InsnMatcher) const { + if (DstChild->getTransformFn() != nullptr) { + return failedImport("Dst pattern child has transform fn " + + DstChild->getTransformFn()->getName()); + } + if (!DstChild->isLeaf()) { // We accept 'bb' here. It's an operator because BasicBlockSDNode isn't // inline, but in MI it's just another operand. @@ -2080,14 +2170,10 @@ Error GlobalISelEmitter::importExplicitUseRenderer( return Error::success(); } - return failedImport("Dst pattern child isn't a leaf node or an MBB"); + return failedImport("Dst pattern child isn't a leaf node or an MBB" + llvm::to_string(*DstChild)); } // Otherwise, we're looking for a bog-standard RegisterClass operand. - if (DstChild->hasAnyPredicate()) - return failedImport("Dst pattern child has predicate (" + - explainPredicates(DstChild) + ")"); - if (auto *ChildDefInit = dyn_cast<DefInit>(DstChild->getLeafValue())) { auto *ChildRec = ChildDefInit->getDef(); @@ -2526,7 +2612,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) { OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n" << ", State(" << MaxTemporaries << "),\n" - << "MatcherInfo({TypeObjects, FeatureBitsets, {\n" + << "MatcherInfo({TypeObjects, FeatureBitsets, ImmPredicateFns, {\n" << " nullptr, // GICP_Invalid\n"; for (const auto &Record : ComplexPredicates) OS << " &" << Target.getName() @@ -2639,6 +2725,31 @@ void GlobalISelEmitter::run(raw_ostream &OS) { OS << "};\n" << "// See constructor for table contents\n\n"; + // Emit imm predicate table and an enum to reference them with. + // The 'Predicate_' part of the name is redundant but eliminating it is more + // trouble than it's worth. + { + OS << "// PatFrag predicates.\n" + << "enum {\n"; + StringRef EnumeratorSeparator = " = GIPFP_Invalid,\n"; + for (const auto *Record : RK.getAllDerivedDefinitions("PatFrag")) { + if (!Record->getValueAsString("ImmediateCode").empty()) { + OS << " GIPFP_Predicate_" << Record->getName() << EnumeratorSeparator; + EnumeratorSeparator = ",\n"; + } + } + OS << "};\n"; + } + for (const auto *Record : RK.getAllDerivedDefinitions("PatFrag")) + if (!Record->getValueAsString("ImmediateCode").empty()) + OS << " static bool Predicate_" << Record->getName() << "(int64_t Imm) {" + << Record->getValueAsString("ImmediateCode") << " }\n"; + OS << "static InstructionSelector::ImmediatePredicateFn ImmPredicateFns[] = {\n"; + for (const auto *Record : RK.getAllDerivedDefinitions("PatFrag")) + if (!Record->getValueAsString("ImmediateCode").empty()) + OS << " Predicate_" << Record->getName() << ",\n"; + OS << "};\n"; + OS << "bool " << Target.getName() << "InstructionSelector::selectImpl(MachineInstr &I) const {\n" << " MachineFunction &MF = *I.getParent()->getParent();\n" |

