Index: include/llvm/Target/GlobalISel/SelectionDAGCompat.td =================================================================== --- include/llvm/Target/GlobalISel/SelectionDAGCompat.td +++ include/llvm/Target/GlobalISel/SelectionDAGCompat.td @@ -62,6 +62,7 @@ def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; +def : GINodeEquiv; def : GINodeEquiv; // Specifies the GlobalISel equivalents for SelectionDAG's ComplexPattern. Index: test/TableGen/GlobalISelEmitter.td =================================================================== --- test/TableGen/GlobalISelEmitter.td +++ test/TableGen/GlobalISelEmitter.td @@ -7,6 +7,10 @@ def MyTargetISA : InstrInfo; def MyTarget : Target { let InstructionSet = MyTargetISA; } +let TargetPrefix = "mytarget" in { +def int_mytarget_nop : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; +} + def R0 : Register<"r0"> { let Namespace = "MyTarget"; } def GPR32 : RegisterClass<"MyTarget", [i32], 32, (add R0)>; def GPR32Op : RegisterOperand; @@ -123,6 +127,37 @@ def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), [(set GPR32:$dst, (add GPR32:$src1, GPR32:$src2))]>; +//===- Test a simple pattern with an intrinsic. ---------------------------===// +// + +// 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_INTRINSIC) && +// 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 */ (isOperandImmEqual(MI0.getOperand(1), 2952, MRI)))) && +// CHECK-NEXT: ((/* src1 */ (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: // (intrinsic_wo_chain:i32 2952:iPTR, GPR32:i32:$src1) => (MOV:i32 GPR32:i32:$src1) +// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MOV)); +// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); +// CHECK-NEXT: MIB.add(MI0.getOperand(2)/*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; } + +def MOV : I<(outs GPR32:$dst), (ins GPR32:$src1), + [(set GPR32:$dst, (int_mytarget_nop GPR32:$src1))]>; + //===- Test a nested instruction match. -----------------------------------===// // CHECK-LABEL: if ([&]() { Index: utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- utils/TableGen/GlobalISelEmitter.cpp +++ utils/TableGen/GlobalISelEmitter.cpp @@ -1349,9 +1349,19 @@ } auto OpTyOrNone = MVTToLLT(ChildTypes.front().getConcrete()); - if (!OpTyOrNone) - return failedImport("Src operand has an unsupported type"); - OM.addPredicate(*OpTyOrNone); + // Check for intrinsics before the type check since they are not a known type. + if (!OpTyOrNone.hasValue() && SrcChild->isLeaf()) { + Init *SrcChildInit = SrcChild->getLeafValue(); + if (IntInit *SrcChildIntInit = dyn_cast(SrcChildInit)) { + OM.addPredicate(SrcChildIntInit->getValue()); + return Error::success(); + } else + return failedImport("Src operand has an unsupported type (" + + to_string(*SrcChild) + ")"); + } else if (OpTyOrNone) + OM.addPredicate(*OpTyOrNone); + else + return failedImport("Src operand has an unsupported type (" + to_string(*SrcChild) + ")"); // Check for nested instructions. if (!SrcChild->isLeaf()) {