summaryrefslogtreecommitdiffstats
path: root/llvm/utils
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/utils')
-rw-r--r--llvm/utils/TableGen/GlobalISelEmitter.cpp137
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"
OpenPOWER on IntegriCloud