diff --git a/test/TableGen/predicate-patfags.td b/test/TableGen/predicate-patfags.td new file mode 100644 index 00000000000..a6a44ff6938 --- /dev/null +++ b/test/TableGen/predicate-patfags.td @@ -0,0 +1,63 @@ +// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common %s 2>&1 | FileCheck -check-prefix=SDAG %s +// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -I %p/Common %s 2>&1 | FileCheck -check-prefix=GISEL %s + +include "llvm/Target/Target.td" +include "GlobalISelEmitterCommon.td" + +// Test that a predicate works when there are multiple pattern trees +// in a PatFrags. + +def int_tgt_mul24 : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty]>; +def int_tgt_mul24_2 : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty]>; + +def TGTmul24_impl : SDNode<"TargetISD::MUL24", SDTIntBinOp>; + +def TGTmul24 : PatFrags<(ops node:$src0, node:$src1), + [(int_tgt_mul24 node:$src0, node:$src1), + (TGTmul24_impl node:$src0, node:$src1)]>; + + +def G_TGT_MUL24 : GenericInstruction { + let Namespace = "MyTarget"; + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + + +def : GINodeEquiv; + + +def TGTmul24_oneuse : PatFrag< + (ops node:$src0, node:$src1), + (TGTmul24 $src0, $src1), + [{ return N->hasOneUse(); }]> { + let GISelPredicateCode = [{ + return MRI->hasOneNonDBGUse(MI.getOperand(0).getReg()); + }]; +} + +// SDAG: OPC_CheckOpcode, TARGET_VAL(ISD::INTRINSIC_W_CHAIN), +// SDAG: OPC_CheckPredicate, 0, // Predicate_TGTmul24_oneuse + +// SDAG: OPC_CheckOpcode, TARGET_VAL(TargetISD::MUL24), +// SDAG: OPC_CheckPredicate, 0, // Predicate_TGTmul24_oneuse + +// GISEL: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, +// GISEL: GIM_CheckIntrinsicID, /*MI*/1, /*Op*/1, Intrinsic::tgt_mul24, +// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIPFP_MI_Predicate_TGTmul24_oneuse, + +// GISEL: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, +// GISEL: GIM_CheckIntrinsicID, /*MI*/1, /*Op*/1, Intrinsic::tgt_mul24, +// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIPFP_MI_Predicate_TGTmul24_oneuse, + +// GISEL: GIM_CheckOpcode, /*MI*/1, MyTarget::G_TGT_MUL24, +// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIPFP_MI_Predicate_TGTmul24_oneuse, + +// GISEL: GIM_CheckOpcode, /*MI*/1, MyTarget::G_TGT_MUL24, +// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIPFP_MI_Predicate_TGTmul24_oneuse, +def inst_mad24 : I< + (outs GPR32:$dst), + (ins GPR32:$src0, GPR32:$src1, GPR32:$src2), + [(set GPR32:$dst, (add (TGTmul24_oneuse i32:$src0, i32:$src1), i32:$src2))]>; diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index d01de3317ff..7e0ba98da94 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -1315,13 +1315,29 @@ std::string TreePredicateFn::getCodeToRunOnSDNode() const { // Handle arbitrary node predicates. assert(hasPredCode() && "Don't have any predicate code!"); + + // If this is using PatFrags, there are multiple trees to search. They should + // all have the same class. FIXME: Is there a way to find a common + // superclass? StringRef ClassName; - if (PatFragRec->getOnlyTree()->isLeaf()) - ClassName = "SDNode"; - else { - Record *Op = PatFragRec->getOnlyTree()->getOperator(); - ClassName = PatFragRec->getDAGPatterns().getSDNodeInfo(Op).getSDClassName(); + for (const auto &Tree : PatFragRec->getTrees()) { + StringRef TreeClassName; + if (Tree->isLeaf()) + TreeClassName = "SDNode"; + else { + Record *Op = Tree->getOperator(); + const SDNodeInfo &Info = PatFragRec->getDAGPatterns().getSDNodeInfo(Op); + TreeClassName = Info.getSDClassName(); + } + + if (ClassName.empty()) + ClassName = TreeClassName; + else if (ClassName != TreeClassName) { + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "PatFrags trees do not have consistent class"); + } } + std::string Result; if (ClassName == "SDNode") Result = " SDNode *N = Node;\n";