Skip to content

[GVN] Limit MemorySSA reaching-value block scans - #217945

Open
madhur13490 wants to merge 1 commit into
llvm:mainfrom
madhur13490:gvn-mssa-walk-cap
Open

[GVN] Limit MemorySSA reaching-value block scans#217945
madhur13490 wants to merge 1 commit into
llvm:mainfrom
madhur13490:gvn-mssa-walk-cap

Conversation

@madhur13490

@madhur13490 madhur13490 commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Cap expensive non-local MemorySSA queries at the same 200-block limit used by MemDep. On an internal workload, this closes the majority of the compile-time gap between the MemorySSA and MemDep GVN paths.
Runtime remains almost flat.

Cap expensive non-local MemorySSA queries at the same 200-block limit used by MemDep. On an internal workload, this closes the majority of the compile-time gap between the MemorySSA and MemDep GVN paths.
@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-llvm-transforms

Author: Madhur Amilkanthwar (madhur13490)

Changes

Cap expensive non-local MemorySSA queries at the same 200-block limit used by MemDep. On an internal workload, this closes the majority of the compile-time gap between the MemorySSA and MemDep GVN paths.
Runtime remains almost flat.


Full diff: https://github.com/llvm/llvm-project/pull/217945.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Scalar/GVN.cpp (+8)
  • (added) llvm/test/Transforms/GVN/mssa-reach-block-limit.ll (+47)
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 64fd14fcba1c5..ddd8e62f393ee 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -128,6 +128,11 @@ static cl::opt<uint32_t> MaxNumDeps(
     "gvn-max-num-deps", cl::Hidden, cl::init(100),
     cl::desc("Max number of dependences to attempt Load PRE (default = 100)"));
 
+static cl::opt<uint32_t> MaxNumReachingBlocks(
+    "gvn-max-num-reaching-blocks", cl::Hidden, cl::init(200),
+    cl::desc("Max number of blocks scanned per load in the MemorySSA "
+             "reaching-value analysis (default = 200)"));
+
 // This is based on IsValueFullyAvailableInBlockNumSpeculationsMax stat.
 static cl::opt<uint32_t> MaxBBSpeculations(
     "gvn-max-block-speculations", cl::Hidden, cl::init(600),
@@ -2665,6 +2670,9 @@ bool GVNPass::findReachingValuesForLoad(LoadInst *L,
   // Do a bottom-up DFS.
   auto Worklist = InitialWorklist;
   while (!Worklist.empty()) {
+    // Match MemDep's cutoff for expensive non-local queries.
+    if (Blocks.size() > MaxNumReachingBlocks)
+      return false;
     auto *BB = Worklist.pop_back_val();
     DependencyBlockInfo &Info = Blocks.find(BB)->second;
 
diff --git a/llvm/test/Transforms/GVN/mssa-reach-block-limit.ll b/llvm/test/Transforms/GVN/mssa-reach-block-limit.ll
new file mode 100644
index 0000000000000..13c6fb1202955
--- /dev/null
+++ b/llvm/test/Transforms/GVN/mssa-reach-block-limit.ll
@@ -0,0 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes='gvn<memoryssa>' -S %s | FileCheck %s --check-prefix=DEFAULT
+; RUN: opt -passes='gvn<memoryssa>' -gvn-max-num-reaching-blocks=1 -S %s \
+; RUN:   | FileCheck %s --check-prefix=LIMIT
+
+; The limit abandons expensive non-local queries without changing the IR.
+define i32 @load_from_predecessors(ptr %ptr, i1 %cond) {
+; DEFAULT-LABEL: @load_from_predecessors(
+; DEFAULT-NEXT:  entry:
+; DEFAULT-NEXT:    br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
+; DEFAULT:       left:
+; DEFAULT-NEXT:    store i32 1, ptr [[PTR:%.*]], align 4
+; DEFAULT-NEXT:    br label [[MERGE:%.*]]
+; DEFAULT:       right:
+; DEFAULT-NEXT:    store i32 1, ptr [[PTR]], align 4
+; DEFAULT-NEXT:    br label [[MERGE]]
+; DEFAULT:       merge:
+; DEFAULT-NEXT:    ret i32 1
+;
+; LIMIT-LABEL: @load_from_predecessors(
+; LIMIT-NEXT:  entry:
+; LIMIT-NEXT:    br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
+; LIMIT:       left:
+; LIMIT-NEXT:    store i32 1, ptr [[PTR:%.*]], align 4
+; LIMIT-NEXT:    br label [[MERGE:%.*]]
+; LIMIT:       right:
+; LIMIT-NEXT:    store i32 1, ptr [[PTR]], align 4
+; LIMIT-NEXT:    br label [[MERGE]]
+; LIMIT:       merge:
+; LIMIT-NEXT:    [[VALUE:%.*]] = load i32, ptr [[PTR]], align 4
+; LIMIT-NEXT:    ret i32 [[VALUE]]
+;
+entry:
+  br i1 %cond, label %left, label %right
+
+left:
+  store i32 1, ptr %ptr
+  br label %merge
+
+right:
+  store i32 1, ptr %ptr
+  br label %merge
+
+merge:
+  %value = load i32, ptr %ptr
+  ret i32 %value
+}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant