[llvm] GVN: Fix trying to inspect uselist of constants when emitting remark (PR #144009)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 12 21:15:32 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Matt Arsenault (arsenm)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/144009.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/Scalar/GVN.cpp (+43-32)
- (added) llvm/test/Transforms/GVN/opt-remark-assert-constant-uselistorder.ll (+26)
``````````diff
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index a0eed31fde792..c8a0479358eab 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -1165,7 +1165,7 @@ static bool isLifetimeStart(const Instruction *Inst) {
/// Assuming To can be reached from both From and Between, does Between lie on
/// every path from From to To?
static bool liesBetween(const Instruction *From, Instruction *Between,
- const Instruction *To, DominatorTree *DT) {
+ const Instruction *To, const DominatorTree *DT) {
if (From->getParent() == Between->getParent())
return DT->dominates(From, Between);
SmallSet<BasicBlock *, 1> Exclusion;
@@ -1173,20 +1173,15 @@ static bool liesBetween(const Instruction *From, Instruction *Between,
return !isPotentiallyReachable(From, To, &Exclusion, DT);
}
-/// Try to locate the three instruction involved in a missed
-/// load-elimination case that is due to an intervening store.
-static void reportMayClobberedLoad(LoadInst *Load, MemDepResult DepInfo,
- DominatorTree *DT,
- OptimizationRemarkEmitter *ORE) {
- using namespace ore;
+static const Instruction *findMayClobberedPtrAccess(LoadInst *Load,
+ const DominatorTree *DT) {
+ Value *PtrOp = Load->getPointerOperand();
+ if (!PtrOp->hasUseList())
+ return nullptr;
Instruction *OtherAccess = nullptr;
- OptimizationRemarkMissed R(DEBUG_TYPE, "LoadClobbered", Load);
- R << "load of type " << NV("Type", Load->getType()) << " not eliminated"
- << setExtraArgs();
-
- for (auto *U : Load->getPointerOperand()->users()) {
+ for (auto *U : PtrOp->users()) {
if (U != Load && (isa<LoadInst>(U) || isa<StoreInst>(U))) {
auto *I = cast<Instruction>(U);
if (I->getFunction() == Load->getFunction() && DT->dominates(I, Load)) {
@@ -1202,32 +1197,48 @@ static void reportMayClobberedLoad(LoadInst *Load, MemDepResult DepInfo,
}
}
- if (!OtherAccess) {
- // There is no dominating use, check if we can find a closest non-dominating
- // use that lies between any other potentially available use and Load.
- for (auto *U : Load->getPointerOperand()->users()) {
- if (U != Load && (isa<LoadInst>(U) || isa<StoreInst>(U))) {
- auto *I = cast<Instruction>(U);
- if (I->getFunction() == Load->getFunction() &&
- isPotentiallyReachable(I, Load, nullptr, DT)) {
- if (OtherAccess) {
- if (liesBetween(OtherAccess, I, Load, DT)) {
- OtherAccess = I;
- } else if (!liesBetween(I, OtherAccess, Load, DT)) {
- // These uses are both partially available at Load were it not for
- // the clobber, but neither lies strictly after the other.
- OtherAccess = nullptr;
- break;
- } // else: keep current OtherAccess since it lies between U and
- // Load.
- } else {
+ if (OtherAccess)
+ return OtherAccess;
+
+ // There is no dominating use, check if we can find a closest non-dominating
+ // use that lies between any other potentially available use and Load.
+ for (auto *U : PtrOp->users()) {
+ if (U != Load && (isa<LoadInst>(U) || isa<StoreInst>(U))) {
+ auto *I = cast<Instruction>(U);
+ if (I->getFunction() == Load->getFunction() &&
+ isPotentiallyReachable(I, Load, nullptr, DT)) {
+ if (OtherAccess) {
+ if (liesBetween(OtherAccess, I, Load, DT)) {
OtherAccess = I;
- }
+ } else if (!liesBetween(I, OtherAccess, Load, DT)) {
+ // These uses are both partially available at Load were it not for
+ // the clobber, but neither lies strictly after the other.
+ OtherAccess = nullptr;
+ break;
+ } // else: keep current OtherAccess since it lies between U and
+ // Load.
+ } else {
+ OtherAccess = I;
}
}
}
}
+ return OtherAccess;
+}
+
+/// Try to locate the three instruction involved in a missed
+/// load-elimination case that is due to an intervening store.
+static void reportMayClobberedLoad(LoadInst *Load, MemDepResult DepInfo,
+ const DominatorTree *DT,
+ OptimizationRemarkEmitter *ORE) {
+ using namespace ore;
+
+ OptimizationRemarkMissed R(DEBUG_TYPE, "LoadClobbered", Load);
+ R << "load of type " << NV("Type", Load->getType()) << " not eliminated"
+ << setExtraArgs();
+
+ const Instruction *OtherAccess = findMayClobberedPtrAccess(Load, DT);
if (OtherAccess)
R << " in favor of " << NV("OtherAccess", OtherAccess);
diff --git a/llvm/test/Transforms/GVN/opt-remark-assert-constant-uselistorder.ll b/llvm/test/Transforms/GVN/opt-remark-assert-constant-uselistorder.ll
new file mode 100644
index 0000000000000..e793728815a88
--- /dev/null
+++ b/llvm/test/Transforms/GVN/opt-remark-assert-constant-uselistorder.ll
@@ -0,0 +1,26 @@
+; RUN: opt -passes='gvn' -pass-remarks-output=%t.yaml %s
+; RUN: FileCheck %s < %t.yaml
+
+; Check that there's no assert from trying to the uses of the constant
+; null.
+
+; CHECK: --- !Missed
+; CHECK-NEXT: Pass: gvn
+; CHECK-NEXT: Name: LoadClobbered
+; CHECK-NEXT: Function: c
+; CHECK-NEXT: Args:
+; CHECK-NEXT: - String: 'load of type '
+; CHECK-NEXT: - Type: i64
+; CHECK-NEXT: - String: ' not eliminated'
+; CHECK-NEXT: - String: ' because it is clobbered by '
+; CHECK-NEXT: - ClobberedBy: store
+; CHECK-NEXT: ...
+define void @c(ptr addrspace(21) %a) {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.cond, %entry
+ %load = load i64, ptr addrspace(21) null, align 1
+ store i64 %load, ptr addrspace(21) %a, align 1
+ br label %for.cond
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/144009
More information about the llvm-commits
mailing list