[llvm] [GVN] Enforce MemDep/MemorySSA mutual exclusion for cl::opt overrides (PR #217896)

Madhur Amilkanthwar via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 21 05:20:45 PDT 2026


https://github.com/madhur13490 created https://github.com/llvm/llvm-project/pull/217896

parseGVNOptions() already keeps the gvn<...> pass parameters mutually exclusive, but the -enable-gvn-{memdep,memoryssa} cl::opt overrides default independently. Two fixes for that path:

- Enabling MemorySSA now implies MemDep is off, so -enable-gvn-memoryssa=true on its own no longer trips the on-demand MemorySSA assertion.
- Explicitly enabling both is a contradiction and is now rejected with a diagnostic instead of resolving it arbitrarily.

>From 7b71befe95c76083e3e84d0245bc5cc4978979f1 Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Fri, 21 Aug 2026 05:06:52 -0700
Subject: [PATCH] [GVN] Enforce MemDep/MemorySSA mutual exclusion for cl::opt
 overrides

parseGVNOptions() already keeps the gvn<...> pass parameters mutually
exclusive, but the -enable-gvn-{memdep,memoryssa} cl::opt overrides
default independently. Two fixes for that path:

- Enabling MemorySSA now implies MemDep is off, so
  -enable-gvn-memoryssa=true on its own no longer trips the on-demand
  MemorySSA assertion.
- Explicitly enabling both is a contradiction and is now rejected with
  a diagnostic instead of resolving it arbitrarily.
---
 llvm/lib/Transforms/Scalar/GVN.cpp            | 15 +++++++++++++
 .../GVN/memoryssa-implies-no-memdep.ll        | 22 +++++++++++++++++++
 2 files changed, 37 insertions(+)
 create mode 100644 llvm/test/Transforms/GVN/memoryssa-implies-no-memdep.ll

diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 64fd14fcba1c5..96b6797605ec1 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -68,6 +68,7 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
@@ -869,6 +870,11 @@ bool GVNPass::isLoadPRESplitBackedgeEnabled() const {
 }
 
 bool GVNPass::isMemDepEnabled() const {
+  // MemDep and MemorySSA are mutually exclusive. parseGVNOptions() enforces
+  // this for pass parameters, but the -enable-gvn-{memdep,memoryssa} cl::opt
+  // overrides default independently, so honor MemorySSA winning here too.
+  if (isMemorySSAEnabled())
+    return Options.AllowMemDep.value_or(false);
   return Options.AllowMemDep.value_or(GVNEnableMemDep);
 }
 
@@ -3456,6 +3462,15 @@ bool GVNPass::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
                       const TargetLibraryInfo &RunTLI, AAResults &RunAA,
                       MemoryDependenceResults *RunMD, LoopInfo &LI,
                       OptimizationRemarkEmitter *RunORE, MemorySSA *MSSA) {
+  // MemDep and MemorySSA are mutually exclusive. isMemDepEnabled() silently
+  // lets MemorySSA win for the common single-flag case, but an explicit
+  // request for both via -enable-gvn-{memdep,memoryssa} is a contradiction we
+  // reject rather than resolve arbitrarily.
+  if (GVNEnableMemDep.getNumOccurrences() && GVNEnableMemDep &&
+      GVNEnableMemorySSA.getNumOccurrences() && GVNEnableMemorySSA)
+    report_fatal_error("GVN: -enable-gvn-memdep and -enable-gvn-memoryssa are "
+                       "mutually exclusive",
+                       /*gen_crash_diag=*/false);
   AC = &RunAC;
   DT = &RunDT;
   VN.setDomTree(DT);
diff --git a/llvm/test/Transforms/GVN/memoryssa-implies-no-memdep.ll b/llvm/test/Transforms/GVN/memoryssa-implies-no-memdep.ll
new file mode 100644
index 0000000000000..df7c6f40ec13c
--- /dev/null
+++ b/llvm/test/Transforms/GVN/memoryssa-implies-no-memdep.ll
@@ -0,0 +1,22 @@
+; MemDep and MemorySSA are mutually exclusive in GVN. Enabling MemorySSA via
+; the -enable-gvn-memoryssa cl::opt alone must imply MemDep is off; otherwise
+; GVN's on-demand MemorySSA path asserts. Regression test for that override
+; path (parseGVNOptions already covers the gvn<memoryssa> pass parameter).
+; RUN: opt -passes=gvn -enable-gvn-memoryssa=true -S < %s | FileCheck %s
+;
+; Explicitly requesting both engines is a contradiction and is rejected.
+; RUN: not opt -passes=gvn -enable-gvn-memdep=true -enable-gvn-memoryssa=true \
+; RUN:   -S < %s 2>&1 | FileCheck %s --check-prefix=CONFLICT
+; CONFLICT: -enable-gvn-memdep and -enable-gvn-memoryssa are mutually exclusive
+
+define i32 @redundant_load(ptr %p) {
+; CHECK-LABEL: @redundant_load(
+; CHECK:         %a = load i32, ptr %p
+; CHECK-NOT:     load i32
+; CHECK:         %c = add i32 %a, %a
+; CHECK:         ret i32 %c
+  %a = load i32, ptr %p
+  %b = load i32, ptr %p
+  %c = add i32 %a, %b
+  ret i32 %c
+}



More information about the llvm-commits mailing list