Index: llvm/trunk/test/TableGen/GlobalISelEmitter.td =================================================================== --- llvm/trunk/test/TableGen/GlobalISelEmitter.td +++ llvm/trunk/test/TableGen/GlobalISelEmitter.td @@ -26,43 +26,55 @@ //===- 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))]>; @@ -72,40 +84,51 @@ // 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)]>; Index: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp +++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp @@ -164,14 +164,28 @@ /// have succeeded. std::vector> Actions; + /// A map of instruction matchers to the local variables created by + /// emitCxxCaptureStmts(). + std::map InsnVariableNames; + + /// ID for the next instruction variable defined with defineInsnVar() + unsigned NextInsnVarID; + public: - RuleMatcher() {} + RuleMatcher() + : Matchers(), Actions(), InsnVariableNames(), NextInsnVarID(0) {} InstructionMatcher &addInstructionMatcher(); template 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 @@ 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 @@ 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 @@ : 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 @@ 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 @@ 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 @@ 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 @@ /// operand. class OperandMatcher : public PredicateListMatcher { 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 @@ 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 @@ /// 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 @@ 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 @@ 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 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 { + OptionalOM = getOptionalOperand(SymbolicName); + if (OM.hasValue()) + return *OM.getValue(); llvm_unreachable("Failed to lookup operand"); } @@ -566,13 +592,24 @@ 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 @@ 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 @@ /// 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 @@ 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 @@ 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 @@ 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 @@ /// 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 @@ 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 @@ return *static_cast(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 @@ "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 @@ return *static_cast(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 @@ // %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 @@ OM.addPredicate(*OpTyOrNone); OM.addPredicate( Target.getRegisterClass(DstIOpRec)); - DstMIBuilder.addRenderer(InsnMatcher, "I", DstIOperand.Name); + DstMIBuilder.addRenderer(InsnMatcher, DstIOperand.Name); ++OpIdx; } @@ -1086,7 +1151,7 @@ if (DstChild->getOperator()->isSubClassOf("SDNode")) { auto &ChildSDNI = CGP.getSDNodeInfo(DstChild->getOperator()); if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") { - DstMIBuilder.addRenderer(InsnMatcher, "I", + DstMIBuilder.addRenderer(InsnMatcher, DstChild->getName()); continue; } @@ -1115,7 +1180,7 @@ } if (ChildRec->isSubClassOf("RegisterClass")) { - DstMIBuilder.addRenderer(InsnMatcher, "I", + DstMIBuilder.addRenderer(InsnMatcher, DstChild->getName()); continue; } @@ -1210,7 +1275,7 @@ << " 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; }