diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -61,6 +61,11 @@ /// combine rule. /// See GIApplyKind for details. dag Apply = apply; + + /// Defines the predicates that are checked before the match function + /// is called. Targets can use this to, for instance, check Subtarget + /// features. + list Predicates = []; } /// The operator at the root of a GICombineRule.Defs dag. diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.td b/llvm/lib/Target/AMDGPU/AMDGPU.td --- a/llvm/lib/Target/AMDGPU/AMDGPU.td +++ b/llvm/lib/Target/AMDGPU/AMDGPU.td @@ -1629,6 +1629,8 @@ def HasMinMaxDenormModes : Predicate<"Subtarget->supportsMinMaxDenormModes()">; def NotHasMinMaxDenormModes : Predicate<"!Subtarget->supportsMinMaxDenormModes()">; +def HasFminFmaxLegacy : Predicate<"Subtarget->hasFminFmaxLegacy()">; + def HasSDWA : Predicate<"Subtarget->hasSDWA()">, AssemblerPredicate<(all_of FeatureSDWA, FeatureVolcanicIslands)>; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCombine.td b/llvm/lib/Target/AMDGPU/AMDGPUCombine.td --- a/llvm/lib/Target/AMDGPU/AMDGPUCombine.td +++ b/llvm/lib/Target/AMDGPU/AMDGPUCombine.td @@ -9,10 +9,10 @@ include "llvm/Target/GlobalISel/Combine.td" // TODO: This really belongs after legalization after scalarization. -// TODO: GICombineRules should accept subtarget predicates def fmin_fmax_legacy_matchdata : GIDefMatchData<"AMDGPUPostLegalizerCombinerHelper::FMinFMaxLegacyInfo">; +let Predicates = [HasFminFmaxLegacy] in def fcmp_select_to_fmin_fmax_legacy : GICombineRule< (defs root:$select, fmin_fmax_legacy_matchdata:$matchinfo), (match (wip_match_opcode G_SELECT):$select, diff --git a/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp b/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp --- a/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp @@ -78,11 +78,6 @@ bool AMDGPUPostLegalizerCombinerHelper::matchFMinFMaxLegacy( MachineInstr &MI, FMinFMaxLegacyInfo &Info) { - // FIXME: Combines should have subtarget predicates, and we shouldn't need - // this here. - if (!MF.getSubtarget().hasFminFmaxLegacy()) - return false; - // FIXME: Type predicate on pattern if (MRI.getType(MI.getOperand(0).getReg()) != LLT::scalar(32)) return false; @@ -310,11 +305,17 @@ AMDGPUCombinerHelper &Helper; AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper; + // Note: pointer is necessary because Target Predicates use + // "Subtarget->" + const GCNSubtarget *Subtarget; + public: AMDGPUPostLegalizerCombinerHelperState( AMDGPUCombinerHelper &Helper, - AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper) - : Helper(Helper), PostLegalizerHelper(PostLegalizerHelper) {} + AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper, + const GCNSubtarget &Subtarget) + : Helper(Helper), PostLegalizerHelper(PostLegalizerHelper), + Subtarget(&Subtarget) {} }; #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS @@ -329,16 +330,18 @@ class AMDGPUPostLegalizerCombinerInfo final : public CombinerInfo { GISelKnownBits *KB; MachineDominatorTree *MDT; + const GCNSubtarget &Subtarget; public: AMDGPUGenPostLegalizerCombinerHelperRuleConfig GeneratedRuleCfg; - AMDGPUPostLegalizerCombinerInfo(bool EnableOpt, bool OptSize, bool MinSize, + AMDGPUPostLegalizerCombinerInfo(const GCNSubtarget &Subtarget, bool EnableOpt, + bool OptSize, bool MinSize, const AMDGPULegalizerInfo *LI, GISelKnownBits *KB, MachineDominatorTree *MDT) : CombinerInfo(/*AllowIllegalOps*/ false, /*ShouldLegalizeIllegal*/ true, /*LegalizerInfo*/ LI, EnableOpt, OptSize, MinSize), - KB(KB), MDT(MDT) { + KB(KB), MDT(MDT), Subtarget(Subtarget) { if (!GeneratedRuleCfg.parseCommandLineOption()) report_fatal_error("Invalid rule identifier"); } @@ -353,8 +356,8 @@ AMDGPUCombinerHelper Helper(Observer, B, /*IsPreLegalize*/ false, KB, MDT, LInfo); AMDGPUPostLegalizerCombinerHelper PostLegalizerHelper(B, Helper); - AMDGPUGenPostLegalizerCombinerHelper Generated(GeneratedRuleCfg, Helper, - PostLegalizerHelper); + AMDGPUGenPostLegalizerCombinerHelper Generated( + GeneratedRuleCfg, Helper, PostLegalizerHelper, Subtarget); if (Generated.tryCombineAll(Observer, MI, B)) return true; @@ -431,7 +434,7 @@ GISelKnownBits *KB = &getAnalysis().get(MF); MachineDominatorTree *MDT = IsOptNone ? nullptr : &getAnalysis(); - AMDGPUPostLegalizerCombinerInfo PCInfo(EnableOpt, F.hasOptSize(), + AMDGPUPostLegalizerCombinerInfo PCInfo(ST, EnableOpt, F.hasOptSize(), F.hasMinSize(), LI, KB, MDT); Combiner C(PCInfo, TPC); return C.combineMachineInstrs(MF, /*CSEInfo*/ nullptr); diff --git a/llvm/test/TableGen/GICombinerEmitter/match-tree.td b/llvm/test/TableGen/GICombinerEmitter/match-tree.td --- a/llvm/test/TableGen/GICombinerEmitter/match-tree.td +++ b/llvm/test/TableGen/GICombinerEmitter/match-tree.td @@ -32,6 +32,9 @@ def ZEXT : I<(outs GPR32:$dst), (ins GPR32:$src1), []>; def ICMP : I<(outs GPR32:$dst), (ins GPR32:$tst, GPR32:$src1, GPR32:$src2), []>; +def HasFoo : Predicate<"Subtarget->hasFoo()">; +def HasAnswerToEverything : Predicate<"Subtarget->getAnswerToUniverse() == 42 && Subtarget->getAnswerToLife() == 42">; + def Rule0 : GICombineRule< (defs root:$d), (match (MUL $t, $s1, $s2), @@ -60,11 +63,13 @@ (match (ADD $d, $s1, $s2)), (apply [{ APPLY }])>; +let Predicates = [HasFoo] in def Rule5 : GICombineRule< (defs root:$d), (match (SUB $d, $s1, $s2)), (apply [{ APPLY }])>; +let Predicates = [HasFoo, HasAnswerToEverything] in def Rule6 : GICombineRule< (defs root:$d), (match (SEXT $t, $s1), @@ -241,7 +246,7 @@ // CODE-NEXT: llvm_unreachable("Combine rule elision was incorrect"); // CODE-NEXT: return false; // CODE-NEXT: } - + // Check that the other rule involving SUB (Rule5) is run otherwise. // CODE-NEXT: if (Partition == 1 /* * or nullptr */) { @@ -249,6 +254,10 @@ // CODE-NEXT: // Rule: Rule5 // CODE-NEXT: if (!RuleConfig->isRuleDisabled(5)) { // CODE-NEXT: if (1 +// CODE-NEXT: && ( +// CODE-NEXT: // Predicate: HasFoo +// CODE-NEXT: Subtarget->hasFoo() +// CODE-NEXT: ) // CODE-NEXT:) { // CODE-NEXT: APPLY // CODE-NEXT: return true; @@ -266,7 +275,11 @@ // CODE-NEXT: // Rule: Rule5 // CODE-NEXT: if (!RuleConfig->isRuleDisabled(5)) { // CODE-NEXT: if (1 -// CODE-NEXT:) { +// CODE-NEXT: && ( +// CODE-NEXT: // Predicate: HasFoo +// CODE-NEXT: Subtarget->hasFoo() +// CODE-NEXT: ) +// CODE-NEXT: ) { // CODE-NEXT: APPLY // CODE-NEXT: return true; // CODE-NEXT: } @@ -276,3 +289,23 @@ // CODE-NEXT: } // CODE-NEXT: } + +// Check multiple predicates are correctly emitted + +// CODE: // Leaf name: Rule6 +// CODE-NEXT: // Rule: Rule6 +// CODE-NEXT: if (!RuleConfig->isRuleDisabled(6)) { +// CODE-NEXT: if (1 +// CODE-NEXT: && ( +// CODE-NEXT: // Predicate: HasFoo +// CODE-NEXT: Subtarget->hasFoo() +// CODE-NEXT: ) +// CODE-NEXT: && ( +// CODE-NEXT: // Predicate: HasAnswerToEverything +// CODE-NEXT: Subtarget->getAnswerToUniverse() == 42 && Subtarget->getAnswerToLife() == 42 +// CODE-NEXT: ) +// CODE-NEXT: ) { +// CODE-NEXT: APPLY +// CODE-NEXT: return true; +// CODE-NEXT: } +// CODE-NEXT: } diff --git a/llvm/utils/TableGen/GICombinerEmitter.cpp b/llvm/utils/TableGen/GICombinerEmitter.cpp --- a/llvm/utils/TableGen/GICombinerEmitter.cpp +++ b/llvm/utils/TableGen/GICombinerEmitter.cpp @@ -764,6 +764,29 @@ OS << Indent << " if (1\n"; + // Emit code for C++ Predicates. + if (RuleDef.getValue("Predicates")) { + ListInit *Preds = RuleDef.getValueAsListInit("Predicates"); + for (Init *I : Preds->getValues()) { + if (DefInit *Pred = dyn_cast(I)) { + Record *Def = Pred->getDef(); + if (!Def->isSubClassOf("Predicate")) { + PrintError(Def->getLoc(), "Unknown 'Predicate' Type"); + return; + } + + StringRef CondString = Def->getValueAsString("CondString"); + if (CondString.empty()) + continue; + + OS << Indent << " && (\n" + << Indent << " // Predicate: " << Def->getName() << "\n" + << Indent << " " << CondString << "\n" + << Indent << " )\n"; + } + } + } + // Attempt to emit code for any untested predicates left over. Note that // isFullyTested() will remain false even if we succeed here and therefore // combine rule elision will not be performed. This is because we do not @@ -804,7 +827,7 @@ << Indent << " return true;\n" << Indent << " }()"; } - OS << ") {\n" << Indent << " "; + OS << Indent << " ) {\n" << Indent << " "; if (const StringInit *Code = dyn_cast(Applyer->getArg(0))) { OS << CodeExpander(Code->getAsUnquotedString(), Expansions,