diff --git a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h --- a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -132,7 +132,7 @@ /// - InsnID - Instruction ID /// - The predicate to test GIM_CheckI64ImmPredicate, - /// Check an immediate predicate on the specified instruction via an APInt. + /// Check an immediate predicate on the specified operand /// - InsnID - Instruction ID /// - The predicate to test GIM_CheckAPIntImmPredicate, @@ -140,6 +140,11 @@ /// - InsnID - Instruction ID /// - The predicate to test GIM_CheckAPFloatImmPredicate, + /// Check an immediate predicate on the specified instruction + /// - InsnID - Instruction ID + /// - OpIdx - Operand index + /// - The predicate to test + GIM_CheckImmOperandPredicate, /// Check a memory operation has the specified atomic ordering. /// - InsnID - Instruction ID /// - Ordering - The AtomicOrdering value diff --git a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h --- a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h @@ -263,22 +263,27 @@ } break; } - case GIM_CheckI64ImmPredicate: { + case GIM_CheckI64ImmPredicate: + case GIM_CheckImmOperandPredicate: { int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatcherOpcode == GIM_CheckImmOperandPredicate + ? MatchTable[CurrentIdx++] + : 1; int64_t Predicate = MatchTable[CurrentIdx++]; DEBUG_WITH_TYPE(TgtInstructionSelector::getName(), - dbgs() - << CurrentIdx << ": GIM_CheckI64ImmPredicate(MIs[" - << InsnID << "], Predicate=" << Predicate << ")\n"); + dbgs() << CurrentIdx << ": GIM_CheckImmPredicate(MIs[" + << InsnID << "]->getOperand(" << OpIdx + << "), Predicate=" << Predicate << ")\n"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); - assert(State.MIs[InsnID]->getOpcode() == TargetOpcode::G_CONSTANT && - "Expected G_CONSTANT"); + assert((State.MIs[InsnID]->getOpcode() == TargetOpcode::G_CONSTANT || + State.MIs[InsnID]->getOperand(OpIdx).isImm()) && + "Expected G_CONSTANT or immediate operand"); assert(Predicate > GIPFP_I64_Invalid && "Expected a valid predicate"); int64_t Value = 0; - if (State.MIs[InsnID]->getOperand(1).isCImm()) - Value = State.MIs[InsnID]->getOperand(1).getCImm()->getSExtValue(); - else if (State.MIs[InsnID]->getOperand(1).isImm()) - Value = State.MIs[InsnID]->getOperand(1).getImm(); + if (State.MIs[InsnID]->getOperand(OpIdx).isCImm()) + Value = State.MIs[InsnID]->getOperand(OpIdx).getCImm()->getSExtValue(); + else if (State.MIs[InsnID]->getOperand(OpIdx).isImm()) + Value = State.MIs[InsnID]->getOperand(OpIdx).getImm(); else llvm_unreachable("Expected Imm or CImm operand"); diff --git a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td --- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td +++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td @@ -50,6 +50,7 @@ // G_INTTOPTR - SelectionDAG has no equivalent. // G_PTRTOINT - SelectionDAG has no equivalent. def : GINodeEquiv; +// timm must not be materialized and therefore has no GlobalISel equivalent def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; diff --git a/llvm/test/TableGen/immarg-predicated.td b/llvm/test/TableGen/immarg-predicated.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/immarg-predicated.td @@ -0,0 +1,22 @@ +// RUN: llvm-tblgen -gen-global-isel -optimize-match-table=false -I %p/Common -I %p/../../include %s -o - < %s | FileCheck -check-prefix=GISEL %s + +include "llvm/Target/Target.td" +include "GlobalISelEmitterCommon.td" + +let TargetPrefix = "mytarget" in { +def int_mytarget_sleep0 : Intrinsic<[], [llvm_i32_ty], [ImmArg>]>; +} + +// GISEL: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, +// GISEL-NEXT: // MIs[0] Operand 0 +// GISEL-NEXT: GIM_CheckIntrinsicID, /*MI*/0, /*Op*/0, Intrinsic::mytarget_sleep0, +// GISEL-NEXT: // MIs[0] src +// GISEL-NEXT: GIM_CheckIsImm, /*MI*/0, /*Op*/1, +// GISEL-NEXT: GIM_CheckImmOperandPredicate, /*MI*/0, /*MO*/1, /*Predicate*/GIPFP_I64_Predicate_tuimm9, +// GISEL-NEXT: // (intrinsic_void {{[0-9]+}}:{ *:[iPTR] }, (timm:{ *:[i32] })<>:$src) => (SLEEP0 (timm:{ *:[i32] }):$src) +// GISEL-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::SLEEP0, +// GISEL-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src +def tuimm9 : TImmLeaf(Imm); }]>; +def SLEEP0 : I<(outs), (ins i32imm:$src), + [(int_mytarget_sleep0 tuimm9:$src)] +>; diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -90,7 +90,7 @@ } /// Get the opcode used to check this predicate. -std::string getMatchOpcodeForPredicate(const TreePredicateFn &Predicate) { +std::string getMatchOpcodeForImmPredicate(const TreePredicateFn &Predicate) { return "GIM_Check" + Predicate.getImmTypeIdentifier().str() + "ImmPredicate"; } @@ -1562,6 +1562,40 @@ } }; +/// Generates code to check that this operand is an immediate whose value meets +/// an immediate predicate. +class OperandImmPredicateMatcher : public OperandPredicateMatcher { +protected: + TreePredicateFn Predicate; + +public: + OperandImmPredicateMatcher(unsigned InsnVarID, unsigned OpIdx, + const TreePredicateFn &Predicate) + : OperandPredicateMatcher(IPM_ImmPredicate, InsnVarID, OpIdx), + Predicate(Predicate) {} + + bool isIdentical(const PredicateMatcher &B) const override { + return OperandPredicateMatcher::isIdentical(B) && + Predicate.getOrigPatFragRecord() == + cast(&B) + ->Predicate.getOrigPatFragRecord(); + } + + static bool classof(const PredicateMatcher *P) { + return P->getKind() == IPM_ImmPredicate; + } + + void emitPredicateOpcodes(MatchTable &Table, + RuleMatcher &Rule) const override { + Table << MatchTable::Opcode("GIM_CheckImmOperandPredicate") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("MO") << MatchTable::IntValue(OpIdx) + << MatchTable::Comment("Predicate") + << MatchTable::NamedValue(getEnumNameForPredicate(Predicate)) + << MatchTable::LineBreak; + } +}; + /// Generates code to check that a set of predicates match for a particular /// operand. class OperandMatcher : public PredicateListMatcher { @@ -1924,7 +1958,7 @@ void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { - Table << MatchTable::Opcode(getMatchOpcodeForPredicate(Predicate)) + Table << MatchTable::Opcode(getMatchOpcodeForImmPredicate(Predicate)) << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Predicate") << MatchTable::NamedValue(getEnumNameForPredicate(Predicate)) @@ -4153,6 +4187,17 @@ } if (SrcChild->getOperator()->getName() == "timm") { OM.addPredicate(); + + // Add predicates, if any + for (const TreePredicateCall &Call : SrcChild->getPredicateCalls()) { + const TreePredicateFn &Predicate = Call.Fn; + + // Only handle immediate patterns for now + if (Predicate.isImmediatePattern()) { + OM.addPredicate(Predicate); + } + } + return Error::success(); } }