summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorDaniel Sanders <daniel_l_sanders@apple.com>2017-03-20 15:20:42 +0000
committerDaniel Sanders <daniel_l_sanders@apple.com>2017-03-20 15:20:42 +0000
commit1111ea1a18939df766e18439e84ac2c6155318a1 (patch)
tree43a6fa964dcb2409a3ca69919082b2f249ee4846 /utils
parent194f24401fe31d741f582e527fd26ad70d899075 (diff)
[tablegen][globalisel] Capture instructions into locals and related infrastructure for multiple instructions matches.
Summary: Prepare the way for nested instruction matching support by having actions like CopyRenderer look up operands in the RuleMatcher rather than a specific InstructionMatcher. This allows actions to reference any operand from any matched instruction. It works by checking the 'shape' of the match and capturing each matched instruction to a local variable. If the shape is wrong (not enough operands, leaf nodes where non-leafs are expected, etc.), then the rule exits early without checking the predicates. Once we've captured the instructions, we then test the predicates as before (except using the local variables). If the match is successful, then we render the new instruction as before using the local variables. It's not noticable in this patch but by the time we support multiple instruction matching, this patch will also cause a significant improvement to readability of the emitted code since MRI.getVRegDef(I->getOperand(0).getReg()) will simply be MI1 after emitCxxCaptureStmts(). This isn't quite NFC because I've also fixed a bug that I'm surprised we haven't encountered yet. It now checks there are at least the expected number of operands before accessing them with getOperand(). Depends on D30531 Reviewers: t.p.northover, qcolombet, aditya_nandakumar, ab, rovka Reviewed By: rovka Subscribers: dberris, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D30535 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@298257 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils')
-rw-r--r--utils/TableGen/GlobalISelEmitter.cpp185
1 files changed, 125 insertions, 60 deletions
diff --git a/utils/TableGen/GlobalISelEmitter.cpp b/utils/TableGen/GlobalISelEmitter.cpp
index 35b5ac80ab0..ae386ae98e1 100644
--- a/utils/TableGen/GlobalISelEmitter.cpp
+++ b/utils/TableGen/GlobalISelEmitter.cpp
@@ -164,14 +164,28 @@ class RuleMatcher {
/// have succeeded.
std::vector<std::unique_ptr<MatchAction>> Actions;
+ /// A map of instruction matchers to the local variables created by
+ /// emitCxxCaptureStmts().
+ std::map<const InstructionMatcher *, std::string> InsnVariableNames;
+
+ /// ID for the next instruction variable defined with defineInsnVar()
+ unsigned NextInsnVarID;
+
public:
- RuleMatcher() {}
+ RuleMatcher()
+ : Matchers(), Actions(), InsnVariableNames(), NextInsnVarID(0) {}
InstructionMatcher &addInstructionMatcher();
template <class Kind, class... Args> Kind &addAction(Args &&... args);
- void emit(raw_ostream &OS) const;
+ std::string defineInsnVar(raw_ostream &OS, const InstructionMatcher &Matcher,
+ StringRef Value);
+ StringRef getInsnVarName(const InstructionMatcher &InsnMatcher) const;
+
+ void emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr);
+
+ void emit(raw_ostream &OS);
/// Compare the priority of this object and B.
///
@@ -255,7 +269,7 @@ public:
PredicateKind getKind() const { return Kind; }
/// Emit a C++ expression that checks the predicate for the given operand.
- virtual void emitCxxPredicateExpr(raw_ostream &OS,
+ virtual void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
StringRef OperandExpr) const = 0;
/// Compare the priority of this object and B.
@@ -283,7 +297,7 @@ public:
return P->getKind() == OPM_LLT;
}
- void emitCxxPredicateExpr(raw_ostream &OS,
+ void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
StringRef OperandExpr) const override {
OS << "MRI.getType(" << OperandExpr << ".getReg()) == (";
Ty.emitCxxConstructorCall(OS);
@@ -308,7 +322,7 @@ public:
: OperandPredicateMatcher(OPM_ComplexPattern), TheDef(TheDef),
BaseTemporaryID(BaseTemporaryID) {}
- void emitCxxPredicateExpr(raw_ostream &OS,
+ void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
StringRef OperandExpr) const override {
OS << TheDef.getValueAsString("MatcherFn") << "(" << OperandExpr;
for (unsigned I = 0; I < getNumOperands(); ++I) {
@@ -337,7 +351,7 @@ public:
return P->getKind() == OPM_RegBank;
}
- void emitCxxPredicateExpr(raw_ostream &OS,
+ void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
StringRef OperandExpr) const override {
OS << "(&RBI.getRegBankFromRegClass(" << RC.getQualifiedName()
<< "RegClass) == RBI.getRegBank(" << OperandExpr
@@ -354,7 +368,7 @@ public:
return P->getKind() == OPM_MBB;
}
- void emitCxxPredicateExpr(raw_ostream &OS,
+ void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
StringRef OperandExpr) const override {
OS << OperandExpr << ".isMBB()";
}
@@ -373,7 +387,7 @@ public:
return P->getKind() == OPM_Int;
}
- void emitCxxPredicateExpr(raw_ostream &OS,
+ void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
StringRef OperandExpr) const override {
OS << "isOperandImmEqual(" << OperandExpr << ", " << Value << ", MRI)";
}
@@ -383,12 +397,14 @@ public:
/// operand.
class OperandMatcher : public PredicateListMatcher<OperandPredicateMatcher> {
protected:
+ InstructionMatcher &Insn;
unsigned OpIdx;
std::string SymbolicName;
public:
- OperandMatcher(unsigned OpIdx, const std::string &SymbolicName)
- : OpIdx(OpIdx), SymbolicName(SymbolicName) {}
+ OperandMatcher(InstructionMatcher &Insn, unsigned OpIdx,
+ const std::string &SymbolicName)
+ : Insn(Insn), OpIdx(OpIdx), SymbolicName(SymbolicName) {}
bool hasSymbolicName() const { return !SymbolicName.empty(); }
const StringRef getSymbolicName() const { return SymbolicName; }
@@ -398,16 +414,19 @@ public:
return (InsnVarName + ".getOperand(" + llvm::to_string(OpIdx) + ")").str();
}
+ InstructionMatcher &getInstructionMatcher() const { return Insn; }
+
/// Emit a C++ expression that tests whether the instruction named in
/// InsnVarName matches all the predicate and all the operands.
- void emitCxxPredicateExpr(raw_ostream &OS, const StringRef InsnVarName) const {
+ void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
+ const StringRef InsnVarName) const {
OS << "(/* ";
if (SymbolicName.empty())
OS << "Operand " << OpIdx;
else
OS << SymbolicName;
OS << " */ ";
- emitCxxPredicateListExpr(OS, getOperandExpr(InsnVarName));
+ emitCxxPredicateListExpr(OS, Rule, getOperandExpr(InsnVarName));
OS << ")";
}
@@ -468,7 +487,7 @@ public:
/// Emit a C++ expression that tests whether the instruction named in
/// InsnVarName matches the predicate.
- virtual void emitCxxPredicateExpr(raw_ostream &OS,
+ virtual void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
StringRef InsnVarName) const = 0;
/// Compare the priority of this object and B.
@@ -496,7 +515,7 @@ public:
return P->getKind() == IPM_Opcode;
}
- void emitCxxPredicateExpr(raw_ostream &OS,
+ void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
StringRef InsnVarName) const override {
OS << InsnVarName << ".getOpcode() == " << I->Namespace
<< "::" << I->TheDef->getName();
@@ -540,18 +559,25 @@ protected:
public:
/// Add an operand to the matcher.
OperandMatcher &addOperand(unsigned OpIdx, const std::string &SymbolicName) {
- Operands.emplace_back(OpIdx, SymbolicName);
+ Operands.emplace_back(*this, OpIdx, SymbolicName);
return Operands.back();
}
- const OperandMatcher &getOperand(const StringRef SymbolicName) const {
+ Optional<const OperandMatcher *> getOptionalOperand(StringRef SymbolicName) const {
assert(!SymbolicName.empty() && "Cannot lookup unnamed operand");
const auto &I = std::find_if(Operands.begin(), Operands.end(),
[&SymbolicName](const OperandMatcher &X) {
return X.getSymbolicName() == SymbolicName;
});
if (I != Operands.end())
- return *I;
+ return &*I;
+ return None;
+ }
+
+ const OperandMatcher &getOperand(const StringRef SymbolicName) const {
+ Optional<const OperandMatcher *>OM = getOptionalOperand(SymbolicName);
+ if (OM.hasValue())
+ return *OM.getValue();
llvm_unreachable("Failed to lookup operand");
}
@@ -566,13 +592,24 @@ public:
return make_range(operands_begin(), operands_end());
}
+ /// Emit C++ statements to check the shape of the match and capture
+ /// instructions into local variables.
+ ///
+ /// TODO: When nested instruction matching is implemented, this function will
+ /// descend into the operands and capture variables.
+ void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, StringRef Expr) {
+ OS << "if (" << Expr << ".getNumOperands() < " << getNumOperands() << ")\n"
+ << " return false;\n";
+ }
+
/// 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, StringRef InsnVarName) const {
- emitCxxPredicateListExpr(OS, InsnVarName);
+ void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
+ StringRef InsnVarName) const {
+ emitCxxPredicateListExpr(OS, Rule, InsnVarName);
for (const auto &Operand : Operands) {
OS << " &&\n(";
- Operand.emitCxxPredicateExpr(OS, InsnVarName);
+ Operand.emitCxxPredicateExpr(OS, Rule, InsnVarName);
OS << ")";
}
}
@@ -646,7 +683,7 @@ public:
RendererKind getKind() const { return Kind; }
- virtual void emitCxxRenderStmts(raw_ostream &OS) const = 0;
+ virtual void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const = 0;
};
/// A CopyRenderer emits code to copy a single operand from an existing
@@ -657,16 +694,13 @@ protected:
/// This provides the facility for looking up an a operand by it's name so
/// that it can be used as a source for the instruction being built.
const InstructionMatcher &Matched;
- /// The name of the instruction to copy from.
- const StringRef InsnVarName;
/// The name of the operand.
const StringRef SymbolicName;
public:
- CopyRenderer(const InstructionMatcher &Matched, const StringRef InsnVarName,
- const StringRef SymbolicName)
- : OperandRenderer(OR_Copy), Matched(Matched), InsnVarName(InsnVarName),
- SymbolicName(SymbolicName) {}
+ CopyRenderer(const InstructionMatcher &Matched, StringRef SymbolicName)
+ : OperandRenderer(OR_Copy), Matched(Matched), SymbolicName(SymbolicName) {
+ }
static bool classof(const OperandRenderer *R) {
return R->getKind() == OR_Copy;
@@ -674,9 +708,11 @@ public:
const StringRef getSymbolicName() const { return SymbolicName; }
- void emitCxxRenderStmts(raw_ostream &OS) const override {
- std::string OperandExpr =
- Matched.getOperand(SymbolicName).getOperandExpr(InsnVarName);
+ 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);
OS << " MIB.add(" << OperandExpr << "/*" << SymbolicName << "*/);\n";
}
};
@@ -695,7 +731,7 @@ public:
return R->getKind() == OR_Register;
}
- void emitCxxRenderStmts(raw_ostream &OS) const override {
+ void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override {
OS << " MIB.addReg(" << RegisterDef->getValueAsString("Namespace")
<< "::" << RegisterDef->getName() << ");\n";
}
@@ -719,7 +755,7 @@ public:
return R->getKind() == OR_ComplexPattern;
}
- void emitCxxRenderStmts(raw_ostream &OS) const override {
+ void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override {
assert(Sources.size() == getNumOperands() && "Inconsistent number of operands");
for (const auto &Source : Sources) {
OS << "MIB.add(";
@@ -740,11 +776,11 @@ public:
/// Emit the C++ statements to implement the action.
///
- /// \param InsnVarName If given, it's an instruction to recycle. The
- /// requirements on the instruction vary from action to
- /// action.
- virtual void emitCxxActionStmts(raw_ostream &OS,
- const StringRef InsnVarName) const = 0;
+ /// \param RecycleVarName If given, it's an instruction to recycle. The
+ /// requirements on the instruction vary from action to
+ /// action.
+ virtual void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule,
+ StringRef RecycleVarName) const = 0;
};
/// Generates a comment describing the matched rule being acted upon.
@@ -755,9 +791,9 @@ private:
public:
DebugCommentAction(const PatternToMatch &P) : P(P) {}
- void emitCxxActionStmts(raw_ostream &OS,
- const StringRef InsnVarName) const override {
- OS << "// " << *P.getSrcPattern() << " => " << *P.getDstPattern();
+ void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule,
+ StringRef RecycleVarName) const override {
+ OS << "// " << *P.getSrcPattern() << " => " << *P.getDstPattern() << "\n";
}
};
@@ -794,12 +830,12 @@ public:
return *static_cast<Kind *>(OperandRenderers.back().get());
}
- virtual void emitCxxActionStmts(raw_ostream &OS,
- const StringRef InsnVarName) const {
+ void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule,
+ StringRef RecycleVarName) const override {
if (canMutate()) {
- OS << "I.setDesc(TII.get(" << I->Namespace << "::" << I->TheDef->getName()
- << "));\n";
- OS << " MachineInstr &NewI = I;\n";
+ OS << RecycleVarName << ".setDesc(TII.get(" << I->Namespace
+ << "::" << I->TheDef->getName() << "));\n";
+ OS << " MachineInstr &NewI = " << RecycleVarName << ";\n";
return;
}
@@ -810,9 +846,9 @@ public:
"I.getDebugLoc(), TII.get("
<< I->Namespace << "::" << I->TheDef->getName() << "));\n";
for (const auto &Renderer : OperandRenderers)
- Renderer->emitCxxRenderStmts(OS);
+ Renderer->emitCxxRenderStmts(OS, Rule);
OS << " MIB.setMemRefs(I.memoperands_begin(), I.memoperands_end());\n";
- OS << " " << InsnVarName << ".eraseFromParent();\n";
+ OS << " " << RecycleVarName << ".eraseFromParent();\n";
OS << " MachineInstr &NewI = *MIB;\n";
}
};
@@ -828,7 +864,31 @@ Kind &RuleMatcher::addAction(Args &&... args) {
return *static_cast<Kind *>(Actions.back().get());
}
-void RuleMatcher::emit(raw_ostream &OS) const {
+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;
+}
+
+StringRef RuleMatcher::getInsnVarName(const InstructionMatcher &InsnMatcher) const {
+ const auto &I = InsnVariableNames.find(&InsnMatcher);
+ if (I != InsnVariableNames.end())
+ return I->second;
+ llvm_unreachable("Matched Insn was not captured in a local variable");
+}
+
+/// Emit C++ statements to check the shape of the match and capture
+/// instructions into local variables.
+void RuleMatcher::emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr) {
+ assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet");
+ std::string InsnVarName = defineInsnVar(OS, *Matchers.front(), Expr);
+ Matchers.front()->emitCxxCaptureStmts(OS, *this, InsnVarName);
+}
+
+void RuleMatcher::emit(raw_ostream &OS) {
if (Matchers.empty())
llvm_unreachable("Unexpected empty matcher!");
@@ -842,19 +902,24 @@ void RuleMatcher::emit(raw_ostream &OS) const {
// %elt0(s32), %elt1(s32) = TGT_LOAD_PAIR %ptr
// 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 (";
- Matchers.front()->emitCxxPredicateExpr(OS, "I");
+ OS << "if ([&]() {\n";
+
+ emitCxxCaptureStmts(OS, "I");
+
+ OS << " if (";
+ Matchers.front()->emitCxxPredicateExpr(OS, *this,
+ getInsnVarName(*Matchers.front()));
OS << ") {\n";
for (const auto &MA : Actions) {
- OS << " ";
- MA->emitCxxActionStmts(OS, "I");
- OS << "\n";
+ MA->emitCxxActionStmts(OS, *this, "I");
}
- OS << " constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);\n";
- OS << " return true;\n";
- OS << " }\n\n";
+ OS << " constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);\n";
+ OS << " return true;\n";
+ OS << " }\n";
+ OS << " return false;\n";
+ OS << " }()) { return true; }\n\n";
}
bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const {
@@ -1007,7 +1072,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
OM.addPredicate<LLTOperandMatcher>(*OpTyOrNone);
OM.addPredicate<RegisterBankOperandMatcher>(
Target.getRegisterClass(DstIOpRec));
- DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, "I", DstIOperand.Name);
+ DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, DstIOperand.Name);
++OpIdx;
}
@@ -1086,7 +1151,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
if (DstChild->getOperator()->isSubClassOf("SDNode")) {
auto &ChildSDNI = CGP.getSDNodeInfo(DstChild->getOperator());
if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") {
- DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, "I",
+ DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher,
DstChild->getName());
continue;
}
@@ -1115,7 +1180,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
}
if (ChildRec->isSubClassOf("RegisterClass")) {
- DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, "I",
+ DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher,
DstChild->getName());
continue;
}
@@ -1210,7 +1275,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
<< " MachineFunction &MF = *I.getParent()->getParent();\n"
<< " const MachineRegisterInfo &MRI = MF.getRegInfo();\n";
- for (const auto &Rule : Rules) {
+ for (auto &Rule : Rules) {
Rule.emit(OS);
++NumPatternEmitted;
}