[llvm] 63390dc - [GlobalISel] Add Predicates to GICombineRule

Pierre van Houtryve via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 26 00:13:46 PDT 2022


Author: Pierre van Houtryve
Date: 2022-10-26T07:13:40Z
New Revision: 63390dccd86d42387abdd0adf11417ae1ec3d4ae

URL: https://github.com/llvm/llvm-project/commit/63390dccd86d42387abdd0adf11417ae1ec3d4ae
DIFF: https://github.com/llvm/llvm-project/commit/63390dccd86d42387abdd0adf11417ae1ec3d4ae.diff

LOG: [GlobalISel] Add Predicates to GICombineRule

Small QoL change to allow Predicates to be used in GICombineRule.
Currently only one combine in the AMDGPU backend makes use of it.

The implementation is pretty simple to get started but of course we can expand this later on and optimize predicate checking better if needed.

Reviewed By: dsanders

Differential Revision: https://reviews.llvm.org/D136681

Added: 
    

Modified: 
    llvm/include/llvm/Target/GlobalISel/Combine.td
    llvm/lib/Target/AMDGPU/AMDGPU.td
    llvm/lib/Target/AMDGPU/AMDGPUCombine.td
    llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp
    llvm/test/TableGen/GICombinerEmitter/match-tree.td
    llvm/utils/TableGen/GICombinerEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index d2fad89dd0a3b..9f29e9faf385b 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -61,6 +61,11 @@ class GICombineRule<dag defs, dag match, dag apply> : GICombine {
   /// 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<Predicate> 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
index d85b79fc78be7..9fd3eef9efaaa 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -1629,6 +1629,8 @@ def HasVOP3PInsts : Predicate<"Subtarget->hasVOP3PInsts()">,
 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
index 2415fdfecaae2..c11d4656db3f4 100644
--- 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
index 3dccb616b79c9..9c04df0b36837 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp
@@ -78,11 +78,6 @@ class AMDGPUPostLegalizerCombinerHelper {
 
 bool AMDGPUPostLegalizerCombinerHelper::matchFMinFMaxLegacy(
     MachineInstr &MI, FMinFMaxLegacyInfo &Info) {
-  // FIXME: Combines should have subtarget predicates, and we shouldn't need
-  // this here.
-  if (!MF.getSubtarget<GCNSubtarget>().hasFminFmaxLegacy())
-    return false;
-
   // FIXME: Type predicate on pattern
   if (MRI.getType(MI.getOperand(0).getReg()) != LLT::scalar(32))
     return false;
@@ -310,11 +305,17 @@ class AMDGPUPostLegalizerCombinerHelperState {
   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 @@ namespace {
 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 @@ bool AMDGPUPostLegalizerCombinerInfo::combine(GISelChangeObserver &Observer,
   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 @@ bool AMDGPUPostLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
   GISelKnownBits *KB = &getAnalysis<GISelKnownBitsAnalysis>().get(MF);
   MachineDominatorTree *MDT =
       IsOptNone ? nullptr : &getAnalysis<MachineDominatorTree>();
-  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
index b52d7ae754b65..e1f0f423e70c1 100644
--- a/llvm/test/TableGen/GICombinerEmitter/match-tree.td
+++ b/llvm/test/TableGen/GICombinerEmitter/match-tree.td
@@ -32,6 +32,9 @@ def SEXT : I<(outs GPR32:$dst), (ins GPR32:$src1), []>;
 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 @@ def Rule4 : GICombineRule<
   (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 @@ def MyCombinerHelper: GICombinerHelper<"GenMyCombinerHelper", [
 // 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 @@ def MyCombinerHelper: GICombinerHelper<"GenMyCombinerHelper", [
 // 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 @@ def MyCombinerHelper: GICombinerHelper<"GenMyCombinerHelper", [
 // 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 @@ def MyCombinerHelper: GICombinerHelper<"GenMyCombinerHelper", [
 // 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
index 52483af8aabe3..266186bf94527 100644
--- a/llvm/utils/TableGen/GICombinerEmitter.cpp
+++ b/llvm/utils/TableGen/GICombinerEmitter.cpp
@@ -764,6 +764,29 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS,
 
     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<DefInit>(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 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS,
          << Indent << "      return true;\n"
          << Indent << "  }()";
     }
-    OS << ") {\n" << Indent << "   ";
+    OS << Indent << "     ) {\n" << Indent << "   ";
 
     if (const StringInit *Code = dyn_cast<StringInit>(Applyer->getArg(0))) {
       OS << CodeExpander(Code->getAsUnquotedString(), Expansions,


        


More information about the llvm-commits mailing list