[llvm] [DirectX] Add a GEP to loads and stores on array allocas (PR #148059)

Deric C. via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 11 09:34:31 PDT 2025


https://github.com/Icohedron updated https://github.com/llvm/llvm-project/pull/148059

>From c641da16ed556d4e6ceea7363715b3135bdd23c4 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 10 Jul 2025 19:02:48 +0000
Subject: [PATCH 1/4] Add a GEP to load/stores on array allocas

---
 llvm/lib/Target/DirectX/DXILLegalizePass.cpp  | 43 +++++++++++++++++++
 .../legalize-load-store-array-alloca.ll       | 23 ++++++++++
 2 files changed, 66 insertions(+)
 create mode 100644 llvm/test/CodeGen/DirectX/legalize-load-store-array-alloca.ll

diff --git a/llvm/lib/Target/DirectX/DXILLegalizePass.cpp b/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
index 76a46c7a2b760..724ee57c05a39 100644
--- a/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
+++ b/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
@@ -562,6 +562,48 @@ legalizeGetHighLowi64Bytes(Instruction &I,
   }
 }
 
+static void legalizeLoadStoreOnArrayAllocas(
+    Instruction &I, SmallVectorImpl<Instruction *> &ToRemove,
+    DenseMap<Value *, Value *> &) {
+
+  Value *PtrOp;
+  [[maybe_unused]] Type *LoadStoreTy;
+  if (auto *LI = dyn_cast<LoadInst>(&I)) {
+    PtrOp = LI->getPointerOperand();
+    LoadStoreTy = LI->getType();
+  } else if (auto *SI = dyn_cast<StoreInst>(&I)) {
+    PtrOp = SI->getPointerOperand();
+    LoadStoreTy = SI->getValueOperand()->getType();
+  } else
+    return;
+
+  assert(LoadStoreTy->isSingleValueType() &&
+         "Expected load/store type to be a single-valued type");
+
+  auto *AllocaPtrOp = dyn_cast<AllocaInst>(PtrOp);
+  if (!AllocaPtrOp)
+    return;
+
+  Type *Ty = AllocaPtrOp->getAllocatedType();
+  if (!isa<ArrayType>(Ty)) return;
+  assert(!isa<ArrayType>(Ty->getArrayElementType()) &&
+         "Expected allocated type of AllocaInst to be a flat ArrayType");
+
+  IRBuilder<> Builder(&I);
+  Value *Zero = Builder.getInt32(0);
+  Value *GEP = Builder.CreateInBoundsGEP(Ty, AllocaPtrOp, {Zero, Zero});
+
+  Value *NewLoadStore = nullptr;
+  if (auto *LI = dyn_cast<LoadInst>(&I))
+    NewLoadStore = Builder.CreateLoad(LI->getType(), GEP, LI->getName());
+  else if (auto *SI = dyn_cast<StoreInst>(&I))
+    NewLoadStore =
+        Builder.CreateStore(SI->getValueOperand(), GEP, SI->isVolatile());
+
+  ToRemove.push_back(&I);
+  I.replaceAllUsesWith(NewLoadStore);
+}
+
 namespace {
 class DXILLegalizationPipeline {
 
@@ -605,6 +647,7 @@ class DXILLegalizationPipeline {
     LegalizationPipeline[Stage1].push_back(legalizeMemCpy);
     LegalizationPipeline[Stage1].push_back(removeMemSet);
     LegalizationPipeline[Stage1].push_back(updateFnegToFsub);
+    LegalizationPipeline[Stage1].push_back(legalizeLoadStoreOnArrayAllocas);
     // Note: legalizeGetHighLowi64Bytes and
     // downcastI64toI32InsertExtractElements both modify extractelement, so they
     // must run staggered stages. legalizeGetHighLowi64Bytes runs first b\c it
diff --git a/llvm/test/CodeGen/DirectX/legalize-load-store-array-alloca.ll b/llvm/test/CodeGen/DirectX/legalize-load-store-array-alloca.ll
new file mode 100644
index 0000000000000..703f569f4dfab
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/legalize-load-store-array-alloca.ll
@@ -0,0 +1,23 @@
+; RUN: opt -S -passes='dxil-legalize' -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
+
+define float @load() {
+; CHECK-LABEL: define float @load
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [2 x float], align 4
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x float], ptr [[ALLOCA]], i32 0, i32 0
+; CHECK-NEXT:    [[LOAD:%.*]] = load float, ptr [[GEP]], align 4
+; CHECK-NEXT:    ret float [[LOAD]]
+  %a = alloca [2 x float], align 4
+  %b = load float, ptr %a, align 4
+  ret float %b
+}
+
+define void @store() {
+; CHECK-LABEL: define void @store
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [3 x i32], align 4
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [3 x i32], ptr [[ALLOCA]], i32 0, i32 0
+; CHECK-NEXT:    store i32 0, ptr [[GEP]], align 4
+; CHECK-NEXT:    ret void
+  %a = alloca [3 x i32], align 4
+  store i32 0, ptr %a, align 4
+  ret void
+}

>From 7e7900a23ca5c6172f6359e5e309fa11ab3f6272 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 10 Jul 2025 21:35:50 +0000
Subject: [PATCH 2/4] Apply clang-format

---
 llvm/lib/Target/DirectX/DXILLegalizePass.cpp | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DXILLegalizePass.cpp b/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
index 724ee57c05a39..0d55ac1230d8f 100644
--- a/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
+++ b/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
@@ -562,9 +562,10 @@ legalizeGetHighLowi64Bytes(Instruction &I,
   }
 }
 
-static void legalizeLoadStoreOnArrayAllocas(
-    Instruction &I, SmallVectorImpl<Instruction *> &ToRemove,
-    DenseMap<Value *, Value *> &) {
+static void
+legalizeLoadStoreOnArrayAllocas(Instruction &I,
+                                SmallVectorImpl<Instruction *> &ToRemove,
+                                DenseMap<Value *, Value *> &) {
 
   Value *PtrOp;
   [[maybe_unused]] Type *LoadStoreTy;
@@ -585,7 +586,8 @@ static void legalizeLoadStoreOnArrayAllocas(
     return;
 
   Type *Ty = AllocaPtrOp->getAllocatedType();
-  if (!isa<ArrayType>(Ty)) return;
+  if (!isa<ArrayType>(Ty))
+    return;
   assert(!isa<ArrayType>(Ty->getArrayElementType()) &&
          "Expected allocated type of AllocaInst to be a flat ArrayType");
 

>From 76d88298fb6bbb472023adc892d9e88391a76718 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 10 Jul 2025 22:28:24 +0000
Subject: [PATCH 3/4] Move pass to stage 2 to not conflict with i8 legalization

---
 llvm/lib/Target/DirectX/DXILLegalizePass.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/DirectX/DXILLegalizePass.cpp b/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
index 0d55ac1230d8f..eb2b118af17da 100644
--- a/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
+++ b/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
@@ -649,7 +649,6 @@ class DXILLegalizationPipeline {
     LegalizationPipeline[Stage1].push_back(legalizeMemCpy);
     LegalizationPipeline[Stage1].push_back(removeMemSet);
     LegalizationPipeline[Stage1].push_back(updateFnegToFsub);
-    LegalizationPipeline[Stage1].push_back(legalizeLoadStoreOnArrayAllocas);
     // Note: legalizeGetHighLowi64Bytes and
     // downcastI64toI32InsertExtractElements both modify extractelement, so they
     // must run staggered stages. legalizeGetHighLowi64Bytes runs first b\c it
@@ -657,6 +656,7 @@ class DXILLegalizationPipeline {
     // downcastI64toI32InsertExtractElements needs to handle.
     LegalizationPipeline[Stage2].push_back(
         downcastI64toI32InsertExtractElements);
+    LegalizationPipeline[Stage2].push_back(legalizeLoadStoreOnArrayAllocas);
   }
 };
 

>From 64bb53341ef40925e96da34c2dde5d79d6afe2dc Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 10 Jul 2025 22:29:06 +0000
Subject: [PATCH 4/4] Add tests with i8, and add nuw flag to GEP

---
 llvm/lib/Target/DirectX/DXILLegalizePass.cpp           |  7 ++++---
 llvm/test/CodeGen/DirectX/legalize-i8.ll               | 10 ++++++----
 .../DirectX/legalize-load-store-array-alloca.ll        |  4 ++--
 3 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DXILLegalizePass.cpp b/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
index eb2b118af17da..7e08eec1411d5 100644
--- a/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
+++ b/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
@@ -98,9 +98,9 @@ static void fixI8UseChain(Instruction &I,
       ElementType = AI->getAllocatedType();
     if (auto *GEP = dyn_cast<GetElementPtrInst>(NewOperands[0])) {
       ElementType = GEP->getSourceElementType();
-      if (ElementType->isArrayTy())
-        ElementType = ElementType->getArrayElementType();
     }
+    if (ElementType->isArrayTy())
+      ElementType = ElementType->getArrayElementType();
     LoadInst *NewLoad = Builder.CreateLoad(ElementType, NewOperands[0]);
     ReplacedValues[Load] = NewLoad;
     ToRemove.push_back(Load);
@@ -593,7 +593,8 @@ legalizeLoadStoreOnArrayAllocas(Instruction &I,
 
   IRBuilder<> Builder(&I);
   Value *Zero = Builder.getInt32(0);
-  Value *GEP = Builder.CreateInBoundsGEP(Ty, AllocaPtrOp, {Zero, Zero});
+  Value *GEP = Builder.CreateGEP(Ty, AllocaPtrOp, {Zero, Zero}, "",
+                                 GEPNoWrapFlags::all());
 
   Value *NewLoadStore = nullptr;
   if (auto *LI = dyn_cast<LoadInst>(&I))
diff --git a/llvm/test/CodeGen/DirectX/legalize-i8.ll b/llvm/test/CodeGen/DirectX/legalize-i8.ll
index f8aa2c5ecd932..7eb47ba661f4c 100644
--- a/llvm/test/CodeGen/DirectX/legalize-i8.ll
+++ b/llvm/test/CodeGen/DirectX/legalize-i8.ll
@@ -127,10 +127,9 @@ define i32 @i8_geps_index0() {
   ; CHECK:         [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
   ; CHECK-NEXT:    ret i32 [[LOAD]]
   %1 = alloca [2 x i32], align 8
-  %2 = getelementptr inbounds nuw i8, ptr %1, i32 0
-  %3 = load i8, ptr %2
-  %4 = sext i8 %3 to i32
-  ret i32 %4
+  %2 = load i8, ptr %1
+  %3 = sext i8 %2 to i32
+  ret i32 %3
 }
 
 define i32 @i8_geps_index1() {
@@ -149,11 +148,14 @@ define i32 @i8_geps_index1() {
 define i32 @i8_gep_store() {
   ; CHECK-LABEL: define i32 @i8_gep_store(
   ; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [2 x i32], align 8
+  ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds nuw [2 x i32], ptr [[ALLOCA]], i32 0, i32 0
+  ; CHECK-NEXT:    store i32 0, ptr [[GEP]], align 4
   ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds nuw [2 x i32], ptr [[ALLOCA]], i32 0, i32 1
   ; CHECK-NEXT:    store i32 1, ptr [[GEP]], align 4
   ; CHECK:         [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
   ; CHECK-NEXT:    ret i32 [[LOAD]]
   %1 = alloca [2 x i32], align 8
+  store i8 0, ptr %1
   %2 = getelementptr inbounds nuw i8, ptr %1, i32 4
   store i8 1, ptr %2
   %3 = load i8, ptr %2
diff --git a/llvm/test/CodeGen/DirectX/legalize-load-store-array-alloca.ll b/llvm/test/CodeGen/DirectX/legalize-load-store-array-alloca.ll
index 703f569f4dfab..b25b3de901d91 100644
--- a/llvm/test/CodeGen/DirectX/legalize-load-store-array-alloca.ll
+++ b/llvm/test/CodeGen/DirectX/legalize-load-store-array-alloca.ll
@@ -3,7 +3,7 @@
 define float @load() {
 ; CHECK-LABEL: define float @load
 ; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [2 x float], align 4
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x float], ptr [[ALLOCA]], i32 0, i32 0
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds nuw [2 x float], ptr [[ALLOCA]], i32 0, i32 0
 ; CHECK-NEXT:    [[LOAD:%.*]] = load float, ptr [[GEP]], align 4
 ; CHECK-NEXT:    ret float [[LOAD]]
   %a = alloca [2 x float], align 4
@@ -14,7 +14,7 @@ define float @load() {
 define void @store() {
 ; CHECK-LABEL: define void @store
 ; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [3 x i32], align 4
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [3 x i32], ptr [[ALLOCA]], i32 0, i32 0
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds nuw [3 x i32], ptr [[ALLOCA]], i32 0, i32 0
 ; CHECK-NEXT:    store i32 0, ptr [[GEP]], align 4
 ; CHECK-NEXT:    ret void
   %a = alloca [3 x i32], align 4



More information about the llvm-commits mailing list