[llvm] r296121 - [globalisel] Sort RuleMatchers by priority.
Daniel Sanders via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 24 05:58:13 PST 2017
Author: dsanders
Date: Fri Feb 24 07:58:11 2017
New Revision: 296121
URL: http://llvm.org/viewvc/llvm-project?rev=296121&view=rev
Log:
[globalisel] Sort RuleMatchers by priority.
Summary:
This makes more important rules have priority over less important rules.
For example, '%a = G_ADD $b:s64, $c:s64' has priority over
'%a = G_ADD $b:s32, $c:s32'. Previously these rules were emitted in the
correct order by chance.
NFC in this patch but it is required to make the next patch work correctly.
Depends on D29710
Reviewers: t.p.northover, ab, qcolombet, aditya_nandakumar, rovka
Reviewed By: ab, rovka
Subscribers: javed.absar, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D29711
Modified:
llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
Modified: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp?rev=296121&r1=296120&r2=296121&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp Fri Feb 24 07:58:11 2017
@@ -103,6 +103,7 @@ public:
iterator_range<typename PredicateVec::const_iterator> predicates() const {
return make_range(predicates_begin(), predicates_end());
}
+ typename PredicateVec::size_type predicates_size() const { return Predicates.size(); }
/// Emit a C++ expression that tests whether all the predicates are met.
template <class... Args>
@@ -130,11 +131,36 @@ public:
/// * Operand is an MBB.
class OperandPredicateMatcher {
public:
+ /// This enum is used for RTTI and also defines the priority that is given to
+ /// the predicate when generating the matcher code. Kinds with higher priority
+ /// must be tested first.
+ ///
+ /// The relative priority of OPM_LLT, OPM_RegBank, and OPM_MBB do not matter.
+ enum PredicateKind {
+ OPM_LLT,
+ OPM_RegBank,
+ OPM_MBB,
+ };
+
+protected:
+ PredicateKind Kind;
+
+public:
+ OperandPredicateMatcher(PredicateKind Kind) : Kind(Kind) {}
virtual ~OperandPredicateMatcher() {}
+ PredicateKind getKind() const { return Kind; }
+
/// Emit a C++ expression that checks the predicate for the given operand.
virtual void emitCxxPredicateExpr(raw_ostream &OS,
StringRef OperandExpr) const = 0;
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ virtual bool isHigherPriorityThan(const OperandPredicateMatcher &B) {
+ return false;
+ };
};
/// Generates code to check that an operand is a particular LLT.
@@ -143,7 +169,12 @@ protected:
std::string Ty;
public:
- LLTOperandMatcher(std::string Ty) : Ty(Ty) {}
+ LLTOperandMatcher(std::string Ty)
+ : OperandPredicateMatcher(OPM_LLT), Ty(Ty) {}
+
+ static bool classof(const OperandPredicateMatcher *P) {
+ return P->getKind() == OPM_LLT;
+ }
void emitCxxPredicateExpr(raw_ostream &OS,
StringRef OperandExpr) const override {
@@ -157,7 +188,12 @@ protected:
const CodeGenRegisterClass &RC;
public:
- RegisterBankOperandMatcher(const CodeGenRegisterClass &RC) : RC(RC) {}
+ RegisterBankOperandMatcher(const CodeGenRegisterClass &RC)
+ : OperandPredicateMatcher(OPM_RegBank), RC(RC) {}
+
+ static bool classof(const OperandPredicateMatcher *P) {
+ return P->getKind() == OPM_RegBank;
+ }
void emitCxxPredicateExpr(raw_ostream &OS,
StringRef OperandExpr) const override {
@@ -170,6 +206,12 @@ public:
/// Generates code to check that an operand is a basic block.
class MBBOperandMatcher : public OperandPredicateMatcher {
public:
+ MBBOperandMatcher() : OperandPredicateMatcher(OPM_MBB) {}
+
+ static bool classof(const OperandPredicateMatcher *P) {
+ return P->getKind() == OPM_MBB;
+ }
+
void emitCxxPredicateExpr(raw_ostream &OS,
StringRef OperandExpr) const override {
OS << OperandExpr << ".isMBB()";
@@ -195,6 +237,27 @@ public:
emitCxxPredicateListExpr(OS, getOperandExpr(InsnVarName));
OS << ")";
}
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ bool isHigherPriorityThan(const OperandMatcher &B) const {
+ // Operand matchers involving more predicates have higher priority.
+ if (predicates_size() > B.predicates_size())
+ return true;
+ if (predicates_size() < B.predicates_size())
+ return false;
+
+ // This assumes that predicates are added in a consistent order.
+ for (const auto &Predicate : zip(predicates(), B.predicates())) {
+ if (std::get<0>(Predicate)->isHigherPriorityThan(*std::get<1>(Predicate)))
+ return true;
+ if (std::get<1>(Predicate)->isHigherPriorityThan(*std::get<0>(Predicate)))
+ return false;
+ }
+
+ return false;
+ };
};
/// Generates code to check a predicate on an instruction.
@@ -203,13 +266,32 @@ public:
/// * The opcode of the instruction is a particular value.
/// * The nsw/nuw flag is/isn't set.
class InstructionPredicateMatcher {
+protected:
+ /// This enum is used for RTTI and also defines the priority that is given to
+ /// the predicate when generating the matcher code. Kinds with higher priority
+ /// must be tested first.
+ enum PredicateKind {
+ IPM_Opcode,
+ };
+
+ PredicateKind Kind;
+
public:
virtual ~InstructionPredicateMatcher() {}
+ PredicateKind getKind() const { return Kind; }
+
/// Emit a C++ expression that tests whether the instruction named in
/// InsnVarName matches the predicate.
virtual void emitCxxPredicateExpr(raw_ostream &OS,
StringRef InsnVarName) const = 0;
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ bool isHigherPriorityThan(const InstructionPredicateMatcher &B) const {
+ return Kind < B.Kind;
+ };
};
/// Generates code to check the opcode of an instruction.
@@ -220,11 +302,34 @@ protected:
public:
InstructionOpcodeMatcher(const CodeGenInstruction *I) : I(I) {}
+ static bool classof(const InstructionPredicateMatcher *P) {
+ return P->getKind() == IPM_Opcode;
+ }
+
void emitCxxPredicateExpr(raw_ostream &OS,
StringRef InsnVarName) const override {
OS << InsnVarName << ".getOpcode() == " << I->Namespace
<< "::" << I->TheDef->getName();
}
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if is more important than B.
+ bool isHigherPriorityThan(const InstructionPredicateMatcher &B) const {
+ if (InstructionPredicateMatcher::isHigherPriorityThan(B))
+ return true;
+ if (B.InstructionPredicateMatcher::isHigherPriorityThan(*this))
+ return false;
+
+ // Prioritize opcodes for cosmetic reasons in the generated source. Although
+ // this is cosmetic at the moment, we may want to drive a similar ordering
+ // using instruction frequency information to improve compile time.
+ if (const InstructionOpcodeMatcher *BO =
+ dyn_cast<InstructionOpcodeMatcher>(&B))
+ return I->TheDef->getName() < BO->I->TheDef->getName();
+
+ return false;
+ };
};
/// Generates code to check that a set of predicates and operands match for a
@@ -255,6 +360,33 @@ public:
OS << ")";
}
}
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ bool isHigherPriorityThan(const InstructionMatcher &B) const {
+ // Instruction matchers involving more operands have higher priority.
+ if (Operands.size() > B.Operands.size())
+ return true;
+ if (Operands.size() < B.Operands.size())
+ return false;
+
+ for (const auto &Predicate : zip(predicates(), B.predicates())) {
+ if (std::get<0>(Predicate)->isHigherPriorityThan(*std::get<1>(Predicate)))
+ return true;
+ if (std::get<1>(Predicate)->isHigherPriorityThan(*std::get<0>(Predicate)))
+ return false;
+ }
+
+ for (const auto &Operand : zip(Operands, B.Operands)) {
+ if (std::get<0>(Operand).isHigherPriorityThan(std::get<1>(Operand)))
+ return true;
+ if (std::get<1>(Operand).isHigherPriorityThan(std::get<0>(Operand)))
+ return false;
+ }
+
+ return false;
+ };
};
//===- Actions ------------------------------------------------------------===//
@@ -352,6 +484,26 @@ public:
OS << " return true;\n";
OS << " }\n\n";
}
+
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ bool isHigherPriorityThan(const RuleMatcher &B) const {
+ // Rules involving more match roots have higher priority.
+ if (Matchers.size() > B.Matchers.size())
+ return true;
+ if (Matchers.size() < B.Matchers.size())
+ return false;
+
+ for (const auto &Matcher : zip(Matchers, B.Matchers)) {
+ if (std::get<0>(Matcher)->isHigherPriorityThan(*std::get<1>(Matcher)))
+ return true;
+ if (std::get<1>(Matcher)->isHigherPriorityThan(*std::get<0>(Matcher)))
+ return false;
+ }
+
+ return false;
+ };
};
//===- GlobalISelEmitter class --------------------------------------------===//
@@ -555,6 +707,17 @@ void GlobalISelEmitter::run(raw_ostream
Rules.push_back(std::move(MatcherOrErr.get()));
}
+ std::sort(Rules.begin(), Rules.end(),
+ [](const RuleMatcher &A, const RuleMatcher &B) {
+ if (A.isHigherPriorityThan(B)) {
+ assert(!B.isHigherPriorityThan(A) && "Cannot be more important "
+ "and less important at "
+ "the same time");
+ return true;
+ }
+ return false;
+ });
+
for (const auto &Rule : Rules) {
Rule.emit(OS);
++NumPatternEmitted;
More information about the llvm-commits
mailing list