[llvm] Preserve AA metadata on coerced GVN loads (PR #190394)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 3 14:39:54 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Pppp1116 (Pppp1116)
<details>
<summary>Changes</summary>
## Summary
This change preserves scoped alias-analysis metadata when GVN forwards a narrower load from an existing wider load.
## What changed
- merge `!alias.scope`, `!noalias`, and `!noalias_addrspace` metadata from the replaced load into the surviving widened load in GVN's coerced-load path
- keep that AA metadata when dropping other non-type-stable metadata after materializing the replacement value
- add a regression test that checks both the preserved metadata after `gvn` and the dead-store deletion that becomes possible after `gvn,dse`
## Why
GVN already knows how to fold a smaller load into a truncation of a wider dominating load, but in that typed coercion path it dropped scoped AA metadata from the surviving load. That made later default-pipeline passes lose alias facts they could otherwise use.
## Impact
Preserving the scoped AA metadata lets later passes such as DSE prove more memory independence on real code without adding a new flag or pipeline stage.
## Validation
- `build-clangd/bin/opt -S -passes=gvn < llvm/test/Transforms/GVN/coerced-load-aa-metadata.ll | build-clangd/bin/FileCheck llvm/test/Transforms/GVN/coerced-load-aa-metadata.ll --check-prefix=GVN`
- `build-clangd/bin/opt -S -passes='gvn,dse' < llvm/test/Transforms/GVN/coerced-load-aa-metadata.ll | build-clangd/bin/FileCheck llvm/test/Transforms/GVN/coerced-load-aa-metadata.ll --check-prefix=DSE`
- `build-clangd/bin/llvm-lit -sv llvm/test/Transforms/GVN/coerced-load-aa-metadata.ll`
---
Full diff: https://github.com/llvm/llvm-project/pull/190394.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/Scalar/GVN.cpp (+4-3)
- (added) llvm/test/Transforms/GVN/coerced-load-aa-metadata.ll (+38)
``````````diff
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 7cab4be169123..7f0ed8cae485b 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -1165,6 +1165,7 @@ Value *AvailableValue::MaterializeAdjustedValue(LoadInst *Load,
} else {
Res = getValueForLoad(CoercedLoad, Offset, LoadTy, InsertPt,
Load->getFunction());
+ combineAAMetadata(CoercedLoad, Load);
// We are adding a new user for this load, for which the original
// metadata may not hold. Additionally, the new load may have a different
// size and type, so their metadata cannot be combined in any
@@ -1172,13 +1173,13 @@ Value *AvailableValue::MaterializeAdjustedValue(LoadInst *Load,
// Drop all metadata that is not known to cause immediate UB on violation,
// unless the load has !noundef, in which case all metadata violations
// will be promoted to UB.
- // TODO: We can combine noalias/alias.scope metadata here, because it is
- // independent of the load type.
if (!CoercedLoad->hasMetadata(LLVMContext::MD_noundef))
CoercedLoad->dropUnknownNonDebugMetadata(
{LLVMContext::MD_dereferenceable,
LLVMContext::MD_dereferenceable_or_null,
- LLVMContext::MD_invariant_load, LLVMContext::MD_invariant_group});
+ LLVMContext::MD_invariant_load, LLVMContext::MD_invariant_group,
+ LLVMContext::MD_alias_scope, LLVMContext::MD_noalias,
+ LLVMContext::MD_noalias_addrspace});
LLVM_DEBUG(dbgs() << "GVN COERCED NONLOCAL LOAD:\nOffset: " << Offset
<< " " << *getCoercedLoadValue() << '\n'
<< *Res << '\n'
diff --git a/llvm/test/Transforms/GVN/coerced-load-aa-metadata.ll b/llvm/test/Transforms/GVN/coerced-load-aa-metadata.ll
new file mode 100644
index 0000000000000..39976ee8fe4a4
--- /dev/null
+++ b/llvm/test/Transforms/GVN/coerced-load-aa-metadata.ll
@@ -0,0 +1,38 @@
+; RUN: opt -S -passes=gvn < %s | FileCheck %s --check-prefix=GVN
+; RUN: opt -S -passes='gvn,dse' < %s | FileCheck %s --check-prefix=DSE
+
+define i16 @test(ptr %p1, ptr %p2) {
+; GVN-LABEL: define i16 @test(
+; GVN-SAME: ptr [[P1:%.*]], ptr [[P2:%.*]]) {
+; GVN: entry:
+; GVN-NEXT: store i8 0, ptr [[P1]], align 1, !noalias [[SCOPE:![0-9]+]]
+; GVN-NEXT: [[L16:%.*]] = load i16, ptr [[P2]], align 2, !alias.scope [[SCOPE]]
+; GVN-NEXT: [[L8:%.*]] = trunc i16 [[L16]] to i8
+; GVN-NEXT: [[COND:%.*]] = icmp eq i8 [[L8]], 7
+; GVN-NEXT: store i8 1, ptr [[P1]], align 1
+; GVN-NEXT: [[R:%.*]] = select i1 [[COND]], i16 [[L16]], i16 0
+; GVN-NEXT: ret i16 [[R]]
+;
+; DSE-LABEL: define i16 @test(
+; DSE-SAME: ptr [[P1:%.*]], ptr [[P2:%.*]]) {
+; DSE: entry:
+; DSE-NEXT: [[L16:%.*]] = load i16, ptr [[P2]], align 2, !alias.scope [[SCOPE:![0-9]+]]
+; DSE-NEXT: [[L8:%.*]] = trunc i16 [[L16]] to i8
+; DSE-NEXT: [[COND:%.*]] = icmp eq i8 [[L8]], 7
+; DSE-NEXT: store i8 1, ptr [[P1]], align 1
+; DSE-NEXT: [[R:%.*]] = select i1 [[COND]], i16 [[L16]], i16 0
+; DSE-NEXT: ret i16 [[R]]
+;
+entry:
+ store i8 0, ptr %p1, align 1, !noalias !2
+ %l16 = load i16, ptr %p2, align 2, !alias.scope !2
+ %l8 = load i8, ptr %p2, align 1, !alias.scope !2
+ %cond = icmp eq i8 %l8, 7
+ store i8 1, ptr %p1, align 1
+ %r = select i1 %cond, i16 %l16, i16 0
+ ret i16 %r
+}
+
+!0 = !{!0}
+!1 = !{!1, !0}
+!2 = !{!1}
``````````
</details>
https://github.com/llvm/llvm-project/pull/190394
More information about the llvm-commits
mailing list