diff --git a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h index e599a1b179ec..4264a866b6c0 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -282,10 +282,6 @@ enum { /// Provides the logic to select generic machine instructions. class InstructionSelector { public: - using I64ImmediatePredicateFn = bool (*)(int64_t); - using APIntImmediatePredicateFn = bool (*)(const APInt &); - using APFloatImmediatePredicateFn = bool (*)(const APFloat &); - virtual ~InstructionSelector() = default; /// Select the (possibly generic) instruction \p I to only use target-specific @@ -319,9 +315,6 @@ public: struct MatcherInfoTy { const LLT *TypeObjects; const PredicateBitset *FeatureBitsets; - const I64ImmediatePredicateFn *I64ImmPredicateFns; - const APIntImmediatePredicateFn *APIntImmPredicateFns; - const APFloatImmediatePredicateFn *APFloatImmPredicateFns; const ComplexMatcherMemFn *ComplexPredicates; }; @@ -340,6 +333,16 @@ protected: const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures, CodeGenCoverage &CoverageInfo) const; + virtual bool testImmPredicate_I64(unsigned, int64_t) const { + llvm_unreachable("Subclasses must override this to use tablegen"); + } + virtual bool testImmPredicate_APInt(unsigned, const APInt &) const { + llvm_unreachable("Subclasses must override this to use tablegen"); + } + virtual bool testImmPredicate_APFloat(unsigned, const APFloat &) const { + llvm_unreachable("Subclasses must override this to use tablegen"); + } + /// Constrain a register operand of an instruction \p I to a specified /// register class. This could involve inserting COPYs before (for uses) or /// after (for defs) and may replace the operand of \p I. diff --git a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h index ac2c055ab145..bf834cf8f5e3 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h @@ -181,7 +181,7 @@ bool InstructionSelector::executeMatchTable( else llvm_unreachable("Expected Imm or CImm operand"); - if (!MatcherInfo.I64ImmPredicateFns[Predicate](Value)) + if (!testImmPredicate_I64(Predicate, Value)) if (handleReject() == RejectAndGiveUp) return false; break; @@ -202,7 +202,7 @@ bool InstructionSelector::executeMatchTable( else llvm_unreachable("Expected Imm or CImm operand"); - if (!MatcherInfo.APIntImmPredicateFns[Predicate](Value)) + if (!testImmPredicate_APInt(Predicate, Value)) if (handleReject() == RejectAndGiveUp) return false; break; @@ -221,7 +221,7 @@ bool InstructionSelector::executeMatchTable( assert(Predicate > GIPFP_APFloat_Invalid && "Expected a valid predicate"); APFloat Value = State.MIs[InsnID]->getOperand(1).getFPImm()->getValueAPF(); - if (!MatcherInfo.APFloatImmPredicateFns[Predicate](Value)) + if (!testImmPredicate_APFloat(Predicate, Value)) if (handleReject() == RejectAndGiveUp) return false; break; diff --git a/llvm/test/TableGen/GlobalISelEmitter.td b/llvm/test/TableGen/GlobalISelEmitter.td index f9fe51f84380..bc0b509622c4 100644 --- a/llvm/test/TableGen/GlobalISelEmitter.td +++ b/llvm/test/TableGen/GlobalISelEmitter.td @@ -63,11 +63,14 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; } // CHECK-NEXT: typedef ComplexRendererFns(MyTargetInstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const; // CHECK-NEXT: const MatcherInfoTy MatcherInfo; // CHECK-NEXT: static MyTargetInstructionSelector::ComplexMatcherMemFn ComplexPredicateFns[]; +// CHECK-NEXT: bool testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const override; +// CHECK-NEXT: bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) const override; +// CHECK-NEXT: bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat &Imm) const override; // CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL // CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_INIT // CHECK-NEXT: , State(2), -// CHECK-NEXT: MatcherInfo({TypeObjects, FeatureBitsets, I64ImmPredicateFns, APIntImmPredicateFns, APFloatImmPredicateFns, ComplexPredicateFns}) +// CHECK-NEXT: MatcherInfo({TypeObjects, FeatureBitsets, ComplexPredicateFns}) // CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT // CHECK-LABEL: enum SubtargetFeatureBits : uint8_t { @@ -127,31 +130,49 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; } // CHECK-NEXT: enum { // CHECK-NEXT: GIPFP_I64_Predicate_simm8 = GIPFP_I64_Invalid + 1, // CHECK-NEXT: }; -// CHECK-NEXT: static bool Predicate_simm8(int64_t Imm) { return isInt<8>(Imm); } -// CHECK-NEXT: static InstructionSelector::I64ImmediatePredicateFn I64ImmPredicateFns[] = { -// CHECK-NEXT: nullptr, -// CHECK-NEXT: Predicate_simm8, -// CHECK-NEXT: }; +// CHECK-NEXT: bool MyTargetInstructionSelector::testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const { +// CHECK-NEXT: switch (PredicateID) { +// CHECK-NEXT: case GIPFP_I64_Predicate_simm8: { +// CHECK-NEXT: return isInt<8>(Imm); +// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned"); +// CHECK-NEXT: return false; +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: llvm_unreachable("Unknown predicate"); +// CHECK-NEXT: return false; +// CHECK-NEXT: } // CHECK-LABEL: // PatFrag predicates. // CHECK-NEXT: enum { // CHECK-NEXT: GIPFP_APFloat_Predicate_fpimmz = GIPFP_APFloat_Invalid + 1, // CHECK-NEXT: }; -// CHECK-NEXT: static bool Predicate_fpimmz(const APFloat & Imm) { return Imm->isExactlyValue(0.0); } -// CHECK-NEXT: static InstructionSelector::APFloatImmediatePredicateFn APFloatImmPredicateFns[] = { -// CHECK-NEXT: nullptr, -// CHECK-NEXT: Predicate_fpimmz, -// CHECK-NEXT: }; +// CHECK-NEXT: bool MyTargetInstructionSelector::testImmPredicate_APFloat(unsigned PredicateID, const APFloat & Imm) const { +// CHECK-NEXT: switch (PredicateID) { +// CHECK-NEXT: case GIPFP_APFloat_Predicate_fpimmz: { +// CHECK-NEXT: return Imm->isExactlyValue(0.0); +// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned"); +// CHECK-NEXT: return false; +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: llvm_unreachable("Unknown predicate"); +// CHECK-NEXT: return false; +// CHECK-NEXT: } // CHECK-LABEL: // PatFrag predicates. // CHECK-NEXT: enum { // CHECK-NEXT: GIPFP_APInt_Predicate_simm9 = GIPFP_APInt_Invalid + 1, // CHECK-NEXT: }; -// CHECK-NEXT: static bool Predicate_simm9(const APInt & Imm) { return isInt<9>(Imm->getSExtValue()); } -// CHECK-NEXT: static InstructionSelector::APIntImmediatePredicateFn APIntImmPredicateFns[] = { -// CHECK-NEXT: nullptr, -// CHECK-NEXT: Predicate_simm9, -// CHECK-NEXT: }; +// CHECK-NEXT: bool MyTargetInstructionSelector::testImmPredicate_APInt(unsigned PredicateID, const APInt & Imm) const { +// CHECK-NEXT: switch (PredicateID) { +// CHECK-NEXT: case GIPFP_APInt_Predicate_simm9: { +// CHECK-NEXT: return isInt<9>(Imm->getSExtValue()); +// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned"); +// CHECK-NEXT: return false; +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: llvm_unreachable("Unknown predicate"); +// CHECK-NEXT: return false; +// CHECK-NEXT: } // CHECK-LABEL: MyTargetInstructionSelector::ComplexMatcherMemFn // CHECK-NEXT: MyTargetInstructionSelector::ComplexPredicateFns[] = { diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index 15400c072798..f4e99622747a 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -3550,16 +3550,21 @@ void GlobalISelEmitter::emitImmPredicates( OS << "};\n"; } - for (const auto *Record : MatchedRecords) - OS << "static bool Predicate_" << Record->getName() << "(" << Type - << " Imm) {" << Record->getValueAsString("ImmediateCode") << "}\n"; - - OS << "static InstructionSelector::" << TypeIdentifier - << "ImmediatePredicateFn " << TypeIdentifier << "ImmPredicateFns[] = {\n" - << " nullptr,\n"; - for (const auto *Record : MatchedRecords) - OS << " Predicate_" << Record->getName() << ",\n"; - OS << "};\n"; + OS << "bool " << Target.getName() << "InstructionSelector::testImmPredicate_" + << TypeIdentifier << "(unsigned PredicateID, " << Type << " Imm) const {\n" + << " switch (PredicateID) {\n"; + for (const auto *Record : MatchedRecords) { + OS << " case GIPFP_" << TypeIdentifier << "_Predicate_" + << Record->getName() << ": {\n" + << " " << Record->getValueAsString("ImmediateCode") << "\n" + << " llvm_unreachable(\"ImmediateCode should have returned\");\n" + << " return false;\n" + << " }\n"; + } + OS << " }\n" + << " llvm_unreachable(\"Unknown predicate\");\n" + << " return false;\n" + << "}\n"; } std::vector GlobalISelEmitter::optimizeRules( @@ -3673,12 +3678,17 @@ void GlobalISelEmitter::run(raw_ostream &OS) { "MatcherInfo;\n" << " static " << Target.getName() << "InstructionSelector::ComplexMatcherMemFn ComplexPredicateFns[];\n" + << "bool testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const " + "override;\n" + << "bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) " + "const override;\n" + << "bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat " + "&Imm) const override;\n" << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n"; OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n" << ", State(" << MaxTemporaries << "),\n" - << "MatcherInfo({TypeObjects, FeatureBitsets, I64ImmPredicateFns, " - "APIntImmPredicateFns, APFloatImmPredicateFns, ComplexPredicateFns})\n" + << "MatcherInfo({TypeObjects, FeatureBitsets, ComplexPredicateFns})\n" << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n"; OS << "#ifdef GET_GLOBALISEL_IMPL\n";