[Mlir-commits] [mlir] 31aaf4a - [mlir][OpenACC] Avoid per-recipe module walks in ACCImplicitDeclare (#220478)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Sep 2 10:06:54 PDT 2026


Author: Valentin Clement (バレンタイン クレメン)
Date: 2026-09-02T10:06:48-07:00
New Revision: 31aaf4adb4dae834e0520144548203ecf288272c

URL: https://github.com/llvm/llvm-project/commit/31aaf4adb4dae834e0520144548203ecf288272c
DIFF: https://github.com/llvm/llvm-project/commit/31aaf4adb4dae834e0520144548203ecf288272c.diff

LOG: [mlir][OpenACC] Avoid per-recipe module walks in ACCImplicitDeclare (#220478)

ACCImplicitDeclare skips unused private/firstprivate/reduction recipes
when collecting globals for implicit declare. Each skip used
getSymbolUses on the whole module, so the check was O(recipes × IR
size). Recipes are generated per type, so large modules paid for many
full scans.

Collect remaining symbol uses once and look recipes up in that set,
ignoring a recipe that only refers to its own symbol. Keep the old scan
as a fallback when getSymbolUses cannot resolve the module.

This is a ~40% gain in large TU.

Added: 
    

Modified: 
    mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitDeclare.cpp

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitDeclare.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitDeclare.cpp
index 28b8e064d7768..88ff5da990377 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitDeclare.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitDeclare.cpp
@@ -185,6 +185,7 @@
 #include "mlir/IR/Operation.h"
 #include "mlir/IR/Value.h"
 #include "mlir/Interfaces/FunctionInterfaces.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/TypeSwitch.h"
 
@@ -244,12 +245,50 @@ bool isValidForAccDeclare(Operation *globalOp) {
   return !isa<FunctionOpInterface>(globalOp);
 }
 
+/// Collect remaining symbol uses with a single walk. Asking whether each
+/// recipe is referenced via getSymbolUses walks the whole module again, and
+/// recipes are generated per type, so there can be many of them. A recipe
+/// referring only to its own symbol is not a "relevant" use (it does not
+/// mean the recipe is attached to a compute construct).
+static std::optional<llvm::DenseSet<StringAttr>>
+collectUsedSymbolsExcludingRecipeSelfUses(ModuleOp mod) {
+  // The module region, not the module op, is the symbol table scope: asking
+  // for the uses on the op itself would not walk into the body.
+  std::optional<SymbolTable::UseRange> uses =
+      SymbolTable::getSymbolUses(&mod.getBodyRegion());
+  if (!uses)
+    return std::nullopt;
+
+  llvm::DenseSet<StringAttr> usedSymbols;
+  auto isRecipeSelfUse = [](Operation *user, StringAttr name) {
+    if (auto recipe = dyn_cast<acc::PrivateRecipeOp>(user))
+      return recipe.getNameAttr() == name;
+    if (auto recipe = dyn_cast<acc::FirstprivateRecipeOp>(user))
+      return recipe.getNameAttr() == name;
+    if (auto recipe = dyn_cast<acc::ReductionRecipeOp>(user))
+      return recipe.getNameAttr() == name;
+    return false;
+  };
+  for (const SymbolTable::SymbolUse &use : *uses) {
+    StringAttr name = use.getSymbolRef().getLeafReference();
+    if (!isRecipeSelfUse(use.getUser(), name))
+      usedSymbols.insert(name);
+  }
+  return usedSymbols;
+}
+
 /// Checks whether a recipe operation has meaningful use of its symbol that
 /// justifies processing its regions for global references. Returns false if:
 /// 1. The recipe has no symbol uses at all, or
 /// 2. The only symbol use is the recipe's own symbol definition
 template <typename RecipeOpT>
-static bool hasRelevantRecipeUse(RecipeOpT &recipeOp, ModuleOp &mod) {
+static bool hasRelevantRecipeUse(
+    RecipeOpT &recipeOp, ModuleOp &mod,
+    const std::optional<llvm::DenseSet<StringAttr>> &usedSymbols) {
+  auto recipeName = recipeOp.getNameAttr();
+  if (usedSymbols)
+    return usedSymbols->contains(recipeName);
+
   std::optional<SymbolTable::UseRange> symbolUses = recipeOp.getSymbolUses(mod);
 
   // No recipe symbol uses.
@@ -366,6 +405,8 @@ class ACCImplicitDeclare
     // attribute.
     SymbolTable symTab(mod);
     GlobalOpSetT globalsToAccDeclare;
+    std::optional<llvm::DenseSet<StringAttr>> usedSymbols =
+        collectUsedSymbolsExcludingRecipeSelfUses(mod);
     mod.walk([&](Operation *op) {
       TypeSwitch<Operation *, void>(op)
           .Case<ACC_COMPUTE_CONSTRUCT_OPS, acc::ComputeRegionOp>(
@@ -388,7 +429,7 @@ class ACCImplicitDeclare
                                                accSupport, symTab);
           })
           .Case([&](acc::PrivateRecipeOp privateRecipe) {
-            if (hasRelevantRecipeUse(privateRecipe, mod)) {
+            if (hasRelevantRecipeUse(privateRecipe, mod, usedSymbols)) {
               collectGlobalsFromDeviceRegion(privateRecipe.getInitRegion(),
                                              globalsToAccDeclare, accSupport,
                                              symTab);
@@ -398,7 +439,7 @@ class ACCImplicitDeclare
             }
           })
           .Case([&](acc::FirstprivateRecipeOp firstprivateRecipe) {
-            if (hasRelevantRecipeUse(firstprivateRecipe, mod)) {
+            if (hasRelevantRecipeUse(firstprivateRecipe, mod, usedSymbols)) {
               collectGlobalsFromDeviceRegion(firstprivateRecipe.getInitRegion(),
                                              globalsToAccDeclare, accSupport,
                                              symTab);
@@ -411,7 +452,7 @@ class ACCImplicitDeclare
             }
           })
           .Case([&](acc::ReductionRecipeOp reductionRecipe) {
-            if (hasRelevantRecipeUse(reductionRecipe, mod)) {
+            if (hasRelevantRecipeUse(reductionRecipe, mod, usedSymbols)) {
               collectGlobalsFromDeviceRegion(reductionRecipe.getInitRegion(),
                                              globalsToAccDeclare, accSupport,
                                              symTab);


        


More information about the Mlir-commits mailing list