[llvm-branch-commits] [llvm] [GVN] Preserve scoped-alias metadata on coerced loads (PR #206417)
Madhur Amilkanthwar via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Jun 29 00:30:07 PDT 2026
https://github.com/madhur13490 created https://github.com/llvm/llvm-project/pull/206417
When forwarding a wider load to a narrower load at an offset, GVN drops
the wider load's metadata. !noalias and !alias.scope are independent of
the load type and offset, and the wider load is not moved and still
accesses the same memory, so they remain valid and are now kept instead
of dropped.
>From 126583db52ddd789c36054c38fb10346b00fd277 Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Sat, 27 Jun 2026 00:08:11 -0700
Subject: [PATCH] [GVN] Preserve scoped-alias metadata on coerced loads
When forwarding a wider load to a narrower load at an offset, GVN drops
the wider load's metadata. !noalias and !alias.scope are independent of
the load type and offset, and the wider load is not moved and still
accesses the same memory, so they remain valid and are now kept instead
of dropped.
---
llvm/lib/Transforms/Scalar/GVN.cpp | 8 +++++---
.../Transforms/GVN/rle-coerced-noalias.ll | 19 ++++++++++++-------
2 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index a619dcc588350..517d33bfba103 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -1163,13 +1163,15 @@ 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.
+ // !noalias and !alias.scope are kept: the load is not moved and still
+ // accesses the same memory, and these are independent of the load type
+ // and offset, so they remain valid for the coerced result.
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});
LLVM_DEBUG(dbgs() << "GVN COERCED NONLOCAL LOAD:\nOffset: " << Offset
<< " " << *getCoercedLoadValue() << '\n'
<< *Res << '\n'
diff --git a/llvm/test/Transforms/GVN/rle-coerced-noalias.ll b/llvm/test/Transforms/GVN/rle-coerced-noalias.ll
index 277e054fdccd5..67f7f58543aa8 100644
--- a/llvm/test/Transforms/GVN/rle-coerced-noalias.ll
+++ b/llvm/test/Transforms/GVN/rle-coerced-noalias.ll
@@ -1,10 +1,10 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -S -passes=gvn < %s | FileCheck %s
-; When GVN coerces a wider load into a narrower load at an offset, it strips
-; !noalias and !alias.scope from the surviving wider load. That load is
-; unchanged and still accesses the same memory, so the metadata stays valid
-; and should be kept. It is currently dropped.
+; When GVN coerces a wider load into a narrower load at an offset, the wider
+; load is not moved and still accesses the same memory. Its !noalias and
+; !alias.scope are independent of the load type and offset, so they are
+; preserved on the surviving wider load rather than dropped.
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@@ -14,7 +14,7 @@ define i32 @noalias_dropped_local(ptr %p) {
; CHECK-LABEL: define i32 @noalias_dropped_local(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: [[WIDE:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT: [[WIDE:%.*]] = load i32, ptr [[P]], align 4, !noalias [[META0:![0-9]+]]
; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 1
; CHECK-NEXT: [[TMP0:%.*]] = lshr i32 [[WIDE]], 8
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8
@@ -36,7 +36,7 @@ define i32 @alias_scope_dropped_local(ptr %p) {
; CHECK-LABEL: define i32 @alias_scope_dropped_local(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: [[WIDE:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT: [[WIDE:%.*]] = load i32, ptr [[P]], align 4, !alias.scope [[META0]]
; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 1
; CHECK-NEXT: [[TMP0:%.*]] = lshr i32 [[WIDE]], 8
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8
@@ -60,7 +60,7 @@ define i32 @noalias_dropped_nonlocal(ptr %p) {
; CHECK-LABEL: define i32 @noalias_dropped_nonlocal(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: [[WIDE:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT: [[WIDE:%.*]] = load i32, ptr [[P]], align 4, !noalias [[META0]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[WIDE]], 127
; CHECK-NEXT: [[TMP0:%.*]] = lshr i32 [[WIDE]], 8
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8
@@ -92,3 +92,8 @@ f:
!2 = distinct !{!2, !"test domain"}
!0 = !{!1}
+;.
+; CHECK: [[META0]] = !{[[META1:![0-9]+]]}
+; CHECK: [[META1]] = distinct !{[[META1]], [[META2:![0-9]+]], !"scope A"}
+; CHECK: [[META2]] = distinct !{[[META2]], !"test domain"}
+;.
More information about the llvm-branch-commits
mailing list