[llvm] 52cf94a - [AMDGPU] Drop !noundef when widening sub-DWORD constant loads (#201085)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 3 06:20:29 PDT 2026


Author: Arseniy Obolenskiy
Date: 2026-06-03T15:20:23+02:00
New Revision: 52cf94a82eabfe70d417c17a3ab38736ded4938b

URL: https://github.com/llvm/llvm-project/commit/52cf94a82eabfe70d417c17a3ab38736ded4938b
DIFF: https://github.com/llvm/llvm-project/commit/52cf94a82eabfe70d417c17a3ab38736ded4938b.diff

LOG: [AMDGPU] Drop !noundef when widening sub-DWORD constant loads (#201085)

The widened i32 load reads bytes outside the original sub-DWORD load, so
new op cannot claim !noundef

Added: 
    

Modified: 
    llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
    llvm/lib/Target/AMDGPU/AMDGPULateCodeGenPrepare.cpp
    llvm/lib/Target/AMDGPU/AMDGPUMemoryUtils.cpp
    llvm/lib/Target/AMDGPU/AMDGPUMemoryUtils.h
    llvm/test/CodeGen/AMDGPU/amdgpu-late-codegenprepare.ll
    llvm/test/CodeGen/AMDGPU/widen_extending_scalar_loads.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp b/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
index 1bcfc1da3b84e..4995cd2d1956b 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "AMDGPU.h"
+#include "AMDGPUMemoryUtils.h"
 #include "AMDGPUTargetMachine.h"
 #include "SIModeRegisterDefaults.h"
 #include "llvm/ADT/SetVector.h"
@@ -1561,17 +1562,15 @@ bool AMDGPUCodeGenPrepareImpl::visitLoadInst(LoadInst &I) {
 
     Type *I32Ty = Builder.getInt32Ty();
     LoadInst *WidenLoad = Builder.CreateLoad(I32Ty, I.getPointerOperand());
-    WidenLoad->copyMetadata(I);
+    AMDGPU::copyMetadataForWidenedLoad(*WidenLoad, I);
 
-    // If we have range metadata, we need to convert the type, and not make
+    // The widened load reads the original bytes in the low bits, so a !range
+    // lower bound still holds. Convert it to the new type and don't make
     // assumptions about the high bits.
-    if (auto *Range = WidenLoad->getMetadata(LLVMContext::MD_range)) {
-      ConstantInt *Lower =
-        mdconst::extract<ConstantInt>(Range->getOperand(0));
+    if (auto *Range = I.getMetadata(LLVMContext::MD_range)) {
+      ConstantInt *Lower = mdconst::extract<ConstantInt>(Range->getOperand(0));
 
-      if (Lower->isNullValue()) {
-        WidenLoad->setMetadata(LLVMContext::MD_range, nullptr);
-      } else {
+      if (!Lower->isNullValue()) {
         Metadata *LowAndHigh[] = {
           ConstantAsMetadata::get(ConstantInt::get(I32Ty, Lower->getValue().zext(32))),
           // Don't make assumptions about the high bits.

diff  --git a/llvm/lib/Target/AMDGPU/AMDGPULateCodeGenPrepare.cpp b/llvm/lib/Target/AMDGPU/AMDGPULateCodeGenPrepare.cpp
index 3844e68be8e8e..b5c2b366c8e7b 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULateCodeGenPrepare.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULateCodeGenPrepare.cpp
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "AMDGPU.h"
+#include "AMDGPUMemoryUtils.h"
 #include "AMDGPUTargetMachine.h"
 #include "llvm/Analysis/AssumptionCache.h"
 #include "llvm/Analysis/UniformityAnalysis.h"
@@ -536,8 +537,7 @@ bool AMDGPULateCodeGenPrepare::visitLoadInst(LoadInst &LI) {
       Offset - Adjust);
 
   LoadInst *NewLd = IRB.CreateAlignedLoad(IRB.getInt32Ty(), NewPtr, Align(4));
-  NewLd->copyMetadata(LI);
-  NewLd->setMetadata(LLVMContext::MD_range, nullptr);
+  AMDGPU::copyMetadataForWidenedLoad(*NewLd, LI);
 
   unsigned ShAmt = Adjust * 8;
   Value *NewVal = IRB.CreateBitCast(

diff  --git a/llvm/lib/Target/AMDGPU/AMDGPUMemoryUtils.cpp b/llvm/lib/Target/AMDGPU/AMDGPUMemoryUtils.cpp
index 9fbb19df1ba53..14592298c907f 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUMemoryUtils.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUMemoryUtils.cpp
@@ -17,6 +17,7 @@
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/IntrinsicsAMDGPU.h"
+#include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/ReplaceConstant.h"
 
 #define DEBUG_TYPE "amdgpu-memory-utils"
@@ -30,6 +31,22 @@ Align getAlign(const DataLayout &DL, const GlobalVariable *GV) {
                                        GV->getValueType());
 }
 
+void copyMetadataForWidenedLoad(LoadInst &Dest, const LoadInst &Source) {
+  SmallVector<std::pair<unsigned, MDNode *>, 8> MD;
+  Source.getAllMetadata(MD);
+  for (const auto [ID, N] : MD) {
+    switch (ID) {
+    case LLVMContext::MD_dbg:
+    case LLVMContext::MD_invariant_load:
+    case LLVMContext::MD_nontemporal:
+      Dest.setMetadata(ID, N);
+      break;
+    default:
+      break;
+    }
+  }
+}
+
 // Returns the target extension type of a global variable,
 // which can only be a TargetExtType, an array or single-element struct of it,
 // or their nesting combination.

diff  --git a/llvm/lib/Target/AMDGPU/AMDGPUMemoryUtils.h b/llvm/lib/Target/AMDGPU/AMDGPUMemoryUtils.h
index 8868b93440768..518f9066e5164 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUMemoryUtils.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUMemoryUtils.h
@@ -35,6 +35,11 @@ using VariableFunctionMap = DenseMap<GlobalVariable *, DenseSet<Function *>>;
 
 Align getAlign(const DataLayout &DL, const GlobalVariable *GV);
 
+// Copy metadata onto a load widened to read a superset of Source's bytes. Only
+// value-independent metadata is copied; metadata describing the loaded value
+// (!range, !noundef, !nofpclass, !tbaa, ...) is dropped.
+void copyMetadataForWidenedLoad(LoadInst &Dest, const LoadInst &Source);
+
 // If GV is a named-barrier return its type. Otherwise return nullptr.
 TargetExtType *isNamedBarrier(const GlobalVariable &GV);
 

diff  --git a/llvm/test/CodeGen/AMDGPU/amdgpu-late-codegenprepare.ll b/llvm/test/CodeGen/AMDGPU/amdgpu-late-codegenprepare.ll
index 3e232bb1914f8..e816492ea381e 100644
--- a/llvm/test/CodeGen/AMDGPU/amdgpu-late-codegenprepare.ll
+++ b/llvm/test/CodeGen/AMDGPU/amdgpu-late-codegenprepare.ll
@@ -149,3 +149,62 @@ bb7:
   %i8 = phi <4 x i8> [ zeroinitializer, %bb5 ], [ zeroinitializer, %bb3 ]
   br label %bb1
 }
+
+; The widened i32 load reads bytes outside the original i8 load, so !noundef
+; must not be carried over for GFX9.
+define amdgpu_kernel void @no_widen_noundef(ptr addrspace(4) align 4 %p, ptr addrspace(1) %out) {
+; GFX9-LABEL: @no_widen_noundef(
+; GFX9-NEXT:    [[TMP1:%.*]] = getelementptr i8, ptr addrspace(4) [[P:%.*]], i64 0
+; GFX9-NEXT:    [[TMP2:%.*]] = load i32, ptr addrspace(4) [[TMP1]], align 4
+; GFX9-NEXT:    [[TMP3:%.*]] = lshr i32 [[TMP2]], 8
+; GFX9-NEXT:    [[TMP4:%.*]] = trunc i32 [[TMP3]] to i8
+; GFX9-NEXT:    [[VZ:%.*]] = zext i8 [[TMP4]] to i32
+; GFX9-NEXT:    store i32 [[VZ]], ptr addrspace(1) [[OUT:%.*]], align 4
+; GFX9-NEXT:    ret void
+;
+; GFX12-LABEL: @no_widen_noundef(
+; GFX12-NEXT:    [[P1:%.*]] = getelementptr inbounds i8, ptr addrspace(4) [[P:%.*]], i64 1
+; GFX12-NEXT:    [[V:%.*]] = load i8, ptr addrspace(4) [[P1]], align 1, !noundef [[META0:![0-9]+]]
+; GFX12-NEXT:    [[VZ:%.*]] = zext i8 [[V]] to i32
+; GFX12-NEXT:    store i32 [[VZ]], ptr addrspace(1) [[OUT:%.*]], align 4
+; GFX12-NEXT:    ret void
+;
+  %p1 = getelementptr inbounds i8, ptr addrspace(4) %p, i64 1
+  %v = load i8, ptr addrspace(4) %p1, align 1, !noundef !0
+  %vz = zext i8 %v to i32
+  store i32 %vz, ptr addrspace(1) %out, align 4
+  ret void
+}
+
+; The widened i32 load reads bytes outside the original f16 load, so !nofpclass
+; must not be carried over for GFX9.
+define amdgpu_kernel void @no_widen_nofpclass(ptr addrspace(4) align 4 %p, ptr addrspace(1) %out) {
+; GFX9-LABEL: @no_widen_nofpclass(
+; GFX9-NEXT:    [[TMP1:%.*]] = getelementptr i8, ptr addrspace(4) [[P:%.*]], i64 0
+; GFX9-NEXT:    [[TMP2:%.*]] = load i32, ptr addrspace(4) [[TMP1]], align 4
+; GFX9-NEXT:    [[TMP3:%.*]] = lshr i32 [[TMP2]], 16
+; GFX9-NEXT:    [[TMP4:%.*]] = trunc i32 [[TMP3]] to i16
+; GFX9-NEXT:    [[TMP5:%.*]] = bitcast i16 [[TMP4]] to half
+; GFX9-NEXT:    [[VB:%.*]] = bitcast half [[TMP5]] to i16
+; GFX9-NEXT:    [[VZ:%.*]] = zext i16 [[VB]] to i32
+; GFX9-NEXT:    store i32 [[VZ]], ptr addrspace(1) [[OUT:%.*]], align 4
+; GFX9-NEXT:    ret void
+;
+; GFX12-LABEL: @no_widen_nofpclass(
+; GFX12-NEXT:    [[P1:%.*]] = getelementptr inbounds i8, ptr addrspace(4) [[P:%.*]], i64 2
+; GFX12-NEXT:    [[V:%.*]] = load half, ptr addrspace(4) [[P1]], align 2, !nofpclass [[META1:![0-9]+]]
+; GFX12-NEXT:    [[VB:%.*]] = bitcast half [[V]] to i16
+; GFX12-NEXT:    [[VZ:%.*]] = zext i16 [[VB]] to i32
+; GFX12-NEXT:    store i32 [[VZ]], ptr addrspace(1) [[OUT:%.*]], align 4
+; GFX12-NEXT:    ret void
+;
+  %p1 = getelementptr inbounds i8, ptr addrspace(4) %p, i64 2
+  %v = load half, ptr addrspace(4) %p1, align 2, !nofpclass !1
+  %vb = bitcast half %v to i16
+  %vz = zext i16 %vb to i32
+  store i32 %vz, ptr addrspace(1) %out, align 4
+  ret void
+}
+
+!0 = !{}
+!1 = !{i32 3}

diff  --git a/llvm/test/CodeGen/AMDGPU/widen_extending_scalar_loads.ll b/llvm/test/CodeGen/AMDGPU/widen_extending_scalar_loads.ll
index 24c1875159f67..95b6a1a31871d 100644
--- a/llvm/test/CodeGen/AMDGPU/widen_extending_scalar_loads.ll
+++ b/llvm/test/CodeGen/AMDGPU/widen_extending_scalar_loads.ll
@@ -317,6 +317,22 @@ define amdgpu_kernel void @constant_load_i16_align4_invariant(ptr addrspace(1) %
   ret void
 }
 
+; The widened i32 load reads bytes outside the original i16 load, so !noundef
+; must not be carried over.
+define amdgpu_kernel void @constant_load_i16_align4_noundef(ptr addrspace(1) %out, ptr addrspace(4) %in) #0 {
+; OPT-LABEL: @constant_load_i16_align4_noundef(
+; OPT-NEXT:    [[TMP1:%.*]] = load i32, ptr addrspace(4) [[IN:%.*]], align 4
+; OPT-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+; OPT-NEXT:    [[EXT:%.*]] = sext i16 [[TMP2]] to i32
+; OPT-NEXT:    store i32 [[EXT]], ptr addrspace(1) [[OUT:%.*]], align 4
+; OPT-NEXT:    ret void
+;
+  %ld = load i16, ptr addrspace(4) %in, align 4, !noundef !6
+  %ext = sext i16 %ld to i32
+  store i32 %ext, ptr addrspace(1) %out
+  ret void
+}
+
 attributes #0 = { nounwind }
 
 ; OPT: !0 = !{i32 5, i32 0}


        


More information about the llvm-commits mailing list