From 97ed1b6036074e66dd926b6720f087b9964a7286 Mon Sep 17 00:00:00 2001 From: Dominik Montada Date: Mon, 29 Mar 2021 15:21:46 +0200 Subject: [PATCH] [GISel] Teach TableGen to check predicates of immediate operands in patterns Reviewed By: dsanders Differential Revision: https://reviews.llvm.org/D91703 --- .../llvm/CodeGen/GlobalISel/InstructionSelector.h | 5 +++ .../CodeGen/GlobalISel/InstructionSelectorImpl.h | 25 ++++++----- .../llvm/Target/GlobalISel/SelectionDAGCompat.td | 1 + llvm/test/TableGen/immarg-predicated.td | 22 ++++++++++ llvm/utils/TableGen/GlobalISelEmitter.cpp | 49 +++++++++++++++++++++- 5 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 llvm/test/TableGen/immarg-predicated.td diff --git a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h index baa32d9..03f4f3b 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -140,6 +140,11 @@ enum { /// - 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 index 82e26b0..25c07f8 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h @@ -263,22 +263,27 @@ bool InstructionSelector::executeMatchTable( } 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]->getOperand(OpIdx).isImm() || + State.MIs[InsnID]->getOperand(OpIdx).isCImm()) && + "Expected 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 index 4c947b5..8a50524 100644 --- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td +++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td @@ -50,6 +50,7 @@ def : GINodeEquiv; // 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 index 0000000..16db4a8 --- /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 index a6bfad1..9a869de 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -90,7 +90,7 @@ std::string getEnumNameForPredicate(const TreePredicateFn &Predicate) { } /// 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 @@ public: } }; +/// 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 @@ public: 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)) @@ -4152,6 +4186,17 @@ Error GlobalISelEmitter::importChildMatcher( } 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(); } } -- 2.7.4