//===- Test the function boilerplate. -------------------------------------===//
+// CHECK: const unsigned MAX_SUBTARGET_PREDICATES = 3;
+// CHECK: using PredicateBitset = llvm::PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;
+
+// CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_DECL
+// CHECK-NEXT: mutable MatcherState State;
+// CHECK-NEXT: typedef ComplexRendererFn(MyTargetInstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const;
+// CHECK-NEXT: const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> MatcherInfo;
+// CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL
+
+// CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_INIT
+// CHECK-NEXT: , State(2),
+// CHECK-NEXT: MatcherInfo({TypeObjects, FeatureBitsets, {
+// CHECK-NEXT: nullptr, // GICP_Invalid
+// CHECK-NEXT: &MyTargetInstructionSelector::selectComplexPattern, // gi_complex
+// CHECK-NEXT: }})
+// CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT
+
// CHECK-LABEL: enum SubtargetFeatureBits : uint8_t {
// CHECK-NEXT: Feature_HasABit = 0,
// CHECK-NEXT: Feature_HasBBit = 1,
// CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I) const {
// CHECK: MachineFunction &MF = *I.getParent()->getParent();
-// CHECK: const MachineRegisterInfo &MRI = MF.getRegInfo();
+// CHECK: MachineRegisterInfo &MRI = MF.getRegInfo();
+// CHECK: AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, &MF);
+// CHECK: const PredicateBitset AvailableFeatures = getAvailableFeatures();
//===- Test a pattern with multiple ComplexPattern operands. --------------===//
//
-// CHECK-LABEL: if ([&]() {
-// CHECK-NEXT: MachineInstr &MI0 = I;
-// CHECK-NEXT: if (MI0.getNumOperands() < 4)
-// CHECK-NEXT: return false;
-// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_SELECT) &&
-// 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: ((Renderer0 = selectComplexPattern(MI0.getOperand(2)))))) &&
-// CHECK-NEXT: ((/* src3 */ (MRI.getType(MI0.getOperand(3).getReg()) == (LLT::scalar(32))) &&
-// 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: 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);
-// CHECK-NEXT: I.eraseFromParent();
-// CHECK-NEXT: MachineInstr &NewI = *MIB;
-// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);
-// CHECK-NEXT: return true;
-// CHECK-NEXT: }
+// CHECK-LABEL: MatchTable0[] = {
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex,
+// CHECK-NEXT: // MIs[0] src3
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/3, /*Renderer*/1, GICP_gi_complex,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
def : GINodeEquiv<G_SELECT, select>;
def INSN2 : I<(outs GPR32:$dst), (ins GPR32Op:$src1, complex:$src2, complex:$src3), []>;
//===- Test a simple pattern with regclass operands. ----------------------===//
-// 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; }
-
+// CHECK-LABEL: MatchTable1[] = {
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID
+// CHECK-NEXT: // MIs[0] src2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2),
[(set GPR32:$dst, (add GPR32:$src1, GPR32:$src2))]>;
//===- Test a nested instruction match. -----------------------------------===//
-// CHECK-LABEL: if ([&]() {
-// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit};
-// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)
-// CHECK-NEXT: return false;
-// CHECK-NEXT: MachineInstr &MI0 = I;
-// CHECK-NEXT: if (MI0.getNumOperands() < 3)
-// CHECK-NEXT: return false;
-// CHECK-NEXT: if (!MI0.getOperand(1).isReg())
-// CHECK-NEXT: return false;
-// CHECK-NEXT: if (TRI.isPhysicalRegister(MI0.getOperand(1).getReg()))
-// CHECK-NEXT: return false;
-// CHECK-NEXT: MachineInstr &MI1 = *MRI.getVRegDef(MI0.getOperand(1).getReg());
-// CHECK-NEXT: if (MI1.getNumOperands() < 3)
+// CHECK-LABEL: MatchTable2[] = {
+// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA,
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_ADD,
+// CHECK-NEXT: // MIs[1] Operand 0
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: // MIs[1] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[1] src2
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src3
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: 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: ((/* Operand 1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: (((MI1.getOpcode() == TargetOpcode::G_ADD) &&
-// CHECK-NEXT: ((/* Operand 0 */ (MRI.getType(MI1.getOperand(0).getReg()) == (LLT::scalar(32))))) &&
-// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI1.getOperand(1).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI1.getOperand(1).getReg(), MRI, TRI))))) &&
-// CHECK-NEXT: ((/* src2 */ (MRI.getType(MI1.getOperand(2).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI1.getOperand(2).getReg(), MRI, TRI))))))
-// CHECK-NEXT: ))) &&
-// CHECK-NEXT: ((/* src3 */ (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: if (!isObviouslySafeToFold(MI1)) 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(MI0.getOperand(0)/*dst*/);
-// CHECK-NEXT: MIB.add(MI1.getOperand(1)/*src1*/);
-// CHECK-NEXT: MIB.add(MI1.getOperand(2)/*src2*/);
-// CHECK-NEXT: MIB.add(MI0.getOperand(2)/*src3*/);
-// CHECK-NEXT: for (const auto *FromMI : {&MI0, &MI1, })
-// 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: // (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: return true;
+// CHECK-NEXT: }
// We also get a second rule by commutativity.
-// CHECK-LABEL: if ([&]() {
-// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit};
-// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)
-// CHECK-NEXT: return false;
-// CHECK-NEXT: MachineInstr &MI0 = I;
-// CHECK-NEXT: if (MI0.getNumOperands() < 3)
-// CHECK-NEXT: return false;
-// CHECK-NEXT: if (!MI0.getOperand(2).isReg())
-// CHECK-NEXT: return false;
-// CHECK-NEXT: if (TRI.isPhysicalRegister(MI0.getOperand(2).getReg()))
-// CHECK-NEXT: return false;
-// CHECK-NEXT: MachineInstr &MI1 = *MRI.getVRegDef(MI0.getOperand(2).getReg());
-// CHECK-NEXT: if (MI1.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: ((/* src3 */ (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: (((MI1.getOpcode() == TargetOpcode::G_ADD) &&
-// CHECK-NEXT: ((/* Operand 0 */ (MRI.getType(MI1.getOperand(0).getReg()) == (LLT::scalar(32))))) &&
-// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI1.getOperand(1).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI1.getOperand(1).getReg(), MRI, TRI))))) &&
-// CHECK-NEXT: ((/* src2 */ (MRI.getType(MI1.getOperand(2).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI1.getOperand(2).getReg(), MRI, TRI))))))
-// CHECK-NEXT: )))) {
-// CHECK-NEXT: if (!isObviouslySafeToFold(MI1)) 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-LABEL: MatchTable3[] = {
+// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA,
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/2,
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src3
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_ADD,
+// CHECK-NEXT: // MIs[1] Operand 0
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: // MIs[1] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[1] src2
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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(MI0.getOperand(0)/*dst*/);
-// CHECK-NEXT: MIB.add(MI1.getOperand(1)/*src1*/);
-// CHECK-NEXT: MIB.add(MI1.getOperand(2)/*src2*/);
-// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src3*/);
-// CHECK-NEXT: for (const auto *FromMI : {&MI0, &MI1, })
+// 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();
//===- Test another simple pattern with regclass operands. ----------------===//
-// CHECK-LABEL: if ([&]() {
-// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit, Feature_HasBBit, Feature_HasCBit};
-// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)
-// CHECK-NEXT: return false;
-// 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: for (const auto *FromMI : {&MI0, })
-// 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: return false;
-// CHECK-NEXT: }()) { return true; }
+// CHECK-LABEL: MatchTable4[] = {
+// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA_HasB_HasC,
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1),
[(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>,
Requires<[HasA, HasB, HasC]>;
+//===- Test a more complex multi-instruction match. -----------------------===//
+
+// CHECK-LABEL: MatchTable5[] = {
+// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA,
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
+// CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/2, /*MI*/0, /*OpIdx*/2, // MIs[2]
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/2, /*Expected*/3,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_SUB,
+// CHECK-NEXT: // MIs[1] Operand 0
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: // MIs[1] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[1] src2
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/2, TargetOpcode::G_SUB,
+// CHECK-NEXT: // MIs[2] Operand 0
+// CHECK-NEXT: GIM_CheckType, /*MI*/2, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: // MIs[2] src3
+// CHECK-NEXT: GIM_CheckType, /*MI*/2, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/2, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[2] src4
+// CHECK-NEXT: GIM_CheckType, /*MI*/2, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/2, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
+
+def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, GPR32:$src4),
+ [(set GPR32:$dst,
+ (sub (sub GPR32:$src1, GPR32:$src2), (sub GPR32:$src3, GPR32:$src4)))]>,
+ Requires<[HasA]>;
+
//===- Test a pattern with ComplexPattern operands. -----------------------===//
//
-// 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_SUB) &&
-// 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: ((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: Renderer0(MIB);
-// CHECK-NEXT: for (const auto *FromMI : {&MI0, })
-// 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-LABEL: MatchTable6[] = {
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
def INSN1 : I<(outs GPR32:$dst), (ins GPR32:$src1, complex:$src2), []>;
def : Pat<(sub GPR32:$src1, complex:$src2), (INSN1 GPR32:$src1, complex:$src2)>;
//===- Test a simple pattern with a default operand. ----------------------===//
//
-// 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: ((/* 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: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: (isOperandImmEqual(MI0.getOperand(2), -2, MRI))))) {
-// 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(MI0.getOperand(0)/*dst*/);
-// CHECK-NEXT: MIB.addImm(-1);
-// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/);
-// CHECK-NEXT: for (const auto *FromMI : {&MI0, })
-// 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: return false;
-// CHECK-NEXT: }()) { return true; }
+// CHECK-LABEL: MatchTable7[] = {
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -2
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
// The -2 is just to distinguish it from the 'not' case below.
def XORI : I<(outs GPR32:$dst), (ins m1:$src2, GPR32:$src1),
//===- Test a simple pattern with a default register operand. -------------===//
//
-// 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: ((/* 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: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: (isOperandImmEqual(MI0.getOperand(2), -3, MRI))))) {
-// 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(MI0.getOperand(0)/*dst*/);
-// CHECK-NEXT: MIB.addReg(MyTarget::R0);
-// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/);
-// CHECK-NEXT: for (const auto *FromMI : {&MI0, })
-// 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: return false;
-// CHECK-NEXT: }()) { return true; }
+// CHECK-LABEL: MatchTable8[] = {
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -3
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
// The -3 is just to distinguish it from the 'not' case below and the other default op case above.
def XOR : I<(outs GPR32:$dst), (ins Z:$src2, GPR32:$src1),
//===- Test a simple pattern with a multiple default operands. ------------===//
//
-// 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: ((/* 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: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: (isOperandImmEqual(MI0.getOperand(2), -4, MRI))))) {
-// 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(MI0.getOperand(0)/*dst*/);
-// CHECK-NEXT: MIB.addImm(-1);
-// CHECK-NEXT: MIB.addReg(MyTarget::R0);
-// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/);
-// CHECK-NEXT: for (const auto *FromMI : {&MI0, })
-// 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: return false;
-// CHECK-NEXT: }()) { return true; }
+// CHECK-LABEL: MatchTable9[] = {
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -4
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
// The -4 is just to distinguish it from the other 'not' cases.
def XORlike : I<(outs GPR32:$dst), (ins m1Z:$src2, GPR32:$src1),
//===- Test a simple pattern with multiple operands with defaults. --------===//
//
-// 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: ((/* 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: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) &&
-// CHECK-NEXT: (isOperandImmEqual(MI0.getOperand(2), -5, MRI))))) {
-// 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(MI0.getOperand(0)/*dst*/);
-// CHECK-NEXT: MIB.addImm(-1);
-// CHECK-NEXT: MIB.addReg(MyTarget::R0);
-// CHECK-NEXT: MIB.addReg(MyTarget::R0);
-// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/);
-// CHECK-NEXT: for (const auto *FromMI : {&MI0, })
-// 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: return false;
-// CHECK-NEXT: }()) { return true; }
+// CHECK-LABEL: MatchTable10[] = {
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -5,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
// The -5 is just to distinguish it from the other cases.
def XORManyDefaults : I<(outs GPR32:$dst), (ins m1Z:$src3, Z:$src2, GPR32:$src1),
// This must precede the 3-register variants because constant immediates have
// priority over register banks.
-// 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: for (const auto *FromMI : {&MI0, })
-// 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: return false;
-// CHECK-NEXT: }()) { return true; }
+// CHECK-LABEL: MatchTable11[] = {
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Wm
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -1,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
def ORN : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>;
def : Pat<(not GPR32:$Wm), (ORN R0, GPR32:$Wm)>;
//===- Test a COPY_TO_REGCLASS --------------------------------------------===//
//
-// CHECK-LABEL: if ([&]() {
-// CHECK-NEXT: MachineInstr &MI0 = I;
-// CHECK-NEXT: if (MI0.getNumOperands() < 2)
-// CHECK-NEXT: return false;
-// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_BITCAST) &&
-// 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::FPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))))
-// 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: return true;
-// CHECK-NEXT: }
-// CHECK-NEXT: return false;
-// CHECK-NEXT: }()) { return true; }
+// CHECK-LABEL: MatchTable12[] = {
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BITCAST,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::FPR32RegClassID,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
def : Pat<(i32 (bitconvert FPR32:$src1)),
(COPY_TO_REGCLASS FPR32:$src1, GPR32)>;
//===- Test a simple pattern with just a leaf immediate. ------------------===//
-// CHECK-LABEL: if ([&]() {
-// CHECK-NEXT: MachineInstr &MI0 = I;
-// CHECK-NEXT: if (MI0.getNumOperands() < 2)
-// CHECK-NEXT: return false;
-// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_CONSTANT) &&
-// 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: ((/* Operand 1 */ (MI0.getOperand(1).isCImm() && MI0.getOperand(1).getCImm()->equalsInt(1))))) {
-// CHECK-NEXT: // 1:i32 => (MOV1:i32)
-// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MOV1));
-// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/);
-// CHECK-NEXT: for (const auto *FromMI : {&MI0, })
-// 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: return false;
-// CHECK-NEXT: }()) { return true; }
+// CHECK-LABEL: MatchTable13[] = {
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 1
+// CHECK-NEXT: GIM_CheckLiteralInt, /*MI*/0, /*Op*/1, 1,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: return true;
+// CHECK-NEXT: }
def MOV1 : I<(outs GPR32:$dst), (ins), [(set GPR32:$dst, 1)]>;
//===- Test a pattern with an MBB operand. --------------------------------===//
-// 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; }
+// CHECK-LABEL: MatchTable14[] = {
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/1,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BR,
+// CHECK-NEXT: // MIs[0] target
+// CHECK-NEXT: GIM_CheckIsMBB, /*MI*/0, /*Op*/0,
+// CHECK-NEXT: GIM_Accept,
+// CHECK-NEXT: };
+// CHECK-NEXT: MIs.clear();
+// CHECK-NEXT: MIs.push_back(&I);
+// 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: }
def BR : I<(outs), (ins unknown:$target),
[(br bb:$target)]>;
public:
LLTCodeGen(const LLT &Ty) : Ty(Ty) {}
+ void emitCxxEnumValue(raw_ostream &OS) const {
+ if (Ty.isScalar()) {
+ OS << "GILLT_s" << Ty.getSizeInBits();
+ return;
+ }
+ if (Ty.isVector()) {
+ OS << "GILLT_v" << Ty.getNumElements() << "s" << Ty.getScalarSizeInBits();
+ return;
+ }
+ llvm_unreachable("Unhandled LLT");
+ }
+
void emitCxxConstructorCall(raw_ostream &OS) const {
if (Ty.isScalar()) {
OS << "LLT::scalar(" << Ty.getSizeInBits() << ")";
}
const LLT &get() const { return Ty; }
+
+ /// This ordering is used for std::unique() and std::sort(). There's no
+ /// particular logic behind the order.
+ bool operator<(const LLTCodeGen &Other) const {
+ if (!Ty.isValid())
+ return Other.Ty.isValid();
+ if (Ty.isScalar()) {
+ if (!Other.Ty.isValid())
+ return false;
+ if (Other.Ty.isScalar())
+ return Ty.getSizeInBits() < Other.Ty.getSizeInBits();
+ return false;
+ }
+ if (Ty.isVector()) {
+ if (!Other.Ty.isValid() || Other.Ty.isScalar())
+ return false;
+ if (Other.Ty.isVector()) {
+ if (Ty.getNumElements() < Other.Ty.getNumElements())
+ return true;
+ if (Ty.getNumElements() > Other.Ty.getNumElements())
+ return false;
+ return Ty.getSizeInBits() < Other.Ty.getSizeInBits();
+ }
+ return false;
+ }
+ llvm_unreachable("Unhandled LLT");
+ }
};
class InstructionMatcher;
return nullptr;
}
+std::string
+getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) {
+ std::string Name = "GIFBS";
+ for (const auto &Feature : FeatureBitset)
+ Name += ("_" + Feature->getName()).str();
+ return Name;
+}
//===- Matchers -----------------------------------------------------------===//
class OperandMatcher;
/// A map of instruction matchers to the local variables created by
/// emitCxxCaptureStmts().
- std::map<const InstructionMatcher *, std::string> InsnVariableNames;
+ std::map<const InstructionMatcher *, unsigned> InsnVariableIDs;
/// ID for the next instruction variable defined with defineInsnVar()
unsigned NextInsnVarID;
public:
RuleMatcher()
- : Matchers(), Actions(), InsnVariableNames(), NextInsnVarID(0) {}
+ : Matchers(), Actions(), InsnVariableIDs(), NextInsnVarID(0) {}
RuleMatcher(RuleMatcher &&Other) = default;
RuleMatcher &operator=(RuleMatcher &&Other) = default;
InstructionMatcher &addInstructionMatcher();
void addRequiredFeature(Record *Feature);
+ const std::vector<Record *> &getRequiredFeatures() const;
template <class Kind, class... Args> Kind &addAction(Args &&... args);
- std::string defineInsnVar(raw_ostream &OS, const InstructionMatcher &Matcher,
- StringRef Value);
- StringRef getInsnVarName(const InstructionMatcher &InsnMatcher) const;
+ /// Define an instruction without emitting any code to do so.
+ /// This is used for the root of the match.
+ unsigned implicitlyDefineInsnVar(const InstructionMatcher &Matcher);
+ /// Define an instruction and emit corresponding state-machine opcodes.
+ unsigned defineInsnVar(raw_ostream &OS, const InstructionMatcher &Matcher,
+ unsigned InsnVarID, unsigned OpIdx);
+ unsigned getInsnVarID(const InstructionMatcher &InsnMatcher) const;
void emitCxxCapturedInsnList(raw_ostream &OS);
- void emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr);
+ void emitCxxCaptureStmts(raw_ostream &OS);
-void emit(raw_ostream &OS, SubtargetFeatureInfoMap SubtargetFeatures);
+ void emit(raw_ostream &OS);
-/// Compare the priority of this object and B.
-///
-/// Returns true if this object is more important than B.
-bool isHigherPriorityThan(const RuleMatcher &B) const;
+ /// Compare the priority of this object and B.
+ ///
+ /// Returns true if this object is more important than B.
+ bool isHigherPriorityThan(const RuleMatcher &B) const;
-/// Report the maximum number of temporary operands needed by the rule
-/// matcher.
-unsigned countRendererFns() const;
+ /// Report the maximum number of temporary operands needed by the rule
+ /// matcher.
+ unsigned countRendererFns() const;
-// FIXME: Remove this as soon as possible
-InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); }
+ // FIXME: Remove this as soon as possible
+ InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); }
};
template <class PredicateTy> class PredicateListMatcher {
template <class... Args>
void emitCxxPredicateListExpr(raw_ostream &OS, Args &&... args) const {
if (Predicates.empty()) {
- OS << "true";
+ OS << "// No predicates\n";
return;
}
- StringRef Separator = "";
- for (const auto &Predicate : predicates()) {
- OS << Separator << "(";
+ for (const auto &Predicate : predicates())
Predicate->emitCxxPredicateExpr(OS, std::forward<Args>(args)...);
- OS << ")";
- Separator = " &&\n";
- }
}
};
///
/// Only InstructionOperandMatcher needs to do anything for this method.
virtual void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule,
- StringRef Expr) const {}
+ unsigned InsnVarID, unsigned OpIdx) const {}
/// Emit a C++ expression that checks the predicate for the given operand.
virtual void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const = 0;
+ unsigned InsnVarID,
+ unsigned OpIdx) const = 0;
/// Compare the priority of this object and B.
///
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << "MRI.getType(" << OperandExpr << ".getReg()) == (";
- Ty.emitCxxConstructorCall(OS);
- OS << ")";
+ unsigned InsnVarID, unsigned OpIdx) const override {
+ OS << " GIM_CheckType, /*MI*/" << InsnVarID << ", /*Op*/" << OpIdx
+ << ", /*Type*/";
+ Ty.emitCxxEnumValue(OS);
+ OS << ", \n";
}
};
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
+ unsigned InsnVarID, unsigned OpIdx) const override {
unsigned ID = getAllocatedTemporariesBaseID();
- OS << "(Renderer" << ID << " = " << TheDef.getValueAsString("MatcherFn")
- << "(" << OperandExpr << "))";
+ OS << " GIM_CheckComplexPattern, /*MI*/" << InsnVarID << ", /*Op*/"
+ << OpIdx << ", /*Renderer*/" << ID << ", GICP_"
+ << TheDef.getName() << ",\n";
}
unsigned countRendererFns() const override {
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << "(&RBI.getRegBankFromRegClass(" << RC.getQualifiedName()
- << "RegClass) == RBI.getRegBank(" << OperandExpr
- << ".getReg(), MRI, TRI))";
+ unsigned InsnVarID, unsigned OpIdx) const override {
+ OS << " GIM_CheckRegBankForClass, /*MI*/" << InsnVarID << ", /*Op*/"
+ << OpIdx << ", /*RC*/" << RC.getQualifiedName() << "RegClassID,\n";
}
};
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << OperandExpr << ".isMBB()";
+ unsigned InsnVarID, unsigned OpIdx) const override {
+ OS << " GIM_CheckIsMBB, /*MI*/" << InsnVarID << ", /*Op*/" << OpIdx << ",\n";
}
};
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << "isOperandImmEqual(" << OperandExpr << ", " << Value << ", MRI)";
+ unsigned InsnVarID, unsigned OpIdx) const override {
+ OS << " GIM_CheckConstantInt, /*MI*/" << InsnVarID << ", /*Op*/"
+ << OpIdx << ", " << Value << ",\n";
}
};
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << OperandExpr << ".isCImm() && " << OperandExpr
- << ".getCImm()->equalsInt(" << Value << ")";
+ unsigned InsnVarID, unsigned OpIdx) const override {
+ OS << " GIM_CheckLiteralInt, /*MI*/" << InsnVarID << ", /*Op*/"
+ << OpIdx << ", " << Value << ",\n";
}
};
}
unsigned getOperandIndex() const { return OpIdx; }
- std::string getOperandExpr(StringRef InsnVarName) const {
- return (InsnVarName + ".getOperand(" + llvm::to_string(OpIdx) + ")").str();
+ std::string getOperandExpr(unsigned InsnVarID) const {
+ return "State.MIs[" + llvm::to_string(InsnVarID) + "]->getOperand(" +
+ llvm::to_string(OpIdx) + ")";
}
Optional<const OperandMatcher *>
/// Emit C++ statements to capture instructions into local variables.
void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const {
+ unsigned InsnVarID) const {
for (const auto &Predicate : predicates())
- Predicate->emitCxxCaptureStmts(OS, Rule, OperandExpr);
+ Predicate->emitCxxCaptureStmts(OS, Rule, InsnVarID, OpIdx);
}
/// Emit a C++ expression that tests whether the instruction named in
- /// InsnVarName matches all the predicate and all the operands.
+ /// InsnVarID matches all the predicates and all the operands.
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef InsnVarName) const {
- OS << "(/* ";
+ unsigned InsnVarID) const {
+ OS << " // MIs[" << InsnVarID << "] ";
if (SymbolicName.empty())
OS << "Operand " << OpIdx;
else
OS << SymbolicName;
- OS << " */ ";
- emitCxxPredicateListExpr(OS, Rule, getOperandExpr(InsnVarName));
- OS << ")";
+ OS << "\n";
+ emitCxxPredicateListExpr(OS, Rule, InsnVarID, OpIdx);
}
/// Compare the priority of this object and B.
PredicateKind getKind() const { return Kind; }
/// Emit a C++ expression that tests whether the instruction named in
- /// InsnVarName matches the predicate.
+ /// InsnVarID matches the predicate.
virtual void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef InsnVarName) const = 0;
+ unsigned InsnVarID) const = 0;
/// Compare the priority of this object and B.
///
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef InsnVarName) const override {
- OS << InsnVarName << ".getOpcode() == " << I->Namespace
- << "::" << I->TheDef->getName();
+ unsigned InsnVarID) const override {
+ OS << " GIM_CheckOpcode, /*MI*/" << InsnVarID << ", " << I->Namespace
+ << "::" << I->TheDef->getName() << ",\n";
}
/// Compare the priority of this object and B.
/// Emit C++ statements to check the shape of the match and capture
/// instructions into local variables.
- void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, StringRef Expr) {
- OS << "if (" << Expr << ".getNumOperands() < " << getNumOperands() << ")\n"
- << " return false;\n";
- for (const auto &Operand : Operands) {
- Operand->emitCxxCaptureStmts(OS, Rule, Operand->getOperandExpr(Expr));
- }
+ void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule,
+ unsigned InsnID) {
+ OS << " GIM_CheckNumOperands, /*MI*/" << InsnID << ", /*Expected*/"
+ << getNumOperands() << ",\n";
+ for (const auto &Operand : Operands)
+ Operand->emitCxxCaptureStmts(OS, Rule, InsnID);
}
/// 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, RuleMatcher &Rule,
- StringRef InsnVarName) const {
- emitCxxPredicateListExpr(OS, Rule, InsnVarName);
- for (const auto &Operand : Operands) {
- OS << " &&\n(";
- Operand->emitCxxPredicateExpr(OS, Rule, InsnVarName);
- OS << ")";
- }
+ unsigned InsnVarID) const {
+ emitCxxPredicateListExpr(OS, Rule, InsnVarID);
+ for (const auto &Operand : Operands)
+ Operand->emitCxxPredicateExpr(OS, Rule, InsnVarID);
}
/// Compare the priority of this object and B.
}
void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OS << "if (!" << OperandExpr + ".isReg())\n"
- << " return false;\n"
- << "if (TRI.isPhysicalRegister(" << OperandExpr + ".getReg()))\n"
- << " return false;\n";
- std::string InsnVarName = Rule.defineInsnVar(
- OS, *InsnMatcher,
- ("*MRI.getVRegDef(" + OperandExpr + ".getReg())").str());
- InsnMatcher->emitCxxCaptureStmts(OS, Rule, InsnVarName);
+ unsigned InsnID, unsigned OpIdx) const override {
+ unsigned InsnVarID = Rule.defineInsnVar(OS, *InsnMatcher, InsnID, OpIdx);
+ InsnMatcher->emitCxxCaptureStmts(OS, Rule, InsnVarID);
}
void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
- StringRef OperandExpr) const override {
- OperandExpr = Rule.getInsnVarName(*InsnMatcher);
- OS << "(";
- InsnMatcher->emitCxxPredicateExpr(OS, Rule, OperandExpr);
- OS << ")\n";
+ unsigned InsnVarID_,
+ unsigned OpIdx_) const override {
+ unsigned InsnVarID = Rule.getInsnVarID(*InsnMatcher);
+ InsnMatcher->emitCxxPredicateExpr(OS, Rule, InsnVarID);
}
};
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);
+ unsigned InsnVarID =
+ Rule.getInsnVarID(Operand.getInstructionMatcher());
+ std::string OperandExpr = Operand.getOperandExpr(InsnVarID);
OS << " MIB.add(" << OperandExpr << "/*" << SymbolicName << "*/);\n";
}
};
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);
+ unsigned InsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
+ std::string OperandExpr = Operand.getOperandExpr(InsnVarID);
OS << " MIB.addReg(" << OperandExpr << ".getReg() /*" << SymbolicName
<< "*/, 0, " << SubReg->EnumValue << ");\n";
}
}
void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override {
- OS << "Renderer" << RendererID << "(MIB);\n";
+ OS << " State.Renderers[" << RendererID << "](MIB);\n";
}
};
void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule,
StringRef RecycleVarName) const override {
- OS << "// " << *P.getSrcPattern() << " => " << *P.getDstPattern() << "\n";
+ OS << " // " << *P.getSrcPattern() << " => " << *P.getDstPattern() << "\n";
}
};
// TODO: Simple permutation looks like it could be almost as common as
// mutation due to commutative operations.
- OS << "MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, "
+ OS << " MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, "
"I.getDebugLoc(), TII.get("
<< I->Namespace << "::" << I->TheDef->getName() << "));\n";
for (const auto &Renderer : OperandRenderers)
RequiredFeatures.push_back(Feature);
}
+const std::vector<Record *> &RuleMatcher::getRequiredFeatures() const {
+ return RequiredFeatures;
+}
+
template <class Kind, class... Args>
Kind &RuleMatcher::addAction(Args &&... args) {
Actions.emplace_back(llvm::make_unique<Kind>(std::forward<Args>(args)...));
return *static_cast<Kind *>(Actions.back().get());
}
-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;
+unsigned
+RuleMatcher::implicitlyDefineInsnVar(const InstructionMatcher &Matcher) {
+ unsigned NewInsnVarID = NextInsnVarID++;
+ InsnVariableIDs[&Matcher] = NewInsnVarID;
+ return NewInsnVarID;
}
-StringRef
-RuleMatcher::getInsnVarName(const InstructionMatcher &InsnMatcher) const {
- const auto &I = InsnVariableNames.find(&InsnMatcher);
- if (I != InsnVariableNames.end())
+unsigned RuleMatcher::defineInsnVar(raw_ostream &OS,
+ const InstructionMatcher &Matcher,
+ unsigned InsnID, unsigned OpIdx) {
+ unsigned NewInsnVarID = implicitlyDefineInsnVar(Matcher);
+ OS << " GIM_RecordInsn, /*DefineMI*/" << NewInsnVarID << ", /*MI*/"
+ << InsnID << ", /*OpIdx*/" << OpIdx << ", // MIs[" << NewInsnVarID
+ << "]\n";
+ return NewInsnVarID;
+}
+
+unsigned RuleMatcher::getInsnVarID(const InstructionMatcher &InsnMatcher) const {
+ const auto &I = InsnVariableIDs.find(&InsnMatcher);
+ if (I != InsnVariableIDs.end())
return I->second;
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<StringRef, 2> Names;
- for (const auto &Pair : InsnVariableNames)
- Names.push_back(Pair.second);
- std::sort(Names.begin(), Names.end());
+ SmallVector<unsigned, 2> IDs;
+ for (const auto &Pair : InsnVariableIDs)
+ IDs.push_back(Pair.second);
+ std::sort(IDs.begin(), IDs.end());
OS << "{";
- for (const auto &Name : Names)
- OS << "&" << Name << ", ";
+ 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, StringRef Expr) {
+void RuleMatcher::emitCxxCaptureStmts(raw_ostream &OS) {
assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet");
- std::string InsnVarName = defineInsnVar(OS, *Matchers.front(), Expr);
- Matchers.front()->emitCxxCaptureStmts(OS, *this, InsnVarName);
+ unsigned InsnVarID = implicitlyDefineInsnVar(*Matchers.front());
+ Matchers.front()->emitCxxCaptureStmts(OS, *this, InsnVarID);
}
-void RuleMatcher::emit(raw_ostream &OS,
- SubtargetFeatureInfoMap SubtargetFeatures) {
+void RuleMatcher::emit(raw_ostream &OS) {
if (Matchers.empty())
llvm_unreachable("Unexpected empty matcher!");
// 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 (";
- OS << "[&]() {\n";
+ OS << " const static int64_t MatchTable" << NumPatternEmitted << "[] = {\n";
if (!RequiredFeatures.empty()) {
- OS << " PredicateBitset ExpectedFeatures = {";
- StringRef Separator = "";
- for (const auto &Predicate : RequiredFeatures) {
- const auto &I = SubtargetFeatures.find(Predicate);
- assert(I != SubtargetFeatures.end() && "Didn't import predicate?");
- OS << Separator << I->second.getEnumBitName();
- Separator = ", ";
- }
- OS << "};\n";
- OS << "if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)\n"
- << " return false;\n";
+ OS << " GIM_CheckFeatures, " << getNameForFeatureBitset(RequiredFeatures)
+ << ",\n";
}
- emitCxxCaptureStmts(OS, "I");
- OS << " if (";
+ emitCxxCaptureStmts(OS);
+
Matchers.front()->emitCxxPredicateExpr(OS, *this,
- getInsnVarName(*Matchers.front()));
- OS << ") {\n";
+ getInsnVarID(*Matchers.front()));
+
+ OS << " GIM_Accept,\n"
+ << " };\n"
+ << " State.MIs.clear();\n"
+ << " State.MIs.push_back(&I);\n"
+ << " if (executeMatchTable(*this, State, MatcherInfo, MatchTable"
+ << NumPatternEmitted << ", MRI, TRI, RBI, AvailableFeatures)) {\n";
// We must also check if it's safe to fold the matched instructions.
- if (InsnVariableNames.size() >= 2) {
+ if (InsnVariableIDs.size() >= 2) {
// Invert the map to create stable ordering (by var names)
- SmallVector<StringRef, 2> Names;
- for (const auto &Pair : InsnVariableNames) {
+ SmallVector<unsigned, 2> InsnIDs;
+ for (const auto &Pair : InsnVariableIDs) {
// Skip the root node since it isn't moving anywhere. Everything else is
// sinking to meet it.
if (Pair.first == Matchers.front().get())
continue;
- Names.push_back(Pair.second);
+ InsnIDs.push_back(Pair.second);
}
- std::sort(Names.begin(), Names.end());
+ std::sort(InsnIDs.begin(), InsnIDs.end());
- for (const auto &Name : Names) {
+ for (const auto &InsnID : InsnIDs) {
// Reject the difficult cases until we have a more accurate check.
- OS << " if (!isObviouslySafeToFold(" << Name
- << ")) return false;\n";
+ OS << " if (!isObviouslySafeToFold(*State.MIs[" << InsnID << "]))\n"
+ << " return false;\n";
// FIXME: Emit checks to determine it's _actually_ safe to fold and/or
// account for unsafe cases.
MA->emitCxxActionStmts(OS, *this, "I");
}
- OS << " return true;\n";
- OS << " }\n";
- OS << " return false;\n";
- OS << " }()) { return true; }\n\n";
+ OS << " return true;\n";
+ OS << " }\n\n";
}
bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const {
return false;
});
+ std::vector<Record *> ComplexPredicates =
+ RK.getAllDerivedDefinitions("GIComplexOperandMatcher");
+ std::sort(ComplexPredicates.begin(), ComplexPredicates.end(),
+ [](const Record *A, const Record *B) {
+ if (A->getName() < B->getName())
+ return true;
+ return false;
+ });
unsigned MaxTemporaries = 0;
for (const auto &Rule : Rules)
MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());
"llvm::PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;\n"
<< "#endif // ifdef GET_GLOBALISEL_PREDICATE_BITSET\n\n";
- OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n";
- for (unsigned I = 0; I < MaxTemporaries; ++I)
- 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 << ", Renderer" << I << "(nullptr)\n";
- OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n";
+ OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n"
+ << " mutable MatcherState State;\n"
+ << " typedef "
+ "ComplexRendererFn("
+ << Target.getName()
+ << "InstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const;\n"
+ << "const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> "
+ "MatcherInfo;\n"
+ << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n";
+
+ OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"
+ << ", State(" << MaxTemporaries << "),\n"
+ << "MatcherInfo({TypeObjects, FeatureBitsets, {\n"
+ << " nullptr, // GICP_Invalid\n";
+ for (const auto &Record : ComplexPredicates)
+ OS << " &" << Target.getName()
+ << "InstructionSelector::" << Record->getValueAsString("MatcherFn")
+ << ", // " << Record->getName() << "\n";
+ OS << "}})\n"
+ << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n";
OS << "#ifdef GET_GLOBALISEL_IMPL\n";
SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures,
"computeAvailableFunctionFeatures", FunctionFeatures, OS,
"const MachineFunction *MF");
+ // Emit a table containing the LLT objects needed by the matcher and an enum
+ // for the matcher to reference them with.
+ std::vector<LLTCodeGen> TypeObjects = {
+ LLT::scalar(8), LLT::scalar(16), LLT::scalar(32),
+ LLT::scalar(64), LLT::scalar(80), LLT::vector(8, 1),
+ LLT::vector(16, 1), LLT::vector(32, 1), LLT::vector(64, 1),
+ LLT::vector(8, 8), LLT::vector(16, 8), LLT::vector(32, 8),
+ LLT::vector(64, 8), LLT::vector(4, 16), LLT::vector(8, 16),
+ LLT::vector(16, 16), LLT::vector(32, 16), LLT::vector(2, 32),
+ LLT::vector(4, 32), LLT::vector(8, 32), LLT::vector(16, 32),
+ LLT::vector(2, 64), LLT::vector(4, 64), LLT::vector(8, 64),
+ };
+ std::sort(TypeObjects.begin(), TypeObjects.end());
+ OS << "enum {\n";
+ for (const auto &TypeObject : TypeObjects) {
+ OS << " ";
+ TypeObject.emitCxxEnumValue(OS);
+ OS << ",\n";
+ }
+ OS << "};\n"
+ << "const static LLT TypeObjects[] = {\n";
+ for (const auto &TypeObject : TypeObjects) {
+ OS << " ";
+ TypeObject.emitCxxConstructorCall(OS);
+ OS << ",\n";
+ }
+ OS << "};\n\n";
+
+ // Emit a table containing the PredicateBitsets objects needed by the matcher
+ // and an enum for the matcher to reference them with.
+ std::vector<std::vector<Record *>> FeatureBitsets;
+ for (auto &Rule : Rules)
+ FeatureBitsets.push_back(Rule.getRequiredFeatures());
+ std::sort(
+ FeatureBitsets.begin(), FeatureBitsets.end(),
+ [&](const std::vector<Record *> &A, const std::vector<Record *> &B) {
+ if (A.size() < B.size())
+ return true;
+ if (A.size() > B.size())
+ return false;
+ for (const auto &Pair : zip(A, B)) {
+ if (std::get<0>(Pair)->getName() < std::get<1>(Pair)->getName())
+ return true;
+ if (std::get<0>(Pair)->getName() > std::get<1>(Pair)->getName())
+ return false;
+ }
+ return false;
+ });
+ FeatureBitsets.erase(
+ std::unique(FeatureBitsets.begin(), FeatureBitsets.end()),
+ FeatureBitsets.end());
+ OS << "enum {\n"
+ << " GIFBS_Invalid,\n";
+ for (const auto &FeatureBitset : FeatureBitsets) {
+ if (FeatureBitset.empty())
+ continue;
+ OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
+ }
+ OS << "};\n"
+ << "const static PredicateBitset FeatureBitsets[] {\n"
+ << " {}, // GIFBS_Invalid\n";
+ for (const auto &FeatureBitset : FeatureBitsets) {
+ if (FeatureBitset.empty())
+ continue;
+ OS << " {";
+ for (const auto &Feature : FeatureBitset) {
+ const auto &I = SubtargetFeatures.find(Feature);
+ assert(I != SubtargetFeatures.end() && "Didn't import predicate?");
+ OS << I->second.getEnumBitName() << ", ";
+ }
+ OS << "},\n";
+ }
+ OS << "};\n\n";
+
+ // Emit complex predicate table and an enum to reference them with.
+ OS << "enum {\n"
+ << " GICP_Invalid,\n";
+ for (const auto &Record : ComplexPredicates)
+ OS << " GICP_" << Record->getName() << ",\n";
+ OS << "};\n"
+ << "// See constructor for table contents\n\n";
+
OS << "bool " << Target.getName()
<< "InstructionSelector::selectImpl(MachineInstr &I) const {\n"
<< " MachineFunction &MF = *I.getParent()->getParent();\n"
- << " const MachineRegisterInfo &MRI = MF.getRegInfo();\n"
+ << " MachineRegisterInfo &MRI = MF.getRegInfo();\n"
<< " // FIXME: This should be computed on a per-function basis rather "
"than per-insn.\n"
<< " AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, "
<< " const PredicateBitset AvailableFeatures = getAvailableFeatures();\n";
for (auto &Rule : Rules) {
- Rule.emit(OS, SubtargetFeatures);
+ Rule.emit(OS);
++NumPatternEmitted;
}