Index: include/llvm/CodeGen/GlobalISel/InstructionSelector.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -19,9 +19,11 @@ #include "llvm/ADT/Optional.h" #include #include +#include namespace llvm { class MachineInstr; +class MachineInstrBuilder; class MachineFunction; class MachineOperand; class MachineRegisterInfo; @@ -76,6 +78,8 @@ virtual bool select(MachineInstr &I) const = 0; protected: + typedef std::function ComplexRendererFn; + InstructionSelector(); /// Mutate the newly-selected instruction \p I to constrain its (possibly Index: include/llvm/CodeGen/MachineOperand.h =================================================================== --- include/llvm/CodeGen/MachineOperand.h +++ include/llvm/CodeGen/MachineOperand.h @@ -65,7 +65,6 @@ MO_CFIIndex, ///< MCCFIInstruction index. MO_IntrinsicID, ///< Intrinsic ID for ISel MO_Predicate, ///< Generic predicate for ISel - MO_Placeholder, ///< Placeholder for GlobalISel ComplexPattern result. }; private: @@ -768,11 +767,6 @@ return Op; } - static MachineOperand CreatePlaceholder() { - MachineOperand Op(MachineOperand::MO_Placeholder); - return Op; - } - friend class MachineInstr; friend class MachineRegisterInfo; private: Index: include/llvm/Target/GlobalISel/Target.td =================================================================== --- include/llvm/Target/GlobalISel/Target.td +++ include/llvm/Target/GlobalISel/Target.td @@ -30,21 +30,13 @@ // Definitions that inherit from this may also inherit from // GIComplexPatternEquiv to enable the import of SelectionDAG patterns involving // those ComplexPatterns. -class GIComplexOperandMatcher { +class GIComplexOperandMatcher { // The expected type of the root of the match. // // TODO: We should probably support, any-type, any-scalar, and multiple types // in the future. LLT Type = type; - // The operands that result from a successful match - // Should be of the form '(ops ty1, ty2, ...)' where ty1/ty2 are definitions - // that inherit from Operand. - // - // FIXME: Which definition is used for ty1/ty2 doesn't actually matter at the - // moment. Only the number of operands is used. - dag Operands = operands; - // The function that determines whether the operand matches. It should be of // the form: // bool select(const MatchOperand &Root, MatchOperand &Result1) Index: lib/CodeGen/MIRPrinter.cpp =================================================================== --- lib/CodeGen/MIRPrinter.cpp +++ lib/CodeGen/MIRPrinter.cpp @@ -925,9 +925,6 @@ << CmpInst::getPredicateName(Pred) << ')'; break; } - case MachineOperand::MO_Placeholder: - OS << ""; - break; } } Index: lib/CodeGen/MachineInstr.cpp =================================================================== --- lib/CodeGen/MachineInstr.cpp +++ lib/CodeGen/MachineInstr.cpp @@ -287,8 +287,6 @@ return getIntrinsicID() == Other.getIntrinsicID(); case MachineOperand::MO_Predicate: return getPredicate() == Other.getPredicate(); - case MachineOperand::MO_Placeholder: - return true; } llvm_unreachable("Invalid machine operand type"); } @@ -337,8 +335,6 @@ return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getIntrinsicID()); case MachineOperand::MO_Predicate: return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getPredicate()); - case MachineOperand::MO_Placeholder: - return hash_combine(); } llvm_unreachable("Invalid machine operand type"); } @@ -515,9 +511,6 @@ << CmpInst::getPredicateName(Pred) << '>'; break; } - case MachineOperand::MO_Placeholder: - OS << ""; - break; } if (unsigned TF = getTargetFlags()) OS << "[TF=" << TF << ']'; Index: lib/Target/AArch64/AArch64InstrFormats.td =================================================================== --- lib/Target/AArch64/AArch64InstrFormats.td +++ lib/Target/AArch64/AArch64InstrFormats.td @@ -693,11 +693,11 @@ def addsub_shifted_imm64_neg : addsub_shifted_imm_neg; def gi_addsub_shifted_imm32 : - GIComplexOperandMatcher, + GIComplexOperandMatcher, GIComplexPatternEquiv; def gi_addsub_shifted_imm64 : - GIComplexOperandMatcher, + GIComplexOperandMatcher, GIComplexPatternEquiv; class neg_addsub_shifted_imm Index: lib/Target/AArch64/AArch64InstructionSelector.cpp =================================================================== --- lib/Target/AArch64/AArch64InstructionSelector.cpp +++ lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -66,8 +66,7 @@ bool selectCompareBranch(MachineInstr &I, MachineFunction &MF, MachineRegisterInfo &MRI) const; - bool selectArithImmed(MachineOperand &Root, MachineOperand &Result1, - MachineOperand &Result2) const; + ComplexRendererFn selectArithImmed(MachineOperand &Root) const; const AArch64TargetMachine &TM; const AArch64Subtarget &STI; @@ -1329,9 +1328,8 @@ /// SelectArithImmed - Select an immediate value that can be represented as /// a 12-bit value shifted left by either 0 or 12. If so, return true with /// Val set to the 12-bit value and Shift set to the shifter operand. -bool AArch64InstructionSelector::selectArithImmed( - MachineOperand &Root, MachineOperand &Result1, - MachineOperand &Result2) const { +InstructionSelector::ComplexRendererFn +AArch64InstructionSelector::selectArithImmed(MachineOperand &Root) const { MachineInstr &MI = *Root.getParent(); MachineBasicBlock &MBB = *MI.getParent(); MachineFunction &MF = *MBB.getParent(); @@ -1350,13 +1348,13 @@ else if (Root.isReg()) { MachineInstr *Def = MRI.getVRegDef(Root.getReg()); if (Def->getOpcode() != TargetOpcode::G_CONSTANT) - return false; + return nullptr; MachineOperand &Op1 = Def->getOperand(1); if (!Op1.isCImm() || Op1.getCImm()->getBitWidth() > 64) - return false; + return nullptr; Immed = Op1.getCImm()->getZExtValue(); } else - return false; + return nullptr; unsigned ShiftAmt; @@ -1366,14 +1364,10 @@ ShiftAmt = 12; Immed = Immed >> 12; } else - return false; + return nullptr; unsigned ShVal = AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt); - Result1.ChangeToImmediate(Immed); - Result1.clearParent(); - Result2.ChangeToImmediate(ShVal); - Result2.clearParent(); - return true; + return [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed).addImm(ShVal); }; } namespace llvm { Index: lib/Target/ARM/ARMExpandPseudoInsts.cpp =================================================================== --- lib/Target/ARM/ARMExpandPseudoInsts.cpp +++ lib/Target/ARM/ARMExpandPseudoInsts.cpp @@ -661,7 +661,6 @@ return false; case MachineOperand::MO_IntrinsicID: case MachineOperand::MO_Predicate: - case MachineOperand::MO_Placeholder: llvm_unreachable("should not exist post-isel"); } llvm_unreachable("unhandled machine operand type"); Index: test/TableGen/GlobalISelEmitter.td =================================================================== --- test/TableGen/GlobalISelEmitter.td +++ test/TableGen/GlobalISelEmitter.td @@ -22,7 +22,7 @@ let MIOperandInfo = (ops i32imm, i32imm); } def gi_complex : - GIComplexOperandMatcher, + GIComplexOperandMatcher, GIComplexPatternEquiv; def m1 : OperandWithDefaultOps ; @@ -72,17 +72,15 @@ // 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: (selectComplexPattern(MI0.getOperand(2), TempOp0, TempOp1)))) && +// CHECK-NEXT: ((Renderer0 = selectComplexPattern(MI0.getOperand(2)))))) && // CHECK-NEXT: ((/* src3 */ (MRI.getType(MI0.getOperand(3).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: (selectComplexPattern(MI0.getOperand(3), TempOp2, TempOp3))))) { +// CHECK-NEXT: ((Renderer1 = selectComplexPattern(MI0.getOperand(3))))))) { // CHECK-NEXT: // (select:i32 GPR32:i32:$src1, complex:i32:$src2, complex:i32:$src3) => (INSN2:i32 GPR32:i32:$src1, complex:i32:$src3, complex:i32:$src2) // CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::INSN2)); // CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); // CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/); -// CHECK-NEXT: MIB.add(TempOp2); -// CHECK-NEXT: MIB.add(TempOp3); -// CHECK-NEXT: MIB.add(TempOp0); -// CHECK-NEXT: MIB.add(TempOp1); +// CHECK-NEXT: Renderer1(MIB); +// CHECK-NEXT: Renderer0(MIB); // CHECK-NEXT: for (const auto *FromMI : {&MI0, }) // CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) // CHECK-NEXT: MIB.addMemOperand(MMO); @@ -263,13 +261,12 @@ // 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: (selectComplexPattern(MI0.getOperand(2), TempOp0, TempOp1))))) { +// CHECK-NEXT: ((Renderer0 = selectComplexPattern(MI0.getOperand(2))))))) { // CHECK-NEXT: // (sub:i32 GPR32:i32:$src1, complex:i32:$src2) => (INSN1:i32 GPR32:i32:$src1, complex:i32:$src2) // CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::INSN1)); // CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); // CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/); -// CHECK-NEXT: MIB.add(TempOp0); -// CHECK-NEXT: MIB.add(TempOp1); +// CHECK-NEXT: Renderer0(MIB); // CHECK-NEXT: for (const auto *FromMI : {&MI0, }) // CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) // CHECK-NEXT: MIB.addMemOperand(MMO); Index: utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- utils/TableGen/GlobalISelEmitter.cpp +++ utils/TableGen/GlobalISelEmitter.cpp @@ -91,52 +91,6 @@ }; class InstructionMatcher; -class OperandPlaceholder { -private: - enum PlaceholderKind { - OP_MatchReference, - OP_Temporary, - } Kind; - - struct MatchReferenceData { - InstructionMatcher *InsnMatcher; - StringRef InsnVarName; - StringRef SymbolicName; - }; - - struct TemporaryData { - unsigned OpIdx; - }; - - union { - struct MatchReferenceData MatchReference; - struct TemporaryData Temporary; - }; - - OperandPlaceholder(PlaceholderKind Kind) : Kind(Kind) {} - -public: - ~OperandPlaceholder() {} - - static OperandPlaceholder - CreateMatchReference(InstructionMatcher *InsnMatcher, - StringRef InsnVarName, StringRef SymbolicName) { - OperandPlaceholder Result(OP_MatchReference); - Result.MatchReference.InsnMatcher = InsnMatcher; - Result.MatchReference.InsnVarName = InsnVarName; - Result.MatchReference.SymbolicName = SymbolicName; - return Result; - } - - static OperandPlaceholder CreateTemporary(unsigned OpIdx) { - OperandPlaceholder Result(OP_Temporary); - Result.Temporary.OpIdx = OpIdx; - return Result; - } - - void emitCxxValueExpr(raw_ostream &OS) const; -}; - /// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for /// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...). static Optional MVTToLLT(MVT::SimpleValueType SVT) { @@ -256,7 +210,10 @@ /// Report the maximum number of temporary operands needed by the rule /// matcher. - unsigned countTemporaryOperands() const; + unsigned countRendererFns() const; + + // FIXME: Remove this as soon as possible + InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); } }; template class PredicateListMatcher { @@ -361,7 +318,7 @@ /// Report the maximum number of temporary operands needed by the predicate /// matcher. - virtual unsigned countTemporaryOperands() const { return 0; } + virtual unsigned countRendererFns() const { return 0; } }; /// Generates code to check that an operand is a particular LLT. @@ -391,10 +348,6 @@ const OperandMatcher &Operand; const Record &TheDef; - unsigned getNumOperands() const { - return TheDef.getValueAsDag("Operands")->getNumArgs(); - } - unsigned getAllocatedTemporariesBaseID() const; public: @@ -409,17 +362,13 @@ void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, StringRef OperandExpr) const override { - OS << TheDef.getValueAsString("MatcherFn") << "(" << OperandExpr; - for (unsigned I = 0; I < getNumOperands(); ++I) { - OS << ", "; - OperandPlaceholder::CreateTemporary(getAllocatedTemporariesBaseID() + I) - .emitCxxValueExpr(OS); - } - OS << ")"; + unsigned ID = getAllocatedTemporariesBaseID(); + OS << "(Renderer" << ID << " = " << TheDef.getValueAsString("MatcherFn") + << "(" << OperandExpr << "))"; } - unsigned countTemporaryOperands() const override { - return getNumOperands(); + unsigned countRendererFns() const override { + return 1; } }; @@ -488,7 +437,7 @@ /// The index of the first temporary variable allocated to this operand. The /// number of allocated temporaries can be found with - /// countTemporaryOperands(). + /// countRendererFns(). unsigned AllocatedTemporariesBaseID; public: @@ -569,12 +518,12 @@ /// Report the maximum number of temporary operands needed by the operand /// matcher. - unsigned countTemporaryOperands() const { + unsigned countRendererFns() const { return std::accumulate( predicates().begin(), predicates().end(), 0, [](unsigned A, const std::unique_ptr &Predicate) { - return A + Predicate->countTemporaryOperands(); + return A + Predicate->countRendererFns(); }); } @@ -623,7 +572,7 @@ /// Report the maximum number of temporary operands needed by the predicate /// matcher. - virtual unsigned countTemporaryOperands() const { return 0; } + virtual unsigned countRendererFns() const { return 0; } }; /// Generates code to check the opcode of an instruction. @@ -780,17 +729,17 @@ /// Report the maximum number of temporary operands needed by the instruction /// matcher. - unsigned countTemporaryOperands() const { + unsigned countRendererFns() const { return std::accumulate(predicates().begin(), predicates().end(), 0, [](unsigned A, const std::unique_ptr &Predicate) { - return A + Predicate->countTemporaryOperands(); + return A + Predicate->countRendererFns(); }) + std::accumulate( Operands.begin(), Operands.end(), 0, [](unsigned A, const std::unique_ptr &Operand) { - return A + Operand->countTemporaryOperands(); + return A + Operand->countRendererFns(); }); } }; @@ -845,18 +794,6 @@ }; //===- Actions ------------------------------------------------------------===// -void OperandPlaceholder::emitCxxValueExpr(raw_ostream &OS) const { - switch (Kind) { - case OP_MatchReference: - OS << MatchReference.InsnMatcher->getOperand(MatchReference.SymbolicName) - .getOperandExpr(MatchReference.InsnVarName); - break; - case OP_Temporary: - OS << "TempOp" << Temporary.OpIdx; - break; - } -} - class OperandRenderer { public: enum RendererKind { OR_Copy, OR_Imm, OR_Register, OR_ComplexPattern }; @@ -942,31 +879,33 @@ } }; +/// Adds operands by calling a renderer function supplied by the ComplexPattern +/// matcher function. class RenderComplexPatternOperand : public OperandRenderer { private: const Record &TheDef; - std::vector Sources; + /// The name of the operand. + const StringRef SymbolicName; + /// The renderer number. This must be unique within a rule since it's used to + /// identify a temporary variable to hold the renderer function. + unsigned RendererID; unsigned getNumOperands() const { return TheDef.getValueAsDag("Operands")->getNumArgs(); } public: - RenderComplexPatternOperand(const Record &TheDef, - const ArrayRef Sources) - : OperandRenderer(OR_ComplexPattern), TheDef(TheDef), Sources(Sources) {} + RenderComplexPatternOperand(const Record &TheDef, StringRef SymbolicName, + unsigned RendererID) + : OperandRenderer(OR_ComplexPattern), TheDef(TheDef), + SymbolicName(SymbolicName), RendererID(RendererID) {} static bool classof(const OperandRenderer *R) { return R->getKind() == OR_ComplexPattern; } 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("; - Source.emitCxxValueExpr(OS); - OS << ");\n"; - } + OS << "Renderer" << RendererID << "(MIB);\n"; } }; @@ -1248,11 +1187,11 @@ return false; } -unsigned RuleMatcher::countTemporaryOperands() const { +unsigned RuleMatcher::countRendererFns() const { return std::accumulate( Matchers.begin(), Matchers.end(), 0, [](unsigned A, const std::unique_ptr &Matcher) { - return A + Matcher->countTemporaryOperands(); + return A + Matcher->countRendererFns(); }); } @@ -1451,9 +1390,9 @@ return failedImport("SelectionDAG ComplexPattern (" + ChildRec->getName() + ") not mapped to GlobalISel"); - const auto &Predicate = OM.addPredicate( - OM, *ComplexPattern->second); - TempOpIdx += Predicate.countTemporaryOperands(); + OM.addPredicate(OM, + *ComplexPattern->second); + TempOpIdx++; return Error::success(); } @@ -1518,13 +1457,10 @@ return failedImport( "SelectionDAG ComplexPattern not mapped to GlobalISel"); - SmallVector RenderedOperands; const OperandMatcher &OM = InsnMatcher.getOperand(DstChild->getName()); - for (unsigned I = 0; I < OM.countTemporaryOperands(); ++I) - RenderedOperands.push_back(OperandPlaceholder::CreateTemporary( - OM.getAllocatedTemporariesBaseID() + I)); DstMIBuilder.addRenderer( - *ComplexPattern->second, RenderedOperands); + *ComplexPattern->second, DstChild->getName(), + OM.getAllocatedTemporariesBaseID()); return Error::success(); } @@ -1744,7 +1680,7 @@ unsigned MaxTemporaries = 0; for (const auto &Rule : Rules) - MaxTemporaries = std::max(MaxTemporaries, Rule.countTemporaryOperands()); + MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns()); OS << "#ifdef GET_GLOBALISEL_PREDICATE_BITSET\n" << "const unsigned MAX_SUBTARGET_PREDICATES = " << SubtargetFeatures.size() @@ -1755,12 +1691,12 @@ OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n"; for (unsigned I = 0; I < MaxTemporaries; ++I) - OS << " mutable MachineOperand TempOp" << I << ";\n"; + 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 << ", TempOp" << I << "(MachineOperand::CreatePlaceholder())\n"; + OS << ", Renderer" << I << "(nullptr)\n"; OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n"; OS << "#ifdef GET_GLOBALISEL_IMPL\n";