[llvm] 48c59d1 - [DSE] Introduce tests for PR181709 (NFC) (#190454)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 4 03:23:23 PDT 2026
Author: Antonio Frighetto
Date: 2026-04-04T12:23:17+02:00
New Revision: 48c59d1a9781107b219d0afee91f64a51758856c
URL: https://github.com/llvm/llvm-project/commit/48c59d1a9781107b219d0afee91f64a51758856c
DIFF: https://github.com/llvm/llvm-project/commit/48c59d1a9781107b219d0afee91f64a51758856c.diff
LOG: [DSE] Introduce tests for PR181709 (NFC) (#190454)
Added:
llvm/test/Transforms/DeadStoreElimination/dead-stores-via-dom-conditions.ll
Modified:
Removed:
################################################################################
diff --git a/llvm/test/Transforms/DeadStoreElimination/dead-stores-via-dom-conditions.ll b/llvm/test/Transforms/DeadStoreElimination/dead-stores-via-dom-conditions.ll
new file mode 100644
index 0000000000000..c1f07c00d648b
--- /dev/null
+++ b/llvm/test/Transforms/DeadStoreElimination/dead-stores-via-dom-conditions.ll
@@ -0,0 +1,283 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -aa-pipeline=basic-aa -passes='dse,verify<memoryssa>' -S | FileCheck %s
+
+; There exists a dominating condition in the entry block, not the immediate
+; dominator for the store, the edge entry->if.eq dominates the store, no
+; clobber in between, the store is redundant.
+define void @remove_tautological_store_via_dom_condition(ptr %x, i1 %c) {
+; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0
+; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[END:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: br i1 [[C]], label %[[IF_EQ:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_EQ]]:
+; CHECK-NEXT: br label %[[JOIN:.*]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: br label %[[JOIN]]
+; CHECK: [[JOIN]]:
+; CHECK-NEXT: br label %[[INNER:.*]]
+; CHECK: [[INNER]]:
+; CHECK-NEXT: store i32 0, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %val = load i32, ptr %x, align 4
+ %cmp = icmp eq i32 %val, 0
+ br i1 %cmp, label %then, label %end
+
+then:
+ br i1 %c, label %if.eq, label %if.else
+
+if.eq:
+ br label %join
+
+if.else:
+ br label %join
+
+join:
+ br label %inner
+
+inner:
+ store i32 0, ptr %x, align 4
+ br label %end
+
+end:
+ ret void
+}
+
+; There exists a dominating condition in block then, the edge then->if.eq immediately
+; dominates the first store, but does not dominate the second one, no clobber
+; in between, the first store is redundant.
+define void @remove_tautological_store_via_dom_condition_2(ptr %x, i1 %c) {
+; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition_2(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[C]], label %[[THEN:.*]], label %[[END:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0
+; CHECK-NEXT: br i1 [[CMP]], label %[[IF_EQ:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_EQ]]:
+; CHECK-NEXT: br label %[[JOIN:.*]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: br label %[[JOIN]]
+; CHECK: [[JOIN]]:
+; CHECK-NEXT: store i32 0, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[INNER:.*]]
+; CHECK: [[INNER]]:
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ br i1 %c, label %then, label %end
+
+then:
+ %val = load i32, ptr %x, align 4
+ %cmp = icmp eq i32 %val, 0
+ br i1 %cmp, label %if.eq, label %if.else
+
+if.eq:
+ store i32 0, ptr %x, align 4
+ br label %join
+
+if.else:
+ br label %join
+
+join:
+ store i32 0, ptr %x, align 4
+ br label %inner
+
+inner:
+ br label %end
+
+end:
+ ret void
+}
+
+; There exist two dominating conditions in the CFG, the edges entry->if.eq and
+; then->if.eq dominate the stores, no clobber in between, the stores are redundant.
+define void @remove_tautological_store_via_dom_condition_3(ptr %x, ptr %y, i1 %c) {
+; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition_3(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0
+; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[END:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: [[VAL_2:%.*]] = load i32, ptr [[Y]], align 4
+; CHECK-NEXT: [[CMP_2:%.*]] = icmp eq i32 [[VAL_2]], 0
+; CHECK-NEXT: br i1 [[CMP_2]], label %[[IF_EQ:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_EQ]]:
+; CHECK-NEXT: store i32 0, ptr [[X]], align 4
+; CHECK-NEXT: store i32 0, ptr [[Y]], align 4
+; CHECK-NEXT: br label %[[JOIN:.*]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: br label %[[JOIN]]
+; CHECK: [[JOIN]]:
+; CHECK-NEXT: br label %[[INNER:.*]]
+; CHECK: [[INNER]]:
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %val = load i32, ptr %x, align 4
+ %cmp = icmp eq i32 %val, 0
+ br i1 %cmp, label %then, label %end
+
+then:
+ %val.2 = load i32, ptr %y, align 4
+ %cmp.2 = icmp eq i32 %val.2, 0
+ br i1 %cmp.2, label %if.eq, label %if.else
+
+if.eq:
+ store i32 0, ptr %x, align 4
+ store i32 0, ptr %y, align 4
+ br label %join
+
+if.else:
+ br label %join
+
+join:
+ br label %inner
+
+inner:
+ br label %end
+
+end:
+ ret void
+}
+
+; Negative tests.
+
+; There exists a dominating condition in the entry block, however,
+; the pointer whose value is implied is clobbered in between.
+define void @remove_tautological_store_via_dom_condition_clobber_between(ptr %x, i1 %c) {
+; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition_clobber_between(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0
+; CHECK-NEXT: br i1 [[CMP]], label %[[IF_EQ:.*]], label %[[END:.*]]
+; CHECK: [[IF_EQ]]:
+; CHECK-NEXT: br label %[[NEXT:.*]]
+; CHECK: [[NEXT]]:
+; CHECK-NEXT: call void @opaque(ptr [[X]])
+; CHECK-NEXT: br i1 [[C]], label %[[INNER:.*]], label %[[END]]
+; CHECK: [[INNER]]:
+; CHECK-NEXT: store i32 0, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %val = load i32, ptr %x, align 4
+ %cmp = icmp eq i32 %val, 0
+ br i1 %cmp, label %if.eq, label %end
+
+if.eq:
+ br label %next
+
+next:
+ call void @opaque(ptr %x)
+ br i1 %c, label %inner, label %end
+
+inner:
+ store i32 0, ptr %x, align 4
+ br label %end
+
+end:
+ ret void
+}
+
+; Volatile stores should not be eliminated.
+define void @remove_tautological_store_via_dom_condition_volatile_store(ptr %x, i1 %c) {
+; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition_volatile_store(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0
+; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[END:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: br i1 [[C]], label %[[IF_EQ:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_EQ]]:
+; CHECK-NEXT: br label %[[JOIN:.*]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: br label %[[JOIN]]
+; CHECK: [[JOIN]]:
+; CHECK-NEXT: store volatile i32 0, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %val = load i32, ptr %x, align 4
+ %cmp = icmp eq i32 %val, 0
+ br i1 %cmp, label %then, label %end
+
+then:
+ br i1 %c, label %if.eq, label %if.else
+
+if.eq:
+ br label %join
+
+if.else:
+ br label %join
+
+join:
+ store volatile i32 0, ptr %x, align 4
+ br label %end
+
+end:
+ ret void
+}
+
+; Atomic stores should not be eliminated.
+define void @remove_tautological_store_via_dom_condition_atomic_store(ptr %x, i1 %c) {
+; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition_atomic_store(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0
+; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[END:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: br i1 [[C]], label %[[IF_EQ:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_EQ]]:
+; CHECK-NEXT: br label %[[JOIN:.*]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: br label %[[JOIN]]
+; CHECK: [[JOIN]]:
+; CHECK-NEXT: store atomic i32 0, ptr [[X]] release, align 4
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %val = load i32, ptr %x, align 4
+ %cmp = icmp eq i32 %val, 0
+ br i1 %cmp, label %then, label %end
+
+then:
+ br i1 %c, label %if.eq, label %if.else
+
+if.eq:
+ br label %join
+
+if.else:
+ br label %join
+
+join:
+ store atomic i32 0, ptr %x release, align 4
+ br label %end
+
+end:
+ ret void
+}
+
+declare void @opaque(ptr)
More information about the llvm-commits
mailing list