//===- Test a simple pattern with regclass operands. ----------------------===//
-// CHECK-LABEL: if ((I.getOpcode() == TargetOpcode::G_ADD) &&
-// CHECK-NEXT: ((/* dst */ (MRI.getType(I.getOperand(0).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(I.getOperand(0).getReg(), MRI, TRI))))) &&
-// CHECK-NEXT: ((/* src1 */ (MRI.getType(I.getOperand(1).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(I.getOperand(1).getReg(), MRI, TRI))))) &&
-// CHECK-NEXT: ((/* src2 */ (MRI.getType(I.getOperand(2).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(I.getOperand(2).getReg(), MRI, TRI)))))) {
-
-// CHECK-NEXT: // (add:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (ADD:i32 GPR32:i32:$src1, GPR32:i32:$src2)
-// CHECK-NEXT: I.setDesc(TII.get(MyTarget::ADD));
-// CHECK-NEXT: MachineInstr &NewI = I;
-// CHECK: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);
-// CHECK-NEXT: return true;
-// CHECK-NEXT: }
+// CHECK-LABEL: if ([&]() {
+// CHECK-NEXT: MachineInstr &MI0 = I;
+// CHECK-NEXT: if (MI0.getNumOperands() < 3)
+// CHECK-NEXT: return false;
+// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_ADD) &&
+// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) &&
+// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) &&
+// CHECK-NEXT: ((/* src2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(2).getReg(), MRI, TRI)))))) {
+
+// CHECK-NEXT: // (add:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (ADD:i32 GPR32:i32:$src1, GPR32:i32:$src2)
+// CHECK-NEXT: I.setDesc(TII.get(MyTarget::ADD));
+// CHECK-NEXT: MachineInstr &NewI = I;
+// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);
+// CHECK-NEXT: return true;
+// CHECK-NEXT: }
+// CHECK-NEXT: return false;
+// CHECK-NEXT: }()) { return true; }
+
def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2),
[(set GPR32:$dst, (add GPR32:$src1, GPR32:$src2))]>;
-// CHECK-LABEL: if ((I.getOpcode() == TargetOpcode::G_MUL) &&
-// CHECK-NEXT: ((/* dst */ (MRI.getType(I.getOperand(0).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(I.getOperand(0).getReg(), MRI, TRI))))) &&
-// CHECK-NEXT: ((/* src1 */ (MRI.getType(I.getOperand(1).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(I.getOperand(1).getReg(), MRI, TRI))))) &&
-// CHECK-NEXT: ((/* src2 */ (MRI.getType(I.getOperand(2).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(I.getOperand(2).getReg(), MRI, TRI)))))) {
-
-// CHECK-NEXT: // (mul:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (MUL:i32 GPR32:i32:$src2, GPR32:i32:$src1)
-// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MUL));
-// CHECK-NEXT: MIB.add(I.getOperand(0)/*dst*/);
-// CHECK-NEXT: MIB.add(I.getOperand(2)/*src2*/);
-// CHECK-NEXT: MIB.add(I.getOperand(1)/*src1*/);
-// CHECK-NEXT: MIB.setMemRefs(I.memoperands_begin(), I.memoperands_end());
-// CHECK-NEXT: I.eraseFromParent();
-// CHECK-NEXT: MachineInstr &NewI = *MIB;
-// CHECK: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);
-// CHECK-NEXT: return true;
-// CHECK-NEXT: }
+// CHECK-LABEL: if ([&]() {
+// CHECK-NEXT: MachineInstr &MI0 = I;
+// CHECK-NEXT: if (MI0.getNumOperands() < 3)
+// CHECK-NEXT: return false;
+// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_MUL) &&
+// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) &&
+// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) &&
+// CHECK-NEXT: ((/* src2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(2).getReg(), MRI, TRI)))))) {
+// CHECK-NEXT: // (mul:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (MUL:i32 GPR32:i32:$src2, GPR32:i32:$src1)
+// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MUL));
+// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/);
+// CHECK-NEXT: MIB.add(MI0.getOperand(2)/*src2*/);
+// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/);
+// CHECK-NEXT: MIB.setMemRefs(I.memoperands_begin(), I.memoperands_end());
+// CHECK-NEXT: I.eraseFromParent();
+// CHECK-NEXT: MachineInstr &NewI = *MIB;
+// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);
+// CHECK-NEXT: return true;
+// CHECK-NEXT: }
+// CHECK-NEXT: return false;
+// CHECK-NEXT: }()) { return true; }
def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1),
[(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>;
// This must precede the 3-register variants because constant immediates have
// priority over register banks.
-// CHECK-LABEL: if ((I.getOpcode() == TargetOpcode::G_XOR) &&
-// CHECK-NEXT: ((/* dst */ (MRI.getType(I.getOperand(0).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(I.getOperand(0).getReg(), MRI, TRI))))) &&
-// CHECK-NEXT: ((/* Wm */ (MRI.getType(I.getOperand(1).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(I.getOperand(1).getReg(), MRI, TRI))))) &&
-// CHECK-NEXT: ((/* Operand 2 */ (MRI.getType(I.getOperand(2).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: (isOperandImmEqual(I.getOperand(2), -1, MRI))))) {
-
-// CHECK-NEXT: // (xor:i32 GPR32:i32:$Wm, -1:i32) => (ORN:i32 R0:i32, GPR32:i32:$Wm)
-// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::ORN));
-// CHECK-NEXT: MIB.add(I.getOperand(0)/*dst*/);
-// CHECK-NEXT: MIB.addReg(MyTarget::R0);
-// CHECK-NEXT: MIB.add(I.getOperand(1)/*Wm*/);
-// CHECK-NEXT: MIB.setMemRefs(I.memoperands_begin(), I.memoperands_end());
-// CHECK-NEXT: I.eraseFromParent();
-// CHECK-NEXT: MachineInstr &NewI = *MIB;
-// CHECK: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);
-// CHECK-NEXT: return true;
-// CHECK-NEXT: }
+// CHECK-LABEL: if ([&]() {
+// CHECK-NEXT: MachineInstr &MI0 = I;
+// CHECK-NEXT: if (MI0.getNumOperands() < 3)
+// CHECK-NEXT: return false;
+// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_XOR) &&
+// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) &&
+// CHECK-NEXT: ((/* Wm */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) &&
+// CHECK-NEXT: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: (isOperandImmEqual(MI0.getOperand(2), -1, MRI))))) {
+// CHECK-NEXT: // (xor:i32 GPR32:i32:$Wm, -1:i32) => (ORN:i32 R0:i32, GPR32:i32:$Wm)
+// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::ORN));
+// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/);
+// CHECK-NEXT: MIB.addReg(MyTarget::R0);
+// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*Wm*/);
+// CHECK-NEXT: MIB.setMemRefs(I.memoperands_begin(), I.memoperands_end());
+// CHECK-NEXT: I.eraseFromParent();
+// CHECK-NEXT: MachineInstr &NewI = *MIB;
+// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);
+// CHECK-NEXT: return true;
+// CHECK-NEXT: }
+// CHECK-NEXT: return false;
+// CHECK-NEXT: }()) { return true; }
def ORN : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>;
def : Pat<(not GPR32:$Wm), (ORN R0, GPR32:$Wm)>;
//===- Test a pattern with an MBB operand. --------------------------------===//
-// CHECK-LABEL: if ((I.getOpcode() == TargetOpcode::G_BR) &&
-// CHECK-NEXT: ((/* target */ (I.getOperand(0).isMBB())))) {
-
-// CHECK-NEXT: // (br (bb:Other):$target) => (BR (bb:Other):$target)
-// CHECK-NEXT: I.setDesc(TII.get(MyTarget::BR));
-// CHECK-NEXT: MachineInstr &NewI = I;
-// CHECK: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);
-// CHECK-NEXT: return true;
-// CHECK-NEXT: }
+// CHECK-LABEL: if ([&]() {
+// CHECK-NEXT: MachineInstr &MI0 = I;
+// CHECK-NEXT: if (MI0.getNumOperands() < 1)
+// CHECK-NEXT: return false;
+// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_BR) &&
+// CHECK-NEXT: ((/* target */ (MI0.getOperand(0).isMBB())))) {
+
+// CHECK-NEXT: // (br (bb:Other):$target) => (BR (bb:Other):$target)
+// CHECK-NEXT: I.setDesc(TII.get(MyTarget::BR));
+// CHECK-NEXT: MachineInstr &NewI = I;
+// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);
+// CHECK-NEXT: return true;
+// CHECK-NEXT: }
+// CHECK-NEXT: return false;
+// CHECK-NEXT: }()) { return true; }
def BR : I<(outs), (ins unknown:$target),
[(br bb:$target)]>;
/// 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.
///
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.
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);
: 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) {
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
return P->getKind() == OPM_MBB;
}
- void emitCxxPredicateExpr(raw_ostream &OS,
+ void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
StringRef OperandExpr) const override {
OS << OperandExpr << ".isMBB()";
}
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)";
}
/// 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; }
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 << ")";
}
/// 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.
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();
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");
}
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 << ")";
}
}
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
/// 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;
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";
}
};
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";
}
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(";
/// 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.
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";
}
};
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;
}
"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";
}
};
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!");
// %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 {
OM.addPredicate<LLTOperandMatcher>(*OpTyOrNone);
OM.addPredicate<RegisterBankOperandMatcher>(
Target.getRegisterClass(DstIOpRec));
- DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, "I", DstIOperand.Name);
+ DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, DstIOperand.Name);
++OpIdx;
}
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;
}
}
if (ChildRec->isSubClassOf("RegisterClass")) {
- DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, "I",
+ DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher,
DstChild->getName());
continue;
}
<< " 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;
}