summaryrefslogtreecommitdiffstats
path: root/llvm/utils/TableGen/GlobalISelEmitter.cpp
diff options
context:
space:
mode:
authorDaniel Sanders <daniel_l_sanders@apple.com>2017-07-04 14:35:06 +0000
committerDaniel Sanders <daniel_l_sanders@apple.com>2017-07-04 14:35:06 +0000
commit6ab0daade820ff12dafb861dfe8e2e5058435b8f (patch)
tree84379a3c426fcd5ad4a8085e08a23b6bcec01c68 /llvm/utils/TableGen/GlobalISelEmitter.cpp
parent90f69abc8b92f896625437616910adce2ae49db1 (diff)
downloadbcm5719-llvm-6ab0daade820ff12dafb861dfe8e2e5058435b8f.tar.gz
bcm5719-llvm-6ab0daade820ff12dafb861dfe8e2e5058435b8f.zip
[globalisel][tablegen] Partially fix compile-time regressions by converting matcher to state-machine(s)
Summary: Replace the matcher if-statements for each rule with a state-machine. This significantly reduces compile time, memory allocations, and cumulative memory allocation when compiling AArch64InstructionSelector.cpp.o after r303259 is recommitted. The following patches will expand on this further to fully fix the regressions. Reviewers: rovka, ab, t.p.northover, qcolombet, aditya_nandakumar Reviewed By: ab Subscribers: vitalybuka, aemerson, javed.absar, igorb, llvm-commits, kristof.beyls Differential Revision: https://reviews.llvm.org/D33758 llvm-svn: 307079
Diffstat (limited to 'llvm/utils/TableGen/GlobalISelEmitter.cpp')
-rw-r--r--llvm/utils/TableGen/GlobalISelEmitter.cpp455
1 files changed, 299 insertions, 156 deletions
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 924ed8f65c2..0a43337e606 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -74,6 +74,18 @@ private:
public:
LLTCodeGen(const LLT &Ty) : Ty(Ty) {}
+ void emitCxxEnumValue(raw_ostream &OS) const {
+ if (Ty.isScalar()) {
+ OS << "GILLT_s" << Ty.getSizeInBits();
+ return;
+ }
+ if (Ty.isVector()) {
+ OS << "GILLT_v" << Ty.getNumElements() << "s" << Ty.getScalarSizeInBits();
+ return;
+ }
+ llvm_unreachable("Unhandled LLT");
+ }
+
void emitCxxConstructorCall(raw_ostream &OS) const {
if (Ty.isScalar()) {
OS << "LLT::scalar(" << Ty.getSizeInBits() << ")";
@@ -88,6 +100,33 @@ public:
}
const LLT &get() const { return Ty; }
+
+ /// This ordering is used for std::unique() and std::sort(). There's no
+ /// particular logic behind the order.
+ bool operator<(const LLTCodeGen &Other) const {
+ if (!Ty.isValid())
+ return Other.Ty.isValid();
+ if (Ty.isScalar()) {
+ if (!Other.Ty.isValid())
+ return false;
+ if (Other.Ty.isScalar())
+ return Ty.getSizeInBits() < Other.Ty.getSizeInBits();
+ return false;
+ }
+ if (Ty.isVector()) {
+ if (!Other.Ty.isValid() || Other.Ty.isScalar())
+ return false;
+ if (Other.Ty.isVector()) {
+ if (Ty.getNumElements() < Other.Ty.getNumElements())
+ return true;
+ if (Ty.getNumElements() > Other.Ty.getNumElements())
+ return false;
+ return Ty.getSizeInBits() < Other.Ty.getSizeInBits();
+ }
+ return false;
+ }
+ llvm_unreachable("Unhandled LLT");
+ }
};
class InstructionMatcher;
@@ -169,6 +208,13 @@ static Record *getInitValueAsRegClass(Init *V) {
return nullptr;
}
+std::string
+getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) {
+ std::string Name = "GIFBS";
+ for (const auto &Feature : FeatureBitset)
+ Name += ("_" + Feature->getName()).str();
+ return Name;
+}
//===- Matchers -----------------------------------------------------------===//
class OperandMatcher;
@@ -188,7 +234,7 @@ class RuleMatcher {
/// A map of instruction matchers to the local variables created by
/// emitCxxCaptureStmts().
- std::map<const InstructionMatcher *, std::string> InsnVariableNames;
+ std::map<const InstructionMatcher *, unsigned> InsnVariableIDs;
/// ID for the next instruction variable defined with defineInsnVar()
unsigned NextInsnVarID;
@@ -197,35 +243,40 @@ class RuleMatcher {
public:
RuleMatcher()
- : Matchers(), Actions(), InsnVariableNames(), NextInsnVarID(0) {}
+ : Matchers(), Actions(), InsnVariableIDs(), NextInsnVarID(0) {}
RuleMatcher(RuleMatcher &&Other) = default;
RuleMatcher &operator=(RuleMatcher &&Other) = default;
InstructionMatcher &addInstructionMatcher();
void addRequiredFeature(Record *Feature);
+ const std::vector<Record *> &getRequiredFeatures() const;
template <class Kind, class... Args> Kind &addAction(Args &&... args);
- std::string defineInsnVar(raw_ostream &OS, const InstructionMatcher &Matcher,
- StringRef Value);
- StringRef getInsnVarName(const InstructionMatcher &InsnMatcher) const;
+ /// Define an instruction without emitting any code to do so.
+ /// This is used for the root of the match.
+ unsigned implicitlyDefineInsnVar(const InstructionMatcher &Matcher);
+ /// Define an instruction and emit corresponding state-machine opcodes.
+ unsigned defineInsnVar(raw_ostream &OS, const InstructionMatcher &Matcher,
+ unsigned InsnVarID, unsigned OpIdx);
+ unsigned getInsnVarID(const InstructionMatcher &InsnMatcher) const;
void emitCxxCapturedInsnList(raw_ostream &OS);
- void emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr);
+ void emitCxxCaptureStmts(raw_ostream &OS);
-void emit(raw_ostream &OS, SubtargetFeatureInfoMap SubtargetFeatures);
+ void emit(raw_ostream &OS);
-/// Compare the priority of this object and B.
-///
-/// Returns true if this object is more important than B.
-bool isHigherPriorityThan(const RuleMatcher &B) const;
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ bool isHigherPriorityThan(const RuleMatcher &B) const;
-/// Report the maximum number of temporary operands needed by the rule
-/// matcher.
-unsigned countRendererFns() const;
+ /// Report the maximum number of temporary operands needed by the rule
+ /// matcher.
+ unsigned countRendererFns() const;
-// FIXME: Remove this as soon as possible
-InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); }
+ // FIXME: Remove this as soon as possible
+ InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); }
};
template <class PredicateTy> class PredicateListMatcher {
@@ -259,17 +310,12 @@ public:
template <class... Args>
void emitCxxPredicateListExpr(raw_ostream &OS, Args &&... args) const {
if (Predicates.empty()) {
- OS << "true";
+ OS << "// No predicates\n";
return;
}
- StringRef Separator = "";
- for (const auto &Predicate : predicates()) {
- OS << Separator << "(";
+ for (const auto &Predicate : predicates())
Predicate->emitCxxPredicateExpr(OS, std::forward<Args>(args)...);
- OS << ")";
- Separator = " &&\n";
- }
}
};
@@ -322,11 +368,12 @@ public:
///
/// Only InstructionOperandMatcher needs to do anything for this method.
virtual void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule,
- StringRef Expr) const {}
+ unsigned InsnVarID, unsigned OpIdx) const {}
/// Emit a C++ expression that checks the predicate for the given operand.
virtual void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const = 0;
+ unsigned InsnVarID,
+ unsigned OpIdx) const = 0;
/// Compare the priority of this object and B.
///
@@ -354,10 +401,11 @@ public:
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << "MRI.getType(" << OperandExpr << ".getReg()) == (";
- Ty.emitCxxConstructorCall(OS);
- OS << ")";
+ unsigned InsnVarID, unsigned OpIdx) const override {
+ OS << " GIM_CheckType, /*MI*/" << InsnVarID << ", /*Op*/" << OpIdx
+ << ", /*Type*/";
+ Ty.emitCxxEnumValue(OS);
+ OS << ", \n";
}
};
@@ -380,10 +428,11 @@ public:
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
+ unsigned InsnVarID, unsigned OpIdx) const override {
unsigned ID = getAllocatedTemporariesBaseID();
- OS << "(Renderer" << ID << " = " << TheDef.getValueAsString("MatcherFn")
- << "(" << OperandExpr << "))";
+ OS << " GIM_CheckComplexPattern, /*MI*/" << InsnVarID << ", /*Op*/"
+ << OpIdx << ", /*Renderer*/" << ID << ", GICP_"
+ << TheDef.getName() << ",\n";
}
unsigned countRendererFns() const override {
@@ -405,10 +454,9 @@ public:
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << "(&RBI.getRegBankFromRegClass(" << RC.getQualifiedName()
- << "RegClass) == RBI.getRegBank(" << OperandExpr
- << ".getReg(), MRI, TRI))";
+ unsigned InsnVarID, unsigned OpIdx) const override {
+ OS << " GIM_CheckRegBankForClass, /*MI*/" << InsnVarID << ", /*Op*/"
+ << OpIdx << ", /*RC*/" << RC.getQualifiedName() << "RegClassID,\n";
}
};
@@ -422,8 +470,8 @@ public:
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << OperandExpr << ".isMBB()";
+ unsigned InsnVarID, unsigned OpIdx) const override {
+ OS << " GIM_CheckIsMBB, /*MI*/" << InsnVarID << ", /*Op*/" << OpIdx << ",\n";
}
};
@@ -442,8 +490,9 @@ public:
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << "isOperandImmEqual(" << OperandExpr << ", " << Value << ", MRI)";
+ unsigned InsnVarID, unsigned OpIdx) const override {
+ OS << " GIM_CheckConstantInt, /*MI*/" << InsnVarID << ", /*Op*/"
+ << OpIdx << ", " << Value << ",\n";
}
};
@@ -462,9 +511,9 @@ public:
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << OperandExpr << ".isCImm() && " << OperandExpr
- << ".getCImm()->equalsInt(" << Value << ")";
+ unsigned InsnVarID, unsigned OpIdx) const override {
+ OS << " GIM_CheckLiteralInt, /*MI*/" << InsnVarID << ", /*Op*/"
+ << OpIdx << ", " << Value << ",\n";
}
};
@@ -496,8 +545,9 @@ public:
}
unsigned getOperandIndex() const { return OpIdx; }
- std::string getOperandExpr(StringRef InsnVarName) const {
- return (InsnVarName + ".getOperand(" + llvm::to_string(OpIdx) + ")").str();
+ std::string getOperandExpr(unsigned InsnVarID) const {
+ return "State.MIs[" + llvm::to_string(InsnVarID) + "]->getOperand(" +
+ llvm::to_string(OpIdx) + ")";
}
Optional<const OperandMatcher *>
@@ -517,23 +567,22 @@ public:
/// Emit C++ statements to capture instructions into local variables.
void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const {
+ unsigned InsnVarID) const {
for (const auto &Predicate : predicates())
- Predicate->emitCxxCaptureStmts(OS, Rule, OperandExpr);
+ Predicate->emitCxxCaptureStmts(OS, Rule, InsnVarID, OpIdx);
}
/// Emit a C++ expression that tests whether the instruction named in
- /// InsnVarName matches all the predicate and all the operands.
+ /// InsnVarID matches all the predicates and all the operands.
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef InsnVarName) const {
- OS << "(/* ";
+ unsigned InsnVarID) const {
+ OS << " // MIs[" << InsnVarID << "] ";
if (SymbolicName.empty())
OS << "Operand " << OpIdx;
else
OS << SymbolicName;
- OS << " */ ";
- emitCxxPredicateListExpr(OS, Rule, getOperandExpr(InsnVarName));
- OS << ")";
+ OS << "\n";
+ emitCxxPredicateListExpr(OS, Rule, InsnVarID, OpIdx);
}
/// Compare the priority of this object and B.
@@ -600,9 +649,9 @@ public:
PredicateKind getKind() const { return Kind; }
/// Emit a C++ expression that tests whether the instruction named in
- /// InsnVarName matches the predicate.
+ /// InsnVarID matches the predicate.
virtual void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef InsnVarName) const = 0;
+ unsigned InsnVarID) const = 0;
/// Compare the priority of this object and B.
///
@@ -631,9 +680,9 @@ public:
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef InsnVarName) const override {
- OS << InsnVarName << ".getOpcode() == " << I->Namespace
- << "::" << I->TheDef->getName();
+ unsigned InsnVarID) const override {
+ OS << " GIM_CheckOpcode, /*MI*/" << InsnVarID << ", " << I->Namespace
+ << "::" << I->TheDef->getName() << ",\n";
}
/// Compare the priority of this object and B.
@@ -723,24 +772,21 @@ public:
/// Emit C++ statements to check the shape of the match and capture
/// instructions into local variables.
- void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, StringRef Expr) {
- OS << "if (" << Expr << ".getNumOperands() < " << getNumOperands() << ")\n"
- << " return false;\n";
- for (const auto &Operand : Operands) {
- Operand->emitCxxCaptureStmts(OS, Rule, Operand->getOperandExpr(Expr));
- }
+ void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule,
+ unsigned InsnID) {
+ OS << " GIM_CheckNumOperands, /*MI*/" << InsnID << ", /*Expected*/"
+ << getNumOperands() << ",\n";
+ for (const auto &Operand : Operands)
+ Operand->emitCxxCaptureStmts(OS, Rule, InsnID);
}
/// Emit a C++ expression that tests whether the instruction named in
/// InsnVarName matches all the predicates and all the operands.
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef InsnVarName) const {
- emitCxxPredicateListExpr(OS, Rule, InsnVarName);
- for (const auto &Operand : Operands) {
- OS << " &&\n(";
- Operand->emitCxxPredicateExpr(OS, Rule, InsnVarName);
- OS << ")";
- }
+ unsigned InsnVarID) const {
+ emitCxxPredicateListExpr(OS, Rule, InsnVarID);
+ for (const auto &Operand : Operands)
+ Operand->emitCxxPredicateExpr(OS, Rule, InsnVarID);
}
/// Compare the priority of this object and B.
@@ -818,23 +864,16 @@ public:
}
void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << "if (!" << OperandExpr + ".isReg())\n"
- << " return false;\n"
- << "if (TRI.isPhysicalRegister(" << OperandExpr + ".getReg()))\n"
- << " return false;\n";
- std::string InsnVarName = Rule.defineInsnVar(
- OS, *InsnMatcher,
- ("*MRI.getVRegDef(" + OperandExpr + ".getReg())").str());
- InsnMatcher->emitCxxCaptureStmts(OS, Rule, InsnVarName);
+ unsigned InsnID, unsigned OpIdx) const override {
+ unsigned InsnVarID = Rule.defineInsnVar(OS, *InsnMatcher, InsnID, OpIdx);
+ InsnMatcher->emitCxxCaptureStmts(OS, Rule, InsnVarID);
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OperandExpr = Rule.getInsnVarName(*InsnMatcher);
- OS << "(";
- InsnMatcher->emitCxxPredicateExpr(OS, Rule, OperandExpr);
- OS << ")\n";
+ unsigned InsnVarID_,
+ unsigned OpIdx_) const override {
+ unsigned InsnVarID = Rule.getInsnVarID(*InsnMatcher);
+ InsnMatcher->emitCxxPredicateExpr(OS, Rule, InsnVarID);
}
};
@@ -885,9 +924,9 @@ public:
void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override {
const OperandMatcher &Operand = Matched.getOperand(SymbolicName);
- StringRef InsnVarName =
- Rule.getInsnVarName(Operand.getInstructionMatcher());
- std::string OperandExpr = Operand.getOperandExpr(InsnVarName);
+ unsigned InsnVarID =
+ Rule.getInsnVarID(Operand.getInstructionMatcher());
+ std::string OperandExpr = Operand.getOperandExpr(InsnVarID);
OS << " MIB.add(" << OperandExpr << "/*" << SymbolicName << "*/);\n";
}
};
@@ -920,9 +959,8 @@ public:
void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override {
const OperandMatcher &Operand = Matched.getOperand(SymbolicName);
- StringRef InsnVarName =
- Rule.getInsnVarName(Operand.getInstructionMatcher());
- std::string OperandExpr = Operand.getOperandExpr(InsnVarName);
+ unsigned InsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
+ std::string OperandExpr = Operand.getOperandExpr(InsnVarID);
OS << " MIB.addReg(" << OperandExpr << ".getReg() /*" << SymbolicName
<< "*/, 0, " << SubReg->EnumValue << ");\n";
}
@@ -994,7 +1032,7 @@ public:
}
void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override {
- OS << "Renderer" << RendererID << "(MIB);\n";
+ OS << " State.Renderers[" << RendererID << "](MIB);\n";
}
};
@@ -1026,7 +1064,7 @@ public:
void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule,
StringRef RecycleVarName) const override {
- OS << "// " << *P.getSrcPattern() << " => " << *P.getDstPattern() << "\n";
+ OS << " // " << *P.getSrcPattern() << " => " << *P.getDstPattern() << "\n";
}
};
@@ -1102,7 +1140,7 @@ public:
// TODO: Simple permutation looks like it could be almost as common as
// mutation due to commutative operations.
- OS << "MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, "
+ OS << " MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, "
"I.getDebugLoc(), TII.get("
<< I->Namespace << "::" << I->TheDef->getName() << "));\n";
for (const auto &Renderer : OperandRenderers)
@@ -1160,25 +1198,36 @@ void RuleMatcher::addRequiredFeature(Record *Feature) {
RequiredFeatures.push_back(Feature);
}
+const std::vector<Record *> &RuleMatcher::getRequiredFeatures() const {
+ return RequiredFeatures;
+}
+
template <class Kind, class... Args>
Kind &RuleMatcher::addAction(Args &&... args) {
Actions.emplace_back(llvm::make_unique<Kind>(std::forward<Args>(args)...));
return *static_cast<Kind *>(Actions.back().get());
}
-std::string RuleMatcher::defineInsnVar(raw_ostream &OS,
- const InstructionMatcher &Matcher,
- StringRef Value) {
- std::string InsnVarName = "MI" + llvm::to_string(NextInsnVarID++);
- OS << "MachineInstr &" << InsnVarName << " = " << Value << ";\n";
- InsnVariableNames[&Matcher] = InsnVarName;
- return InsnVarName;
+unsigned
+RuleMatcher::implicitlyDefineInsnVar(const InstructionMatcher &Matcher) {
+ unsigned NewInsnVarID = NextInsnVarID++;
+ InsnVariableIDs[&Matcher] = NewInsnVarID;
+ return NewInsnVarID;
}
-StringRef
-RuleMatcher::getInsnVarName(const InstructionMatcher &InsnMatcher) const {
- const auto &I = InsnVariableNames.find(&InsnMatcher);
- if (I != InsnVariableNames.end())
+unsigned RuleMatcher::defineInsnVar(raw_ostream &OS,
+ const InstructionMatcher &Matcher,
+ unsigned InsnID, unsigned OpIdx) {
+ unsigned NewInsnVarID = implicitlyDefineInsnVar(Matcher);
+ OS << " GIM_RecordInsn, /*DefineMI*/" << NewInsnVarID << ", /*MI*/"
+ << InsnID << ", /*OpIdx*/" << OpIdx << ", // MIs[" << NewInsnVarID
+ << "]\n";
+ return NewInsnVarID;
+}
+
+unsigned RuleMatcher::getInsnVarID(const InstructionMatcher &InsnMatcher) const {
+ const auto &I = InsnVariableIDs.find(&InsnMatcher);
+ if (I != InsnVariableIDs.end())
return I->second;
llvm_unreachable("Matched Insn was not captured in a local variable");
}
@@ -1186,27 +1235,26 @@ RuleMatcher::getInsnVarName(const InstructionMatcher &InsnMatcher) const {
/// Emit a C++ initializer_list containing references to every matched
/// instruction.
void RuleMatcher::emitCxxCapturedInsnList(raw_ostream &OS) {
- SmallVector<StringRef, 2> Names;
- for (const auto &Pair : InsnVariableNames)
- Names.push_back(Pair.second);
- std::sort(Names.begin(), Names.end());
+ SmallVector<unsigned, 2> IDs;
+ for (const auto &Pair : InsnVariableIDs)
+ IDs.push_back(Pair.second);
+ std::sort(IDs.begin(), IDs.end());
OS << "{";
- for (const auto &Name : Names)
- OS << "&" << Name << ", ";
+ for (const auto &ID : IDs)
+ OS << "State.MIs[" << ID << "], ";
OS << "}";
}
/// Emit C++ statements to check the shape of the match and capture
/// instructions into local variables.
-void RuleMatcher::emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr) {
+void RuleMatcher::emitCxxCaptureStmts(raw_ostream &OS) {
assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet");
- std::string InsnVarName = defineInsnVar(OS, *Matchers.front(), Expr);
- Matchers.front()->emitCxxCaptureStmts(OS, *this, InsnVarName);
+ unsigned InsnVarID = implicitlyDefineInsnVar(*Matchers.front());
+ Matchers.front()->emitCxxCaptureStmts(OS, *this, InsnVarID);
}
-void RuleMatcher::emit(raw_ostream &OS,
- SubtargetFeatureInfoMap SubtargetFeatures) {
+void RuleMatcher::emit(raw_ostream &OS) {
if (Matchers.empty())
llvm_unreachable("Unexpected empty matcher!");
@@ -1221,47 +1269,43 @@ void RuleMatcher::emit(raw_ostream &OS,
// 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 (";
- OS << "[&]() {\n";
+ OS << " const static int64_t MatchTable" << NumPatternEmitted << "[] = {\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";
+ OS << " GIM_CheckFeatures, " << getNameForFeatureBitset(RequiredFeatures)
+ << ",\n";
}
- emitCxxCaptureStmts(OS, "I");
- OS << " if (";
+ emitCxxCaptureStmts(OS);
+
Matchers.front()->emitCxxPredicateExpr(OS, *this,
- getInsnVarName(*Matchers.front()));
- OS << ") {\n";
+ getInsnVarID(*Matchers.front()));
+
+ OS << " GIM_Accept,\n"
+ << " };\n"
+ << " State.MIs.clear();\n"
+ << " State.MIs.push_back(&I);\n"
+ << " if (executeMatchTable(*this, State, MatcherInfo, MatchTable"
+ << NumPatternEmitted << ", MRI, TRI, RBI, AvailableFeatures)) {\n";
// We must also check if it's safe to fold the matched instructions.
- if (InsnVariableNames.size() >= 2) {
+ if (InsnVariableIDs.size() >= 2) {
// Invert the map to create stable ordering (by var names)
- SmallVector<StringRef, 2> Names;
- for (const auto &Pair : InsnVariableNames) {
+ SmallVector<unsigned, 2> InsnIDs;
+ for (const auto &Pair : InsnVariableIDs) {
// Skip the root node since it isn't moving anywhere. Everything else is
// sinking to meet it.
if (Pair.first == Matchers.front().get())
continue;
- Names.push_back(Pair.second);
+ InsnIDs.push_back(Pair.second);
}
- std::sort(Names.begin(), Names.end());
+ std::sort(InsnIDs.begin(), InsnIDs.end());
- for (const auto &Name : Names) {
+ for (const auto &InsnID : InsnIDs) {
// Reject the difficult cases until we have a more accurate check.
- OS << " if (!isObviouslySafeToFold(" << Name
- << ")) return false;\n";
+ OS << " if (!isObviouslySafeToFold(*State.MIs[" << InsnID << "]))\n"
+ << " return false;\n";
// FIXME: Emit checks to determine it's _actually_ safe to fold and/or
// account for unsafe cases.
@@ -1304,10 +1348,8 @@ void RuleMatcher::emit(raw_ostream &OS,
MA->emitCxxActionStmts(OS, *this, "I");
}
- OS << " return true;\n";
- OS << " }\n";
- OS << " return false;\n";
- OS << " }()) { return true; }\n\n";
+ OS << " return true;\n";
+ OS << " }\n\n";
}
bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const {
@@ -1969,6 +2011,14 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
return false;
});
+ std::vector<Record *> ComplexPredicates =
+ RK.getAllDerivedDefinitions("GIComplexOperandMatcher");
+ std::sort(ComplexPredicates.begin(), ComplexPredicates.end(),
+ [](const Record *A, const Record *B) {
+ if (A->getName() < B->getName())
+ return true;
+ return false;
+ });
unsigned MaxTemporaries = 0;
for (const auto &Rule : Rules)
MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());
@@ -1980,15 +2030,26 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
"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 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 << ", Renderer" << I << "(nullptr)\n";
- OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n";
+ OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n"
+ << " mutable MatcherState State;\n"
+ << " typedef "
+ "ComplexRendererFn("
+ << Target.getName()
+ << "InstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const;\n"
+ << "const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> "
+ "MatcherInfo;\n"
+ << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n";
+
+ OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"
+ << ", State(" << MaxTemporaries << "),\n"
+ << "MatcherInfo({TypeObjects, FeatureBitsets, {\n"
+ << " nullptr, // GICP_Invalid\n";
+ for (const auto &Record : ComplexPredicates)
+ OS << " &" << Target.getName()
+ << "InstructionSelector::" << Record->getValueAsString("MatcherFn")
+ << ", // " << Record->getName() << "\n";
+ OS << "}})\n"
+ << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n";
OS << "#ifdef GET_GLOBALISEL_IMPL\n";
SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures,
@@ -2016,10 +2077,92 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
"computeAvailableFunctionFeatures", FunctionFeatures, OS,
"const MachineFunction *MF");
+ // Emit a table containing the LLT objects needed by the matcher and an enum
+ // for the matcher to reference them with.
+ std::vector<LLTCodeGen> TypeObjects = {
+ LLT::scalar(8), LLT::scalar(16), LLT::scalar(32),
+ LLT::scalar(64), LLT::scalar(80), LLT::vector(8, 1),
+ LLT::vector(16, 1), LLT::vector(32, 1), LLT::vector(64, 1),
+ LLT::vector(8, 8), LLT::vector(16, 8), LLT::vector(32, 8),
+ LLT::vector(64, 8), LLT::vector(4, 16), LLT::vector(8, 16),
+ LLT::vector(16, 16), LLT::vector(32, 16), LLT::vector(2, 32),
+ LLT::vector(4, 32), LLT::vector(8, 32), LLT::vector(16, 32),
+ LLT::vector(2, 64), LLT::vector(4, 64), LLT::vector(8, 64),
+ };
+ std::sort(TypeObjects.begin(), TypeObjects.end());
+ OS << "enum {\n";
+ for (const auto &TypeObject : TypeObjects) {
+ OS << " ";
+ TypeObject.emitCxxEnumValue(OS);
+ OS << ",\n";
+ }
+ OS << "};\n"
+ << "const static LLT TypeObjects[] = {\n";
+ for (const auto &TypeObject : TypeObjects) {
+ OS << " ";
+ TypeObject.emitCxxConstructorCall(OS);
+ OS << ",\n";
+ }
+ OS << "};\n\n";
+
+ // Emit a table containing the PredicateBitsets objects needed by the matcher
+ // and an enum for the matcher to reference them with.
+ std::vector<std::vector<Record *>> FeatureBitsets;
+ for (auto &Rule : Rules)
+ FeatureBitsets.push_back(Rule.getRequiredFeatures());
+ std::sort(
+ FeatureBitsets.begin(), FeatureBitsets.end(),
+ [&](const std::vector<Record *> &A, const std::vector<Record *> &B) {
+ if (A.size() < B.size())
+ return true;
+ if (A.size() > B.size())
+ return false;
+ for (const auto &Pair : zip(A, B)) {
+ if (std::get<0>(Pair)->getName() < std::get<1>(Pair)->getName())
+ return true;
+ if (std::get<0>(Pair)->getName() > std::get<1>(Pair)->getName())
+ return false;
+ }
+ return false;
+ });
+ FeatureBitsets.erase(
+ std::unique(FeatureBitsets.begin(), FeatureBitsets.end()),
+ FeatureBitsets.end());
+ OS << "enum {\n"
+ << " GIFBS_Invalid,\n";
+ for (const auto &FeatureBitset : FeatureBitsets) {
+ if (FeatureBitset.empty())
+ continue;
+ OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
+ }
+ OS << "};\n"
+ << "const static PredicateBitset FeatureBitsets[] {\n"
+ << " {}, // GIFBS_Invalid\n";
+ for (const auto &FeatureBitset : FeatureBitsets) {
+ if (FeatureBitset.empty())
+ continue;
+ OS << " {";
+ for (const auto &Feature : FeatureBitset) {
+ const auto &I = SubtargetFeatures.find(Feature);
+ assert(I != SubtargetFeatures.end() && "Didn't import predicate?");
+ OS << I->second.getEnumBitName() << ", ";
+ }
+ OS << "},\n";
+ }
+ OS << "};\n\n";
+
+ // Emit complex predicate table and an enum to reference them with.
+ OS << "enum {\n"
+ << " GICP_Invalid,\n";
+ for (const auto &Record : ComplexPredicates)
+ OS << " GICP_" << Record->getName() << ",\n";
+ OS << "};\n"
+ << "// See constructor for table contents\n\n";
+
OS << "bool " << Target.getName()
<< "InstructionSelector::selectImpl(MachineInstr &I) const {\n"
<< " MachineFunction &MF = *I.getParent()->getParent();\n"
- << " const MachineRegisterInfo &MRI = MF.getRegInfo();\n"
+ << " MachineRegisterInfo &MRI = MF.getRegInfo();\n"
<< " // FIXME: This should be computed on a per-function basis rather "
"than per-insn.\n"
<< " AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, "
@@ -2027,7 +2170,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
<< " const PredicateBitset AvailableFeatures = getAvailableFeatures();\n";
for (auto &Rule : Rules) {
- Rule.emit(OS, SubtargetFeatures);
+ Rule.emit(OS);
++NumPatternEmitted;
}
OpenPOWER on IntegriCloud