Index: include/llvm/CodeGen/GlobalISel/InstructionSelector.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -116,6 +116,69 @@ GIM_Accept, }; +enum { + /// Mutate an instruction + /// - NewInsnID - Instruction ID to define + /// - OldInsnID - Instruction ID to mutate + /// - NewOpcode - The new opcode to use + GIR_MutateOpcode, + /// Build a new instruction + /// - InsnID - Instruction ID to define + /// - Opcode - The new opcode to use + GIR_BuildMI, + + /// Copy an operand to the specified instruction + /// - NewInsnID - Instruction ID to modify + /// - OldInsnID - Instruction ID to copy from + /// - OpIdx - The operand to copy + GIR_Copy, + /// Copy an operand to the specified instruction + /// - NewInsnID - Instruction ID to modify + /// - OldInsnID - Instruction ID to copy from + /// - OpIdx - The operand to copy + /// - SubRegIdx - The subregister to copy + GIR_CopySubReg, + /// Add an implicit register def to the specified instruction + /// - InsnID - Instruction ID to modify + /// - RegNum - The register to add + GIR_AddImplicitDef, + /// Add an implicit register use to the specified instruction + /// - InsnID - Instruction ID to modify + /// - RegNum - The register to add + GIR_AddImplicitUse, + /// Add an register to the specified instruction + /// - InsnID - Instruction ID to modify + /// - RegNum - The register to add + GIR_AddRegister, + /// Add an immediate to the specified instruction + /// - InsnID - Instruction ID to modify + /// - Imm - The immediate to add + GIR_AddImm, + /// Render complex operands to the specified instruction + /// - InsnID - Instruction ID to modify + /// - RendererID - The renderer to call + GIR_ComplexRenderer, + + /// Constrain an instruction operand to a register class. + /// - InsnID - Instruction ID to modify + /// - OpIdx - Operand index + /// - RCEnum - Register class enumeration value + GIR_ConstrainOperandRC, + /// Constrain an instructions operands according to the instruction + /// description. + /// - InsnID - Instruction ID to modify + GIR_ConstrainSelectedInstOperands, + /// Merge all memory operands into instruction. + /// - InsnID - Instruction ID to modify + GIR_MergeMemOperands, + /// Erase from parent. + /// - InsnID - Instruction ID to erase + GIR_EraseFromParent, + + /// A successful emission + GIR_Done, +}; + /// Provides the logic to select generic machine instructions. class InstructionSelector { public: @@ -137,6 +200,7 @@ protected: using ComplexRendererFn = std::function; using RecordedMIVector = SmallVector; + using NewMIVector = SmallVector; struct MatcherState { std::vector Renderers; @@ -166,6 +230,10 @@ const int64_t *MatchTable, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures) const; + void executeEmitTable(NewMIVector &OutMIs, MatcherState &State, + const int64_t *EmitTable, const TargetInstrInfo &TII, + const TargetRegisterInfo &TRI, + const RegisterBankInfo &RBI) const; /// Constrain a register operand of an instruction \p I to a specified /// register class. This could involve inserting COPYs before (for uses) or Index: include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h +++ include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h @@ -161,13 +161,14 @@ } case GIM_Accept: - DEBUG(dbgs() << "GIM_Accept"); + DEBUG(dbgs() << "GIM_Accept\n"); return true; default: llvm_unreachable("Unexpected command"); } } } + } // end namespace llvm #endif // LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTORIMPL_H Index: lib/CodeGen/GlobalISel/InstructionSelector.cpp =================================================================== --- lib/CodeGen/GlobalISel/InstructionSelector.cpp +++ lib/CodeGen/GlobalISel/InstructionSelector.cpp @@ -16,7 +16,11 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/MC/MCInstrDesc.h" +#include "llvm/IR/Constants.h" +#include "llvm/Target/TargetInstrInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -31,6 +35,155 @@ InstructionSelector::InstructionSelector() = default; +void InstructionSelector::executeEmitTable(NewMIVector &OutMIs, + MatcherState &State, + const int64_t *EmitTable, + const TargetInstrInfo &TII, + const TargetRegisterInfo &TRI, + const RegisterBankInfo &RBI) const { + const int64_t *Command = EmitTable; + while (true) { + switch (*Command++) { + case GIR_MutateOpcode: { + int64_t OldInsnID = *Command++; + int64_t NewInsnID = *Command++; + int64_t NewOpcode = *Command++; + assert((size_t)NewInsnID == OutMIs.size() && + "Expected to store MIs in order"); + OutMIs.push_back( + MachineInstrBuilder(*State.MIs[OldInsnID]->getParent()->getParent(), + State.MIs[OldInsnID])); + OutMIs[NewInsnID]->setDesc(TII.get(NewOpcode)); + DEBUG(dbgs() << "GIR_MutateOpcode(OutMIs[" << NewInsnID << "], MIs[" + << OldInsnID << "], " << NewOpcode << ")\n"); + break; + } + case GIR_BuildMI: { + int64_t InsnID = *Command++; + int64_t Opcode = *Command++; + assert((size_t)InsnID == OutMIs.size() && + "Expected to store MIs in order"); + OutMIs.push_back(BuildMI(*State.MIs[0]->getParent(), State.MIs[0], + State.MIs[0]->getDebugLoc(), TII.get(Opcode))); + DEBUG(dbgs() << "GIR_BuildMI(OutMIs[" << InsnID << "], " << Opcode + << ")\n"); + break; + } + + case GIR_Copy: { + int64_t NewInsnID = *Command++; + int64_t OldInsnID = *Command++; + int64_t OpIdx = *Command++; + assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction"); + OutMIs[NewInsnID].add(State.MIs[OldInsnID]->getOperand(OpIdx)); + DEBUG(dbgs() << "GIR_Copy(OutMIs[" << NewInsnID << "], MIs[" << OldInsnID + << "], " << OpIdx << ")\n"); + break; + } + case GIR_CopySubReg: { + int64_t NewInsnID = *Command++; + int64_t OldInsnID = *Command++; + int64_t OpIdx = *Command++; + int64_t SubRegIdx = *Command++; + assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction"); + OutMIs[NewInsnID].addReg(State.MIs[OldInsnID]->getOperand(OpIdx).getReg(), + 0, SubRegIdx); + DEBUG(dbgs() << "GIR_CopySubReg(OutMIs[" << NewInsnID << "], MIs[" + << OldInsnID << "], " << OpIdx << ", " << SubRegIdx + << ")\n"); + break; + } + case GIR_AddImplicitDef: { + int64_t InsnID = *Command++; + int64_t RegNum = *Command++; + assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); + OutMIs[InsnID].addDef(RegNum, RegState::Implicit); + DEBUG(dbgs() << "GIR_AddImplicitDef(OutMIs[" << InsnID << "], " << RegNum + << ")\n"); + break; + } + case GIR_AddImplicitUse: { + int64_t InsnID = *Command++; + int64_t RegNum = *Command++; + assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); + OutMIs[InsnID].addUse(RegNum, RegState::Implicit); + DEBUG(dbgs() << "GIR_AddImplicitUse(OutMIs[" << InsnID << "], " << RegNum + << ")\n"); + break; + } + case GIR_AddRegister: { + int64_t InsnID = *Command++; + int64_t RegNum = *Command++; + assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); + OutMIs[InsnID].addReg(RegNum); + DEBUG(dbgs() << "GIR_AddRegister(OutMIs[" << InsnID << "], " << RegNum + << ")\n"); + break; + } + case GIR_AddImm: { + int64_t InsnID = *Command++; + int64_t Imm = *Command++; + assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); + OutMIs[InsnID].addImm(Imm); + DEBUG(dbgs() << "GIR_AddImm(OutMIs[" << InsnID << "], " << Imm << ")\n"); + break; + } + case GIR_ComplexRenderer: { + int64_t InsnID = *Command++; + int64_t RendererID = *Command++; + assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); + State.Renderers[RendererID](OutMIs[InsnID]); + DEBUG(dbgs() << "GIR_ComplexRenderer(OutMIs[" << InsnID << "], " + << RendererID << ")\n"); + break; + } + + case GIR_ConstrainOperandRC: { + int64_t InsnID = *Command++; + int64_t OpIdx = *Command++; + int64_t RCEnum = *Command++; + assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); + constrainOperandRegToRegClass(*OutMIs[InsnID].getInstr(), OpIdx, + *TRI.getRegClass(RCEnum), TII, TRI, RBI); + DEBUG(dbgs() << "GIR_ConstrainOperandRC(OutMIs[" << InsnID << "], " + << OpIdx << ", " << RCEnum << ")\n"); + break; + } + case GIR_ConstrainSelectedInstOperands: { + int64_t InsnID = *Command++; + assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); + constrainSelectedInstRegOperands(*OutMIs[InsnID].getInstr(), TII, TRI, + RBI); + DEBUG(dbgs() << "GIR_ConstrainSelectedInstOperands(OutMIs[" << InsnID + << "])\n"); + break; + } + case GIR_MergeMemOperands: { + int64_t InsnID = *Command++; + assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); + for (const auto *FromMI : State.MIs) + for (const auto &MMO : FromMI->memoperands()) + OutMIs[InsnID].addMemOperand(MMO); + DEBUG(dbgs() << "GIR_MergeMemOperands(OutMIs[" << InsnID << "])\n"); + break; + } + case GIR_EraseFromParent: { + int64_t InsnID = *Command++; + assert(State.MIs[InsnID] && "Attempted to erase an undefined instruction"); + State.MIs[InsnID]->eraseFromParent(); + DEBUG(dbgs() << "GIR_EraseFromParent(MIs[" << InsnID << "])\n"); + break; + } + + case GIR_Done: + DEBUG(dbgs() << "GIR_Done"); + return; + default: + llvm_unreachable("Unexpected command"); + } + } +} + bool InstructionSelector::constrainOperandRegToRegClass( MachineInstr &I, unsigned OpIdx, const TargetRegisterClass &RC, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, Index: test/TableGen/GlobalISelEmitter.td =================================================================== --- test/TableGen/GlobalISelEmitter.td +++ test/TableGen/GlobalISelEmitter.td @@ -107,19 +107,23 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable0\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable0, MRI, TRI, RBI, AvailableFeatures)) { -// 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(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(1)/*src1*/); -// CHECK-NEXT: Renderers[1](MIB); -// CHECK-NEXT: Renderers[0](MIB); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable0[] = { +// 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: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN2, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1 +// CHECK-NEXT: GIR_ComplexRenderer, /*InsnID*/0, /*RendererID*/1, +// CHECK-NEXT: GIR_ComplexRenderer, /*InsnID*/0, /*RendererID*/0, +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable0\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable0, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -146,11 +150,17 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable1\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable1, MRI, TRI, RBI, AvailableFeatures)) { -// 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: const static int64_t EmitTable1[] = { +// CHECK-NEXT: // (add:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (ADD:i32 GPR32:i32:$src1, GPR32:i32:$src2) +// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/ 0, /*Opcode*/MyTarget::ADD, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable1\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable1, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -186,21 +196,25 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable2\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable2, MRI, TRI, RBI, AvailableFeatures)) { // CHECK-NEXT: if (!isObviouslySafeToFold(*State.MIs[1])) // CHECK-NEXT: return false; -// CHECK-NEXT: // (mul:i32 (add:i32 GPR32:i32:$src1, GPR32:i32:$src2), GPR32:i32:$src3) => (MULADD:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MULADD)); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.add(State.MIs[1]->getOperand(1)/*src1*/); -// CHECK-NEXT: MIB.add(State.MIs[1]->getOperand(2)/*src2*/); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(2)/*src3*/); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], State.MIs[1], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable2[] = { +// CHECK-NEXT: // (mul:i32 (add:i32 GPR32:i32:$src1, GPR32:i32:$src2), GPR32:i32:$src3) => (MULADD:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MULADD, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1 +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/2, // src2 +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // src3 +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable2\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable2, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -232,23 +246,27 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable3\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable3, MRI, TRI, RBI, AvailableFeatures)) { -// CHECK-NEXT: if (!isObviouslySafeToFold(*State.MIs[1])) -// CHECK-NEXT: return false; -// CHECK-NEXT: // (mul:i32 GPR32:i32:$src3, (add:i32 GPR32:i32:$src1, GPR32:i32:$src2)) => (MULADD:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MULADD)); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.add(State.MIs[1]->getOperand(1)/*src1*/); -// CHECK-NEXT: MIB.add(State.MIs[1]->getOperand(2)/*src2*/); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(1)/*src3*/); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], State.MIs[1], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } +// CHECK-NEXT: if (!isObviouslySafeToFold(*State.MIs[1])) +// CHECK-NEXT: return false; +// CHECK-NEXT: const static int64_t EmitTable3[] = { +// CHECK-NEXT: // (mul:i32 GPR32:i32:$src3, (add:i32 GPR32:i32:$src1, GPR32:i32:$src2)) => (MULADD:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MULADD, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1 +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/2, // src2 +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src3 +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable3\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable3, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } def MULADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3), [(set GPR32:$dst, @@ -274,18 +292,22 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable4\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable4, MRI, TRI, RBI, AvailableFeatures)) { -// 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(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(2)/*src2*/); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(1)/*src1*/); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable4[] = { +// CHECK-NEXT: // (mul:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (MUL:i32 GPR32:i32:$src2, GPR32:i32:$src1) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MUL, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // src2 +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1 +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable4\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable4, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -332,24 +354,28 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable5\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable5, MRI, TRI, RBI, AvailableFeatures)) { // CHECK-NEXT: if (!isObviouslySafeToFold(*State.MIs[1])) // CHECK-NEXT: return false; // CHECK-NEXT: if (!isObviouslySafeToFold(*State.MIs[2])) // CHECK-NEXT: return false; -// CHECK-NEXT: // (sub:i32 (sub:i32 GPR32:i32:$src1, GPR32:i32:$src2), (sub:i32 GPR32:i32:$src3, GPR32:i32:$src4)) => (INSNBOB:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3, GPR32:i32:$src4) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::INSNBOB)); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.add(State.MIs[1]->getOperand(1)/*src1*/); -// CHECK-NEXT: MIB.add(State.MIs[1]->getOperand(2)/*src2*/); -// CHECK-NEXT: MIB.add(State.MIs[2]->getOperand(1)/*src3*/); -// CHECK-NEXT: MIB.add(State.MIs[2]->getOperand(2)/*src4*/); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], State.MIs[1], State.MIs[2], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable5[] = { +// CHECK-NEXT: // (sub:i32 (sub:i32 GPR32:i32:$src1, GPR32:i32:$src2), (sub:i32 GPR32:i32:$src3, GPR32:i32:$src4)) => (INSNBOB:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3, GPR32:i32:$src4) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSNBOB, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1 +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/2, // src2 +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/2, /*OpIdx*/1, // src3 +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/2, /*OpIdx*/2, // src4 +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable5\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable5, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -377,18 +403,22 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable6\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable6, MRI, TRI, RBI, AvailableFeatures)) { -// 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(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(1)/*src1*/); -// CHECK-NEXT: Renderers[0](MIB); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable6[] = { +// CHECK-NEXT: // (sub:i32 GPR32:i32:$src1, complex:i32:$src2) => (INSN1:i32 GPR32:i32:$src1, complex:i32:$src2) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN1, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1 +// CHECK-NEXT: GIR_ComplexRenderer, /*InsnID*/0, /*RendererID*/0, +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable6\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable6, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -414,18 +444,22 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable7\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable7, MRI, TRI, RBI, AvailableFeatures)) { -// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -2:i32) => (XORI:i32 GPR32:i32:$src1) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XORI)); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.addImm(-1); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(1)/*src1*/); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable7[] = { +// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -2:i32) => (XORI:i32 GPR32:i32:$src1) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORI, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1 +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable7\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable7, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -452,18 +486,22 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable8\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable8, MRI, TRI, RBI, AvailableFeatures)) { -// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -3:i32) => (XOR:i32 GPR32:i32:$src1) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XOR)); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.addReg(MyTarget::R0); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(1)/*src1*/); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable8[] = { +// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -3:i32) => (XOR:i32 GPR32:i32:$src1) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XOR, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1 +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable8\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable8, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -490,19 +528,23 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable9\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable9, MRI, TRI, RBI, AvailableFeatures)) { -// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -4:i32) => (XORlike:i32 GPR32:i32:$src1) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XORlike)); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.addImm(-1); -// CHECK-NEXT: MIB.addReg(MyTarget::R0); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(1)/*src1*/); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable9[] = { +// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -4:i32) => (XORlike:i32 GPR32:i32:$src1) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORlike, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1, +// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1 +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable9\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable9, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -529,20 +571,24 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable10\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable10, MRI, TRI, RBI, AvailableFeatures)) { -// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -5:i32) => (XORManyDefaults:i32 GPR32:i32:$src1) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XORManyDefaults)); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.addImm(-1); -// CHECK-NEXT: MIB.addReg(MyTarget::R0); -// CHECK-NEXT: MIB.addReg(MyTarget::R0); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(1)/*src1*/); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable10[] = { +// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -5:i32) => (XORManyDefaults:i32 GPR32:i32:$src1) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORManyDefaults, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1, +// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0, +// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1 +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable10\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable10, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -571,18 +617,22 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable11\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable11, MRI, TRI, RBI, AvailableFeatures)) { -// 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(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.addReg(MyTarget::R0); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(1)/*Wm*/); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable11[] = { +// CHECK-NEXT: // (xor:i32 GPR32:i32:$Wm, -1:i32) => (ORN:i32 R0:i32, GPR32:i32:$Wm) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::ORN, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // Wm +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable11\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable11, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -605,11 +655,17 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable12\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable12, MRI, TRI, RBI, AvailableFeatures)) { -// CHECK-NEXT: // (bitconvert:i32 FPR32:f32:$src1) => (COPY_TO_REGCLASS:i32 FPR32:f32:$src1, GPR32:i32) -// CHECK-NEXT: I.setDesc(TII.get(TargetOpcode::COPY)); -// CHECK-NEXT: MachineInstr &NewI = I; -// CHECK-NEXT: constrainOperandRegToRegClass(NewI, 0, MyTarget::GPR32RegClass, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable12[] = { +// CHECK-NEXT: // (bitconvert:i32 FPR32:f32:$src1) => (COPY_TO_REGCLASS:i32 FPR32:f32:$src1, GPR32:i32) +// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/ 0, /*Opcode*/TargetOpcode::COPY, +// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC GPR32*/ 1, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable12\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable12, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -630,16 +686,20 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable13\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable13, MRI, TRI, RBI, AvailableFeatures)) { -// CHECK-NEXT: // 1:i32 => (MOV1:i32) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MOV1)); -// CHECK-NEXT: MIB.add(State.MIs[0]->getOperand(0)/*dst*/); -// CHECK-NEXT: for (const auto *FromMI : {State.MIs[0], }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: const static int64_t EmitTable13[] = { +// CHECK-NEXT: // 1:i32 => (MOV1:i32) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOV1, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable13\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable13, TII, TRI, RBI); // CHECK-NEXT: return true; // CHECK-NEXT: } @@ -656,12 +716,18 @@ // CHECK-NEXT: }; // CHECK-NEXT: MIs.clear(); // CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable14\n"); // CHECK-NEXT: if (executeMatchTable(*this, State, MatcherInfo, MatchTable14, MRI, TRI, RBI, AvailableFeatures)) { -// 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: const static int64_t EmitTable14[] = { +// CHECK-NEXT: // (br (bb:Other):$target) => (BR (bb:Other):$target) +// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/ 0, /*Opcode*/MyTarget::BR, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: }; +// CHECK-NEXT: NewMIVector OutMIs; +// CHECK-NEXT: DEBUG(dbgs() << "Processing EmitTable14\n"); +// CHECK-NEXT: executeEmitTable(OutMIs, State, EmitTable14, TII, TRI, RBI); +// CHECK-NEXT: return true; // CHECK-NEXT: } def BR : I<(outs), (ins unknown:$target), Index: utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- utils/TableGen/GlobalISelEmitter.cpp +++ utils/TableGen/GlobalISelEmitter.cpp @@ -261,7 +261,6 @@ unsigned InsnVarID, unsigned OpIdx); unsigned getInsnVarID(const InstructionMatcher &InsnMatcher) const; - void emitCxxCapturedInsnList(raw_ostream &OS); void emitCxxCaptureStmts(raw_ostream &OS); void emit(raw_ostream &OS); @@ -904,6 +903,7 @@ /// instruction to the one being built. class CopyRenderer : public OperandRenderer { protected: + unsigned NewInsnID; /// The matcher for the instruction that this operand is copied from. /// 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. @@ -912,9 +912,10 @@ const StringRef SymbolicName; public: - CopyRenderer(const InstructionMatcher &Matched, StringRef SymbolicName) - : OperandRenderer(OR_Copy), Matched(Matched), SymbolicName(SymbolicName) { - } + CopyRenderer(unsigned NewInsnID, const InstructionMatcher &Matched, + StringRef SymbolicName) + : OperandRenderer(OR_Copy), NewInsnID(NewInsnID), Matched(Matched), + SymbolicName(SymbolicName) {} static bool classof(const OperandRenderer *R) { return R->getKind() == OR_Copy; @@ -924,10 +925,10 @@ void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { const OperandMatcher &Operand = Matched.getOperand(SymbolicName); - unsigned InsnVarID = - Rule.getInsnVarID(Operand.getInstructionMatcher()); - std::string OperandExpr = Operand.getOperandExpr(InsnVarID); - OS << " MIB.add(" << OperandExpr << "/*" << SymbolicName << "*/);\n"; + unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher()); + OS << " GIR_Copy, /*NewInsnID*/" << NewInsnID << ", /*OldInsnID*/" + << OldInsnVarID << ", /*OpIdx*/" << Operand.getOperandIndex() << ", // " + << SymbolicName << "\n"; } }; @@ -936,6 +937,7 @@ /// subregister should be copied. class CopySubRegRenderer : public OperandRenderer { protected: + unsigned NewInsnID; /// The matcher for the instruction that this operand is copied from. /// 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. @@ -946,9 +948,9 @@ const CodeGenSubRegIndex *SubReg; public: - CopySubRegRenderer(const InstructionMatcher &Matched, StringRef SymbolicName, - const CodeGenSubRegIndex *SubReg) - : OperandRenderer(OR_CopySubReg), Matched(Matched), + CopySubRegRenderer(unsigned NewInsnID, const InstructionMatcher &Matched, + StringRef SymbolicName, const CodeGenSubRegIndex *SubReg) + : OperandRenderer(OR_CopySubReg), NewInsnID(NewInsnID), Matched(Matched), SymbolicName(SymbolicName), SubReg(SubReg) {} static bool classof(const OperandRenderer *R) { @@ -959,10 +961,11 @@ void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { const OperandMatcher &Operand = Matched.getOperand(SymbolicName); - unsigned InsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher()); - std::string OperandExpr = Operand.getOperandExpr(InsnVarID); - OS << " MIB.addReg(" << OperandExpr << ".getReg() /*" << SymbolicName - << "*/, 0, " << SubReg->EnumValue << ");\n"; + unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher()); + OS << " GIR_CopySubReg, /*NewInsnID*/" << NewInsnID + << ", /*OldInsnID*/" << OldInsnVarID << ", /*OpIdx*/" + << Operand.getOperandIndex() << ", /*SubRegIdx*/" << SubReg->EnumValue + << ", // " << SymbolicName << "\n"; } }; @@ -970,39 +973,44 @@ /// This is typically useful for WZR/XZR on AArch64. class AddRegisterRenderer : public OperandRenderer { protected: + unsigned InsnID; const Record *RegisterDef; public: - AddRegisterRenderer(const Record *RegisterDef) - : OperandRenderer(OR_Register), RegisterDef(RegisterDef) {} + AddRegisterRenderer(unsigned InsnID, const Record *RegisterDef) + : OperandRenderer(OR_Register), InsnID(InsnID), RegisterDef(RegisterDef) { + } static bool classof(const OperandRenderer *R) { return R->getKind() == OR_Register; } void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { - OS << " MIB.addReg(" << (RegisterDef->getValue("Namespace") - ? RegisterDef->getValueAsString("Namespace") - : "") - << "::" << RegisterDef->getName() << ");\n"; + OS << " GIR_AddRegister, /*InsnID*/" << InsnID << ", " + << (RegisterDef->getValue("Namespace") + ? RegisterDef->getValueAsString("Namespace") + : "") + << "::" << RegisterDef->getName() << ",\n"; } }; /// Adds a specific immediate to the instruction being built. class ImmRenderer : public OperandRenderer { protected: + unsigned InsnID; int64_t Imm; public: - ImmRenderer(int64_t Imm) - : OperandRenderer(OR_Imm), Imm(Imm) {} + ImmRenderer(unsigned InsnID, int64_t Imm) + : OperandRenderer(OR_Imm), InsnID(InsnID), Imm(Imm) {} static bool classof(const OperandRenderer *R) { return R->getKind() == OR_Imm; } void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { - OS << " MIB.addImm(" << Imm << ");\n"; + OS << " GIR_AddImm, /*InsnID*/" << InsnID << ", /*Imm*/" << Imm + << ",\n"; } }; @@ -1010,6 +1018,7 @@ /// matcher function. class RenderComplexPatternOperand : public OperandRenderer { private: + unsigned InsnID; const Record &TheDef; /// The name of the operand. const StringRef SymbolicName; @@ -1022,9 +1031,9 @@ } public: - RenderComplexPatternOperand(const Record &TheDef, StringRef SymbolicName, - unsigned RendererID) - : OperandRenderer(OR_ComplexPattern), TheDef(TheDef), + RenderComplexPatternOperand(unsigned InsnID, const Record &TheDef, + StringRef SymbolicName, unsigned RendererID) + : OperandRenderer(OR_ComplexPattern), InsnID(InsnID), TheDef(TheDef), SymbolicName(SymbolicName), RendererID(RendererID) {} static bool classof(const OperandRenderer *R) { @@ -1032,7 +1041,8 @@ } void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { - OS << " State.Renderers[" << RendererID << "](MIB);\n"; + OS << " GIR_ComplexRenderer, /*InsnID*/" << InsnID + << ", /*RendererID*/" << RendererID << ",\n"; } }; @@ -1047,11 +1057,11 @@ /// Emit the C++ statements to implement the action. /// - /// \param RecycleVarName If given, it's an instruction to recycle. The - /// requirements on the instruction vary from action to - /// action. + /// \param RecycleInsnID 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; + unsigned RecycleInsnID) const = 0; }; /// Generates a comment describing the matched rule being acted upon. @@ -1063,8 +1073,9 @@ DebugCommentAction(const PatternToMatch &P) : P(P) {} void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef RecycleVarName) const override { - OS << " // " << *P.getSrcPattern() << " => " << *P.getDstPattern() << "\n"; + unsigned RecycleInsnID) const override { + OS << " // " << *P.getSrcPattern() << " => " << *P.getDstPattern() + << "\n"; } }; @@ -1072,7 +1083,7 @@ /// into the desired instruction when this is possible. class BuildMIAction : public MatchAction { private: - std::string Name; + unsigned InsnID; const CodeGenInstruction *I; const InstructionMatcher &Matched; std::vector> OperandRenderers; @@ -1096,9 +1107,9 @@ } public: - BuildMIAction(const StringRef Name, const CodeGenInstruction *I, + BuildMIAction(unsigned InsnID, const CodeGenInstruction *I, const InstructionMatcher &Matched) - : Name(Name), I(I), Matched(Matched) {} + : InsnID(InsnID), I(I), Matched(Matched) {} template Kind &addRenderer(Args&&... args) { @@ -1108,84 +1119,74 @@ } void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef RecycleVarName) const override { + unsigned RecycleInsnID) const override { if (canMutate()) { - OS << " " << RecycleVarName << ".setDesc(TII.get(" << I->Namespace - << "::" << I->TheDef->getName() << "));\n"; + OS << " GIR_MutateOpcode, /*InsnID*/" << InsnID + << ", /*RecycleInsnID*/ " << RecycleInsnID << ", /*Opcode*/" + << I->Namespace << "::" << I->TheDef->getName() << ",\n"; if (!I->ImplicitDefs.empty() || !I->ImplicitUses.empty()) { - OS << " auto MIB = MachineInstrBuilder(MF, &" << RecycleVarName - << ");\n"; - for (auto Def : I->ImplicitDefs) { auto Namespace = Def->getValue("Namespace") ? Def->getValueAsString("Namespace") : ""; - OS << " MIB.addDef(" << Namespace << "::" << Def->getName() - << ", RegState::Implicit);\n"; + OS << " GIR_AddImplicitDef, " << InsnID << ", " << Namespace + << "::" << Def->getName() << ",\n"; } for (auto Use : I->ImplicitUses) { auto Namespace = Use->getValue("Namespace") ? Use->getValueAsString("Namespace") : ""; - OS << " MIB.addUse(" << Namespace << "::" << Use->getName() - << ", RegState::Implicit);\n"; + OS << " GIR_AddImplicitUse, " << InsnID << ", " << Namespace + << "::" << Use->getName() << ",\n"; } } - - OS << " MachineInstr &" << Name << " = " << RecycleVarName << ";\n"; return; } // TODO: Simple permutation looks like it could be almost as common as // mutation due to commutative operations. - OS << " MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, " - "I.getDebugLoc(), TII.get(" - << I->Namespace << "::" << I->TheDef->getName() << "));\n"; + OS << " GIR_BuildMI, /*InsnID*/" << InsnID << ", /*Opcode*/" + << I->Namespace << "::" << I->TheDef->getName() << ",\n"; for (const auto &Renderer : OperandRenderers) Renderer->emitCxxRenderStmts(OS, Rule); - OS << " for (const auto *FromMI : "; - Rule.emitCxxCapturedInsnList(OS); - OS << ")\n"; - OS << " for (const auto &MMO : FromMI->memoperands())\n"; - OS << " MIB.addMemOperand(MMO);\n"; - OS << " " << RecycleVarName << ".eraseFromParent();\n"; - OS << " MachineInstr &" << Name << " = *MIB;\n"; + + OS << " GIR_MergeMemOperands, /*InsnID*/" << InsnID << ",\n" + << " GIR_EraseFromParent, /*InsnID*/" << RecycleInsnID << ",\n"; } }; /// Generates code to constrain the operands of an output instruction to the /// register classes specified by the definition of that instruction. class ConstrainOperandsToDefinitionAction : public MatchAction { - std::string Name; + unsigned InsnID; public: - ConstrainOperandsToDefinitionAction(const StringRef Name) : Name(Name) {} + ConstrainOperandsToDefinitionAction(unsigned InsnID) : InsnID(InsnID) {} void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef RecycleVarName) const override { - OS << " constrainSelectedInstRegOperands(" << Name - << ", TII, TRI, RBI);\n"; + unsigned RecycleInsnID) const override { + OS << " GIR_ConstrainSelectedInstOperands, /*InsnID*/" << InsnID << ",\n"; } }; /// Generates code to constrain the specified operand of an output instruction /// to the specified register class. class ConstrainOperandToRegClassAction : public MatchAction { - std::string Name; + unsigned InsnID; unsigned OpIdx; const CodeGenRegisterClass &RC; public: - ConstrainOperandToRegClassAction(const StringRef Name, unsigned OpIdx, + ConstrainOperandToRegClassAction(unsigned InsnID, unsigned OpIdx, const CodeGenRegisterClass &RC) - : Name(Name), OpIdx(OpIdx), RC(RC) {} + : InsnID(InsnID), OpIdx(OpIdx), RC(RC) {} void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef RecycleVarName) const override { - OS << " constrainOperandRegToRegClass(" << Name << ", " << OpIdx - << ", " << RC.getQualifiedName() << "RegClass, TII, TRI, RBI);\n"; + unsigned RecycleInsnID) const override { + OS << " GIR_ConstrainOperandRC, /*InsnID*/" << InsnID << ", /*Op*/" + << OpIdx << ", /*RC " << RC.getName() << "*/ " << RC.EnumValue << ",\n"; } }; @@ -1232,20 +1233,6 @@ llvm_unreachable("Matched Insn was not captured in a local variable"); } -/// Emit a C++ initializer_list containing references to every matched -/// instruction. -void RuleMatcher::emitCxxCapturedInsnList(raw_ostream &OS) { - SmallVector IDs; - for (const auto &Pair : InsnVariableIDs) - IDs.push_back(Pair.second); - std::sort(IDs.begin(), IDs.end()); - - OS << "{"; - 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) { @@ -1285,6 +1272,8 @@ << " };\n" << " State.MIs.clear();\n" << " State.MIs.push_back(&I);\n" + << " DEBUG(dbgs() << \"Processing MatchTable" << NumPatternEmitted + << "\\n\");\n" << " if (executeMatchTable(*this, State, MatcherInfo, MatchTable" << NumPatternEmitted << ", MRI, TRI, RBI, AvailableFeatures)) {\n"; @@ -1344,9 +1333,16 @@ } } - for (const auto &MA : Actions) { - MA->emitCxxActionStmts(OS, *this, "I"); - } + OS << " const static int64_t EmitTable" << NumPatternEmitted << "[] = {\n"; + for (const auto &MA : Actions) + MA->emitCxxActionStmts(OS, *this, 0); + OS << " GIR_Done,\n" + << " };\n" + << " NewMIVector OutMIs;\n" + << " DEBUG(dbgs() << \"Processing EmitTable" << NumPatternEmitted + << "\\n\");\n" + << " executeEmitTable(OutMIs, State, EmitTable" << NumPatternEmitted + << ", TII, TRI, RBI);\n"; OS << " return true;\n"; OS << " }\n\n"; @@ -1623,7 +1619,7 @@ if (DstChild->getOperator()->isSubClassOf("SDNode")) { auto &ChildSDNI = CGP.getSDNodeInfo(DstChild->getOperator()); if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") { - DstMIBuilder.addRenderer(InsnMatcher, + DstMIBuilder.addRenderer(0, InsnMatcher, DstChild->getName()); return Error::success(); } @@ -1648,13 +1644,14 @@ return failedImport("Dst operand has an unsupported type"); if (ChildRec->isSubClassOf("Register")) { - DstMIBuilder.addRenderer(ChildRec); + DstMIBuilder.addRenderer(0, ChildRec); return Error::success(); } if (ChildRec->isSubClassOf("RegisterClass") || ChildRec->isSubClassOf("RegisterOperand")) { - DstMIBuilder.addRenderer(InsnMatcher, DstChild->getName()); + DstMIBuilder.addRenderer(0, InsnMatcher, + DstChild->getName()); return Error::success(); } @@ -1666,7 +1663,7 @@ const OperandMatcher &OM = InsnMatcher.getOperand(DstChild->getName()); DstMIBuilder.addRenderer( - *ComplexPattern->second, DstChild->getName(), + 0, *ComplexPattern->second, DstChild->getName(), OM.getAllocatedTemporariesBaseID()); return Error::success(); } @@ -1709,12 +1706,12 @@ IsExtractSubReg = true; } - auto &DstMIBuilder = M.addAction("NewI", DstI, InsnMatcher); + auto &DstMIBuilder = M.addAction(0, DstI, InsnMatcher); // Render the explicit defs. for (unsigned I = 0; I < DstI->Operands.NumDefs; ++I) { const CGIOperandList::OperandInfo &DstIOperand = DstI->Operands[I]; - DstMIBuilder.addRenderer(InsnMatcher, DstIOperand.Name); + DstMIBuilder.addRenderer(0, InsnMatcher, DstIOperand.Name); } // EXTRACT_SUBREG needs to use a subregister COPY. @@ -1737,7 +1734,7 @@ } DstMIBuilder.addRenderer( - InsnMatcher, Dst->getChild(0)->getName(), SubIdx); + 0, InsnMatcher, Dst->getChild(0)->getName(), SubIdx); return DstMIBuilder; } @@ -1793,12 +1790,12 @@ } if (const DefInit *DefaultDefOp = dyn_cast(DefaultOp)) { - DstMIBuilder.addRenderer(DefaultDefOp->getDef()); + DstMIBuilder.addRenderer(0, DefaultDefOp->getDef()); continue; } if (const IntInit *DefaultIntOp = dyn_cast(DefaultOp)) { - DstMIBuilder.addRenderer(DefaultIntOp->getValue()); + DstMIBuilder.addRenderer(0, DefaultIntOp->getValue()); continue; } @@ -1917,7 +1914,7 @@ return failedImport("COPY_TO_REGCLASS operand #1 isn't a register class"); M.addAction( - "NewI", 0, Target.getRegisterClass(DstIOpRec)); + 0, 0, Target.getRegisterClass(DstIOpRec)); // We're done with this pattern! It's eligible for GISel emission; return // it. @@ -1945,8 +1942,7 @@ return failedImport("EXTRACT_SUBREG operand #1 isn't a register class"); CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef()); - CodeGenRegisterClass *SrcRC = CGRegs.getRegClass( - getInitValueAsRegClass(Dst->getChild(0)->getLeafValue())); + CodeGenRegisterClass *SrcRC = CGRegs.getRegClass(DstIOpRec); // It would be nice to leave this constraint implicit but we're required // to pick a register class so constrain the result to a register class @@ -1960,12 +1956,16 @@ const auto &SrcRCDstRCPair = SrcRC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx); assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass"); - M.addAction("NewI", 0, - *SrcRCDstRCPair->second); - M.addAction("NewI", 1, - *SrcRCDstRCPair->first); - } else - M.addAction("NewI"); + M.addAction(0, 0, *SrcRCDstRCPair->second); + M.addAction(0, 1, *SrcRCDstRCPair->first); + + // We're done with this pattern! It's eligible for GISel emission; return + // it. + ++NumPatternImported; + return std::move(M); + } + + M.addAction(0); // We're done with this pattern! It's eligible for GISel emission; return it. ++NumPatternImported;