diff options
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"  | 

