[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