[llvm] [HLSL][DirectX] Handles GEPs in dxil resource access pass (PR #224754)
Sarah Spall via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 18 14:53:57 PDT 2026
https://github.com/spall created https://github.com/llvm/llvm-project/pull/224754
Add support to traverse through GEPs in dxil resource access pass, as well as support getbasepointer which is used by cbuffers.
Closes #224102
Assisted by GPT-5.6 Sol and @inbelic
>From c5ad74db2f5eec8907559c97e905fd8d86248ce7 Mon Sep 17 00:00:00 2001
From: Sarah Spall <sarahspall at microsoft.com>
Date: Thu, 17 Sep 2026 15:39:09 -0700
Subject: [PATCH 1/6] start with @inbelic original pr
---
.../lib/Target/DirectX/DXILResourceAccess.cpp | 89 +++++++++++++++++--
1 file changed, 84 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index 40f5a36284ae3..5d87efd030f5f 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -9,6 +9,7 @@
#include "DXILResourceAccess.h"
#include "DirectX.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Analysis/DXILResource.h"
@@ -650,6 +651,7 @@ static void createCBufferLoad(IntrinsicInst *II, LoadInst *LI,
DL, Builder, LastGEP->getPointerOperand(), hlsl::CBufferRowSizeInBytes);
CurrentRow = Builder.CreateAdd(GEPOffset, CurrentRow);
+ // todo look here
APInt ConstantOffset(DL.getIndexTypeSizeInBits(LastGEP->getType()), 0);
if (LastGEP->accumulateConstantOffset(DL, ConstantOffset)) {
APInt Remainder(DL.getIndexTypeSizeInBits(LastGEP->getType()),
@@ -793,6 +795,8 @@ static SmallVector<IntrinsicInst *> collectUsedHandles(Value *Ptr) {
} else if (auto *Select = dyn_cast<SelectInst>(X))
for (Value *V : {Select->getTrueValue(), Select->getFalseValue()})
Worklist.push_back(V);
+ else if (auto *GEP = dyn_cast<GetElementPtrInst>(X))
+ Worklist.push_back(GEP->getPointerOperand());
else if (auto *II = dyn_cast<IntrinsicInst>(X)) {
Intrinsic::ID IID = II->getIntrinsicID();
@@ -828,24 +832,52 @@ namespace {
struct AccessIndices {
Value *GetPtrIdx;
Value *HandleIdx;
+ Value *OffsetIdx;
bool hasGetPtrIdx() { return GetPtrIdx != nullptr; }
bool hasHandleIdx() { return HandleIdx != nullptr; }
+ bool hasOffsetIdx() { return OffsetIdx != nullptr; }
};
} // namespace
+// Compute the total byte offset described by a GEP as a single i32 value,
+// handling both constant and variable indices.
+static Value *accumulateGEPOffset(GetElementPtrInst *GEP,
+ IRBuilder<> &Builder) {
+ const DataLayout &DL = GEP->getDataLayout();
+ unsigned BitWidth = DL.getIndexTypeSizeInBits(GEP->getType());
+ SmallMapVector<Value *, APInt, 4> VariableOffsets;
+ APInt ConstantOffset(BitWidth, 0);
+ bool Success =
+ GEP->collectOffset(DL, BitWidth, VariableOffsets, ConstantOffset);
+ assert(Success && "Unhandled GEP structure for resource access");
+ (void)Success;
+
+ Type *I32 = Builder.getInt32Ty();
+ Value *Offset = ConstantInt::get(I32, ConstantOffset.getSExtValue());
+ for (auto &[V, Scale] : VariableOffsets) {
+ Value *Index = Builder.CreateZExtOrTrunc(V, I32);
+ if (!Scale.isOne())
+ Index =
+ Builder.CreateMul(Index, ConstantInt::get(I32, Scale.getSExtValue()));
+ Offset = Builder.CreateAdd(Offset, Index);
+ }
+ return Offset;
+}
+
// getAccessIndices traverses up the control flow that a ptr came from and
// propagates back the indicies used to access the resource (AccessIndices):
//
// - GetPtrIdx is the index of dx.resource.getpointer
// - HandleIdx is the index of dx.resource.handlefrom.*
+// - OffsetIdx is the accumulated byte offset of any GEPs in the ptr chain
static AccessIndices
getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
SmallDenseMap<PHINode *, PHINode *> &VisitedPhis) {
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
if (llvm::is_contained(HandleIntrins, II->getIntrinsicID())) {
DeadInsts.insert(II);
- return {nullptr, II->getArgOperand(/*Index=*/3)};
+ return {nullptr, II->getArgOperand(/*Index=*/3), nullptr};
}
if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) {
@@ -860,10 +892,25 @@ getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
}
}
+ if (auto *GEP = dyn_cast<GetElementPtrInst>(I)) {
+ auto *V = dyn_cast<Instruction>(GEP->getPointerOperand());
+ auto AccessIdx = getAccessIndices(V, DeadInsts, VisitedPhis);
+
+ IRBuilder<> Builder(GEP);
+ Value *GEPOffset = accumulateGEPOffset(GEP, Builder);
+ AccessIdx.OffsetIdx =
+ AccessIdx.hasOffsetIdx()
+ ? Builder.CreateAdd(AccessIdx.OffsetIdx, GEPOffset)
+ : GEPOffset;
+
+ DeadInsts.insert(GEP);
+ return AccessIdx;
+ }
+
if (auto *Phi = dyn_cast<PHINode>(I)) {
// If we're already building indices for this phi, return a ref to the phi
if (auto It = VisitedPhis.find(Phi); It != VisitedPhis.end())
- return {nullptr, It->second};
+ return {nullptr, It->second, nullptr};
unsigned NumEdges = Phi->getNumIncomingValues();
assert(NumEdges != 0 && "Malformed Phi Node");
@@ -873,6 +920,8 @@ getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
PHINode::Create(Builder.getInt32Ty(), NumEdges));
std::unique_ptr<PHINode> HandlePhi(
PHINode::Create(Builder.getInt32Ty(), NumEdges));
+ std::unique_ptr<PHINode> OffsetPhi(
+ PHINode::Create(Builder.getInt32Ty(), NumEdges));
// Register a ref to this phi for a recursive phi. This is safe to add to
// the map even if we end up deleting newly created phi below since we can't
@@ -887,6 +936,8 @@ getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
if (AccessIdx.hasGetPtrIdx())
GetPtrPhi->addIncoming(AccessIdx.GetPtrIdx, BB);
HandlePhi->addIncoming(AccessIdx.HandleIdx, BB);
+ if (AccessIdx.hasOffsetIdx())
+ OffsetPhi->addIncoming(AccessIdx.OffsetIdx, BB);
}
Value *GetPtrIdx;
@@ -907,8 +958,16 @@ getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
Builder.Insert(HandleIdx);
}
+ Value *OffsetIdx;
+ if (Value *ConstantIdx = OffsetPhi->hasConstantValue())
+ OffsetIdx = ConstantIdx;
+ else {
+ OffsetIdx = OffsetPhi.release();
+ Builder.Insert(OffsetIdx);
+ }
+
DeadInsts.insert(Phi);
- return {GetPtrIdx, HandleIdx};
+ return {GetPtrIdx, HandleIdx, OffsetIdx};
}
if (auto *Select = dyn_cast<SelectInst>(I)) {
@@ -920,6 +979,7 @@ getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
IRBuilder<> Builder(Select);
Value *GetPtrSelect = nullptr;
+ Value *OffsetSelect = nullptr;
if (TrueAccessIdx.hasGetPtrIdx() && FalseAccessIdx.hasGetPtrIdx())
GetPtrSelect =
@@ -929,8 +989,19 @@ getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
auto *HandleSelect =
Builder.CreateSelect(Select->getCondition(), TrueAccessIdx.HandleIdx,
FalseAccessIdx.HandleIdx);
+
+ if (TrueAccessIdx.hasOffsetIdx() || FalseAccessIdx.hasOffsetIdx()) {
+ Value *Zero = ConstantInt::get(Builder.getInt32Ty(), 0);
+ Value *TrueOffset =
+ TrueAccessIdx.hasOffsetIdx() ? TrueAccessIdx.OffsetIdx : Zero;
+ Value *FalseOffset =
+ FalseAccessIdx.hasOffsetIdx() ? FalseAccessIdx.OffsetIdx : Zero;
+ OffsetSelect =
+ Builder.CreateSelect(Select->getCondition(), TrueOffset, FalseOffset);
+ }
+
DeadInsts.insert(Select);
- return {GetPtrSelect, HandleSelect};
+ return {GetPtrSelect, HandleSelect, OffsetSelect};
}
llvm_unreachable("collectUsedHandles should assure this does not occur");
@@ -959,7 +1030,15 @@ replaceHandleWithIndices(Instruction *Ptr, IntrinsicInst *OldHandle,
auto *GetPtr = Builder.CreateIntrinsic(Ptr->getType(),
Intrinsic::dx_resource_getpointer,
{Handle, AccessIdx.GetPtrIdx});
- Ptr->replaceAllUsesWith(GetPtr);
+
+ // Reapply any byte offset that came from GEPs in the original ptr chain so
+ // that later access lowering still sees it.
+ Value *Result = GetPtr;
+ if (AccessIdx.hasOffsetIdx())
+ Result =
+ Builder.CreateGEP(Builder.getInt8Ty(), GetPtr, AccessIdx.OffsetIdx);
+ // todo is this gep right?
+ Ptr->replaceAllUsesWith(Result);
} else {
assert(Ptr->getType()->isTargetExtTy() && !AccessIdx.hasGetPtrIdx() &&
"Unexpected resource access operand type");
>From a82c03958974490ebf67cc05abb72ba607b3dfed Mon Sep 17 00:00:00 2001
From: Sarah Spall <sarahspall at microsoft.com>
Date: Thu, 17 Sep 2026 19:00:23 -0700
Subject: [PATCH 2/6] handle case where only one branch has gep
---
llvm/lib/Target/DirectX/DXILResourceAccess.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index 5d87efd030f5f..ad20dc9fc4c97 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -938,6 +938,8 @@ getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
HandlePhi->addIncoming(AccessIdx.HandleIdx, BB);
if (AccessIdx.hasOffsetIdx())
OffsetPhi->addIncoming(AccessIdx.OffsetIdx, BB);
+ else
+ OffsetPhi->addIncoming(ConstantInt::get(Builder.getInt32Ty(), 0), BB);
}
Value *GetPtrIdx;
>From 056f862b5af4351da5f9c5a1bf592067e25b5a2b Mon Sep 17 00:00:00 2001
From: Sarah Spall <sarahspall at microsoft.com>
Date: Thu, 17 Sep 2026 19:44:11 -0700
Subject: [PATCH 3/6] deal with basepointers
---
llvm/lib/Target/DirectX/DXILResourceAccess.cpp | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index ad20dc9fc4c97..7595d435fb6b5 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -800,7 +800,8 @@ static SmallVector<IntrinsicInst *> collectUsedHandles(Value *Ptr) {
else if (auto *II = dyn_cast<IntrinsicInst>(X)) {
Intrinsic::ID IID = II->getIntrinsicID();
- if (IID == Intrinsic::dx_resource_getpointer)
+ if (IID == Intrinsic::dx_resource_getpointer ||
+ IID == Intrinsic::dx_resource_getbasepointer)
Worklist.push_back(II->getArgOperand(/*Handle=*/0));
if (llvm::is_contained(HandleIntrins, IID))
@@ -880,12 +881,17 @@ getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
return {nullptr, II->getArgOperand(/*Index=*/3), nullptr};
}
- if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) {
+ Intrinsic::ID IID = II->getIntrinsicID();
+ if (IID == Intrinsic::dx_resource_getpointer ||
+ IID == Intrinsic::dx_resource_getbasepointer) {
auto *V = dyn_cast<Instruction>(II->getArgOperand(/*Handle=*/0));
auto AccessIdx = getAccessIndices(V, DeadInsts, VisitedPhis);
assert(!AccessIdx.hasGetPtrIdx() &&
"Encountered multiple dx.resource.getpointers in ptr chain?");
- AccessIdx.GetPtrIdx = II->getArgOperand(1);
+ IRBuilder<> Builder(II);
+ AccessIdx.GetPtrIdx = ConstantInt::get(Builder.getInt32Ty(), 0);
+ if (IID == Intrinsic::dx_resource_getpointer)
+ AccessIdx.GetPtrIdx = II->getArgOperand(1);
DeadInsts.insert(II);
return AccessIdx;
>From 6d98f7b2646250fdfe7b184b76795f9992640faf Mon Sep 17 00:00:00 2001
From: Sarah Spall <sarahspall at microsoft.com>
Date: Fri, 18 Sep 2026 11:54:58 -0700
Subject: [PATCH 4/6] ai updates
---
.../lib/Target/DirectX/DXILResourceAccess.cpp | 35 +++++++++++++------
1 file changed, 25 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index 7595d435fb6b5..fd24238d44980 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -613,6 +613,9 @@ struct CBufferRowIntrin {
};
} // namespace
+static Value *accumulateGEPOffset(GetElementPtrInst *GEP,
+ IRBuilder<> &Builder);
+
static void createCBufferLoad(IntrinsicInst *II, LoadInst *LI,
dxil::ResourceTypeInfo &RTI) {
const DataLayout &DL = LI->getDataLayout();
@@ -667,9 +670,17 @@ static void createCBufferLoad(IntrinsicInst *II, LoadInst *LI,
// because arrays and structs are always row aligned, and accesses to
// vector elements will show up as a load of the vector followed by an
// extractelement.
+ Value *RowOffset = *LastGEP->idx_begin();
+ if (LastGEP->getSourceElementType()->isIntegerTy(8)) {
+ Value *ByteOffset =
+ accumulateGEPOffset(cast<GetElementPtrInst>(LastGEP), Builder);
+ RowOffset = Builder.CreateExactUDiv(
+ ByteOffset, ConstantInt::get(Builder.getInt32Ty(),
+ hlsl::CBufferRowSizeInBytes));
+ }
CurrentRow = cast<ConstantInt>(CurrentRow)->isZero()
- ? *LastGEP->idx_begin()
- : Builder.CreateAdd(CurrentRow, *LastGEP->idx_begin());
+ ? RowOffset
+ : Builder.CreateAdd(CurrentRow, RowOffset);
CurrentIndex = 0;
}
}
@@ -928,6 +939,7 @@ getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
PHINode::Create(Builder.getInt32Ty(), NumEdges));
std::unique_ptr<PHINode> OffsetPhi(
PHINode::Create(Builder.getInt32Ty(), NumEdges));
+ bool HasOffset = false;
// Register a ref to this phi for a recursive phi. This is safe to add to
// the map even if we end up deleting newly created phi below since we can't
@@ -942,9 +954,10 @@ getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
if (AccessIdx.hasGetPtrIdx())
GetPtrPhi->addIncoming(AccessIdx.GetPtrIdx, BB);
HandlePhi->addIncoming(AccessIdx.HandleIdx, BB);
- if (AccessIdx.hasOffsetIdx())
+ if (AccessIdx.hasOffsetIdx()) {
OffsetPhi->addIncoming(AccessIdx.OffsetIdx, BB);
- else
+ HasOffset = true;
+ } else
OffsetPhi->addIncoming(ConstantInt::get(Builder.getInt32Ty(), 0), BB);
}
@@ -966,12 +979,14 @@ getAccessIndices(Instruction *I, SmallSetVector<Instruction *, 16> &DeadInsts,
Builder.Insert(HandleIdx);
}
- Value *OffsetIdx;
- if (Value *ConstantIdx = OffsetPhi->hasConstantValue())
- OffsetIdx = ConstantIdx;
- else {
- OffsetIdx = OffsetPhi.release();
- Builder.Insert(OffsetIdx);
+ Value *OffsetIdx = nullptr;
+ if (HasOffset) {
+ if (Value *ConstantIdx = OffsetPhi->hasConstantValue())
+ OffsetIdx = ConstantIdx;
+ else {
+ OffsetIdx = OffsetPhi.release();
+ Builder.Insert(OffsetIdx);
+ }
}
DeadInsts.insert(Phi);
>From 3e2088d055d13d6fef33f5428f4f7d8d5c6bbbb2 Mon Sep 17 00:00:00 2001
From: Sarah Spall <sarahspall at microsoft.com>
Date: Fri, 18 Sep 2026 13:04:20 -0700
Subject: [PATCH 5/6] avoid unncessary gep index multiplication and division
for cbuffers
---
.../lib/Target/DirectX/DXILResourceAccess.cpp | 30 +++++++++----------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index fd24238d44980..7351bc80c19b5 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -613,9 +613,6 @@ struct CBufferRowIntrin {
};
} // namespace
-static Value *accumulateGEPOffset(GetElementPtrInst *GEP,
- IRBuilder<> &Builder);
-
static void createCBufferLoad(IntrinsicInst *II, LoadInst *LI,
dxil::ResourceTypeInfo &RTI) {
const DataLayout &DL = LI->getDataLayout();
@@ -654,7 +651,6 @@ static void createCBufferLoad(IntrinsicInst *II, LoadInst *LI,
DL, Builder, LastGEP->getPointerOperand(), hlsl::CBufferRowSizeInBytes);
CurrentRow = Builder.CreateAdd(GEPOffset, CurrentRow);
- // todo look here
APInt ConstantOffset(DL.getIndexTypeSizeInBits(LastGEP->getType()), 0);
if (LastGEP->accumulateConstantOffset(DL, ConstantOffset)) {
APInt Remainder(DL.getIndexTypeSizeInBits(LastGEP->getType()),
@@ -670,17 +666,9 @@ static void createCBufferLoad(IntrinsicInst *II, LoadInst *LI,
// because arrays and structs are always row aligned, and accesses to
// vector elements will show up as a load of the vector followed by an
// extractelement.
- Value *RowOffset = *LastGEP->idx_begin();
- if (LastGEP->getSourceElementType()->isIntegerTy(8)) {
- Value *ByteOffset =
- accumulateGEPOffset(cast<GetElementPtrInst>(LastGEP), Builder);
- RowOffset = Builder.CreateExactUDiv(
- ByteOffset, ConstantInt::get(Builder.getInt32Ty(),
- hlsl::CBufferRowSizeInBytes));
- }
CurrentRow = cast<ConstantInt>(CurrentRow)->isZero()
- ? RowOffset
- : Builder.CreateAdd(CurrentRow, RowOffset);
+ ? *LastGEP->idx_begin()
+ : Builder.CreateAdd(CurrentRow, *LastGEP->idx_begin());
CurrentIndex = 0;
}
}
@@ -781,6 +769,16 @@ static Instruction *getHandleOperand(Instruction *AI) {
return nullptr;
}
+static Instruction *getHandleRoot(Instruction *I) {
+ while (auto *GEP = dyn_cast<GetElementPtrInst>(I)) {
+ auto *PointerI = dyn_cast<Instruction>(GEP->getPointerOperand());
+ if (!PointerI)
+ break;
+ I = PointerI;
+ }
+ return I;
+}
+
static const std::array<Intrinsic::ID, 2> HandleIntrins = {
Intrinsic::dx_resource_handlefrombinding,
Intrinsic::dx_resource_handlefromimplicitbinding,
@@ -1060,7 +1058,6 @@ replaceHandleWithIndices(Instruction *Ptr, IntrinsicInst *OldHandle,
if (AccessIdx.hasOffsetIdx())
Result =
Builder.CreateGEP(Builder.getInt8Ty(), GetPtr, AccessIdx.OffsetIdx);
- // todo is this gep right?
Ptr->replaceAllUsesWith(Result);
} else {
assert(Ptr->getType()->isTargetExtTy() && !AccessIdx.hasGetPtrIdx() &&
@@ -1104,7 +1101,8 @@ static bool legalizeResourceHandles(Function &F, DXILResourceTypeMap &DRTM) {
continue;
}
- replaceHandleWithIndices(HandleOp, Handles[0], DeadInsts, VisitedPhis);
+ replaceHandleWithIndices(getHandleRoot(HandleOp), Handles[0], DeadInsts,
+ VisitedPhis);
}
}
}
>From dd726a18ccc96d15cf794a3794c17d6a4fdaa606 Mon Sep 17 00:00:00 2001
From: Sarah Spall <sarahspall at microsoft.com>
Date: Fri, 18 Sep 2026 14:45:19 -0700
Subject: [PATCH 6/6] test
---
.../ResourceAccess/handle-to-index-gep.ll | 184 ++++++++++++++++++
1 file changed, 184 insertions(+)
create mode 100644 llvm/test/CodeGen/DirectX/ResourceAccess/handle-to-index-gep.ll
diff --git a/llvm/test/CodeGen/DirectX/ResourceAccess/handle-to-index-gep.ll b/llvm/test/CodeGen/DirectX/ResourceAccess/handle-to-index-gep.ll
new file mode 100644
index 0000000000000..52a0c875ae3e7
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ResourceAccess/handle-to-index-gep.ll
@@ -0,0 +1,184 @@
+; RUN: opt -S -dxil-resource-type -dxil-resource-access -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
+
+%struct.S = type { i32, i32 }
+%__cblayout_CB = type <{ <3 x i32>, target("dx.Padding", 4) }>
+%__cblayout_CB2 = type <{ <{ [9 x <{ <3 x i32>, target("dx.Padding", 4) }>], <3 x i32> }> }>
+
+
+ at OutArr.str = internal unnamed_addr constant [7 x i8] c"OutArr\00"
+ at CBArr.str = internal unnamed_addr constant [6 x i8] c"CBArr\00"
+ at CB.str = private unnamed_addr constant [3 x i8] c"CB\00"
+
+; CHECK-LABEL: define i32 @gep_phi(
+; CHECK-SAME: i1 %[[COND:.*]], i32 %[[A:.*]], i32 %[[B:.*]], i32 %[[X:.*]], i32 %[[Y:.*]])
+define i32 @gep_phi(i1 %cond, i32 %a, i32 %b, i32 %x, i32 %y) {
+entry:
+; CHECK: entry:
+; CHECK-NEXT: %[[X_OFFSET:.*]] = mul i32 %[[X]], 8
+; CHECK-NEXT: %[[X_FIELD:.*]] = add i32 4, %[[X_OFFSET]]
+; CHECK-NEXT: br i1 %[[COND]], label %then, label %merge
+ %handle0 = call target("dx.RawBuffer", %struct.S, 1, 0) @llvm.dx.resource.handlefromimplicitbinding(i32 2, i32 0, i32 -1, i32 0, ptr @OutArr.str)
+ %ptr0 = call ptr @llvm.dx.resource.getpointer(target("dx.RawBuffer", %struct.S, 1, 0) %handle0, i32 %a)
+ %field0 = getelementptr %struct.S, ptr %ptr0, i32 %x, i32 1
+ br i1 %cond, label %then, label %merge
+
+then:
+; CHECK: then:
+; CHECK-NEXT: %[[Y_OFFSET:.*]] = mul i32 %[[Y]], 8
+; CHECK-NEXT: %[[Y_FIELD:.*]] = add i32 4, %[[Y_OFFSET]]
+; CHECK-NEXT: br label %merge
+ %handle1 = call target("dx.RawBuffer", %struct.S, 1, 0) @llvm.dx.resource.handlefromimplicitbinding(i32 2, i32 0, i32 -1, i32 1, ptr @OutArr.str)
+ %ptr1 = call ptr @llvm.dx.resource.getpointer(target("dx.RawBuffer", %struct.S, 1, 0) %handle1, i32 %b)
+ %field1 = getelementptr %struct.S, ptr %ptr1, i32 %y, i32 1
+ br label %merge
+
+merge:
+; CHECK: merge:
+; CHECK-NEXT: %[[ELEMENT:.*]] = phi i32 [ %[[A]], %entry ], [ %[[B]], %then ]
+; CHECK-NEXT: %[[HANDLE_IDX:.*]] = phi i32 [ 0, %entry ], [ 1, %then ]
+; CHECK-NEXT: %[[OFFSET:.*]] = phi i32 [ %[[X_FIELD]], %entry ], [ %[[Y_FIELD]], %then ]
+; CHECK-NEXT: %[[HANDLE:.*]] = call target("dx.RawBuffer", %struct.S, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_s_struct.Ss_1_0t(i32 2, i32 0, i32 -1, i32 %[[HANDLE_IDX]], ptr @OutArr.str)
+; CHECK-NEXT: %[[LOAD:.*]] = call { i32, i1 } @llvm.dx.resource.load.rawbuffer.i32.tdx.RawBuffer_s_struct.Ss_1_0t(target("dx.RawBuffer", %struct.S, 1, 0) %[[HANDLE]], i32 %[[ELEMENT]], i32 %[[OFFSET]])
+; CHECK-NEXT: %[[VALUE:.*]] = extractvalue { i32, i1 } %[[LOAD]], 0
+; CHECK-NEXT: ret i32 %[[VALUE]]
+ %ptr = phi ptr [ %field0, %entry ], [ %field1, %then ]
+ %value = load i32, ptr %ptr
+ ret i32 %value
+}
+
+; CHECK-LABEL: define i32 @gep_phi_one_branch(
+; CHECK-SAME: i1 %[[COND:.*]], i32 %[[A:.*]], i32 %[[B:.*]])
+define i32 @gep_phi_one_branch(i1 %cond, i32 %a, i32 %b) {
+entry:
+ %handle0 = call target("dx.RawBuffer", %struct.S, 1, 0) @llvm.dx.resource.handlefromimplicitbinding(i32 2, i32 0, i32 -1, i32 0, ptr @OutArr.str)
+ %ptr0 = call ptr @llvm.dx.resource.getpointer(target("dx.RawBuffer", %struct.S, 1, 0) %handle0, i32 %a)
+; CHECK: br i1 %[[COND]], label %then, label %merge
+ br i1 %cond, label %then, label %merge
+
+then:
+ %handle1 = call target("dx.RawBuffer", %struct.S, 1, 0) @llvm.dx.resource.handlefromimplicitbinding(i32 2, i32 0, i32 -1, i32 1, ptr @OutArr.str)
+ %ptr1 = call ptr @llvm.dx.resource.getpointer(target("dx.RawBuffer", %struct.S, 1, 0) %handle1, i32 %b)
+ %field1 = getelementptr %struct.S, ptr %ptr1, i32 0, i32 1
+ ; CHECK: br label %merge
+ br label %merge
+
+merge:
+; CHECK: merge:
+; CHECK-NEXT: %[[ELEMENT:.*]] = phi i32 [ %[[A]], %entry ], [ %[[B]], %then ]
+; CHECK-NEXT: %[[HANDLE_IDX:.*]] = phi i32 [ 0, %entry ], [ 1, %then ]
+; CHECK-NEXT: %[[OFFSET:.*]] = phi i32 [ 0, %entry ], [ 4, %then ]
+; CHECK-NEXT: %[[HANDLE:.*]] = call target("dx.RawBuffer", %struct.S, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_s_struct.Ss_1_0t(i32 2, i32 0, i32 -1, i32 %[[HANDLE_IDX]], ptr @OutArr.str)
+; CHECK-NEXT: %[[LOAD:.*]] = call { i32, i1 } @llvm.dx.resource.load.rawbuffer.i32.tdx.RawBuffer_s_struct.Ss_1_0t(target("dx.RawBuffer", %struct.S, 1, 0) %[[HANDLE]], i32 %[[ELEMENT]], i32 %[[OFFSET]])
+; CHECK-NEXT: %[[VALUE:.*]] = extractvalue { i32, i1 } %[[LOAD]], 0
+; CHECK-NEXT: ret i32 %[[VALUE]]
+ %ptr = phi ptr [ %ptr0, %entry ], [ %field1, %then ]
+ %value = load i32, ptr %ptr
+ ret i32 %value
+}
+
+; CHECK-LABEL: define i32 @gep_select_one_branch(
+; CHECK-SAME: i1 %[[COND:.*]], i32 %[[A:.*]], i32 %[[B:.*]])
+define i32 @gep_select_one_branch(i1 %cond, i32 %a, i32 %b) {
+entry:
+; CHECK: entry:
+; CHECK-NEXT: %[[ELEMENT:.*]] = select i1 %[[COND]], i32 %[[A]], i32 %[[B]]
+; CHECK-NEXT: %[[HANDLE_IDX:.*]] = select i1 %[[COND]], i32 0, i32 1
+; CHECK-NEXT: %[[OFFSET:.*]] = select i1 %[[COND]], i32 0, i32 4
+; CHECK-NEXT: %[[HANDLE:.*]] = call target("dx.RawBuffer", %struct.S, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_s_struct.Ss_1_0t(i32 2, i32 0, i32 -1, i32 %[[HANDLE_IDX]], ptr @OutArr.str)
+; CHECK-NEXT: %[[LOAD:.*]] = call { i32, i1 } @llvm.dx.resource.load.rawbuffer.i32.tdx.RawBuffer_s_struct.Ss_1_0t(target("dx.RawBuffer", %struct.S, 1, 0) %[[HANDLE]], i32 %[[ELEMENT]], i32 %[[OFFSET]])
+; CHECK-NEXT: %[[VALUE:.*]] = extractvalue { i32, i1 } %[[LOAD]], 0
+; CHECK-NEXT: ret i32 %[[VALUE]]
+ %handle0 = call target("dx.RawBuffer", %struct.S, 1, 0) @llvm.dx.resource.handlefromimplicitbinding(i32 2, i32 0, i32 -1, i32 0, ptr @OutArr.str)
+ %ptr0 = call ptr @llvm.dx.resource.getpointer(target("dx.RawBuffer", %struct.S, 1, 0) %handle0, i32 %a)
+ %handle1 = call target("dx.RawBuffer", %struct.S, 1, 0) @llvm.dx.resource.handlefromimplicitbinding(i32 2, i32 0, i32 -1, i32 1, ptr @OutArr.str)
+ %ptr1 = call ptr @llvm.dx.resource.getpointer(target("dx.RawBuffer", %struct.S, 1, 0) %handle1, i32 %b)
+ %field1 = getelementptr %struct.S, ptr %ptr1, i32 0, i32 1
+ %ptr = select i1 %cond, ptr %ptr0, ptr %field1
+ %value = load i32, ptr %ptr
+ ret i32 %value
+}
+
+; CHECK-LABEL: define <3 x i32> @basepointer_phi(
+; CHECK-SAME: i1 %[[COND:.*]])
+define <3 x i32> @basepointer_phi(i1 %cond) {
+entry:
+ %handle0 = call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefromimplicitbinding(i32 1, i32 0, i32 2, i32 0, ptr @CBArr.str)
+ %ptr0 = call ptr addrspace(2) @llvm.dx.resource.getbasepointer(target("dx.CBuffer", %__cblayout_CB) %handle0)
+; CHECK: br i1 %[[COND]], label %then, label %merge
+ br i1 %cond, label %then, label %merge
+
+then:
+ %handle1 = call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefromimplicitbinding(i32 1, i32 0, i32 2, i32 1, ptr @CBArr.str)
+ %ptr1 = call ptr addrspace(2) @llvm.dx.resource.getbasepointer(target("dx.CBuffer", %__cblayout_CB) %handle1)
+; CHECK: br label %merge
+ br label %merge
+
+merge:
+; CHECK: merge:
+; CHECK-NEXT: %[[HANDLE_IDX:.*]] = phi i32 [ 0, %entry ], [ 1, %then ]
+; CHECK-NEXT: %[[HANDLE:.*]] = call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBst(i32 1, i32 0, i32 2, i32 %[[HANDLE_IDX]], ptr @CBArr.str)
+; CHECK-NEXT: %[[LOAD:.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.i32.i32.i32.i32.tdx.CBuffer_s___cblayout_CBst(target("dx.CBuffer", %__cblayout_CB) %[[HANDLE]], i32 1)
+; CHECK-NEXT: %[[X:.*]] = extractvalue { i32, i32, i32, i32 } %[[LOAD]], 0
+; CHECK-NEXT: %[[Y:.*]] = extractvalue { i32, i32, i32, i32 } %[[LOAD]], 1
+; CHECK-NEXT: %[[Z:.*]] = extractvalue { i32, i32, i32, i32 } %[[LOAD]], 2
+; CHECK-NEXT: %[[V0:.*]] = insertelement <3 x i32> poison, i32 %[[X]], i32 0
+; CHECK-NEXT: %[[V1:.*]] = insertelement <3 x i32> %[[V0]], i32 %[[Y]], i32 1
+; CHECK-NEXT: %[[V2:.*]] = insertelement <3 x i32> %[[V1]], i32 %[[Z]], i32 2
+; CHECK-NEXT: ret <3 x i32> %[[V2]]
+ %ptr = phi ptr addrspace(2) [ %ptr0, %entry ], [ %ptr1, %then ]
+ %row1 = getelementptr i8, ptr addrspace(2) %ptr, i32 16
+ %value = load <3 x i32>, ptr addrspace(2) %row1, align 16
+ ret <3 x i32> %value
+}
+
+; CHECK-LABEL: define <3 x i32> @basepointer_phi_variable_row(
+; CHECK-SAME: i1 %[[COND:.*]], i32 %[[ROW:.*]])
+define <3 x i32> @basepointer_phi_variable_row(i1 %cond, i32 %row) {
+entry:
+ %handle0 = call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefromimplicitbinding(i32 1, i32 0, i32 2, i32 0, ptr @CBArr.str)
+ %ptr0 = call ptr addrspace(2) @llvm.dx.resource.getbasepointer(target("dx.CBuffer", %__cblayout_CB) %handle0)
+; CHECK: br i1 %[[COND]], label %then, label %merge
+ br i1 %cond, label %then, label %merge
+
+then:
+ %handle1 = call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefromimplicitbinding(i32 1, i32 0, i32 2, i32 1, ptr @CBArr.str)
+ %ptr1 = call ptr addrspace(2) @llvm.dx.resource.getbasepointer(target("dx.CBuffer", %__cblayout_CB) %handle1)
+; CHECK: br label %merge
+ br label %merge
+
+merge:
+; CHECK: merge:
+; CHECK-NEXT: %[[HANDLE_IDX:.*]] = phi i32 [ 0, %entry ], [ 1, %then ]
+; CHECK-NEXT: %[[HANDLE:.*]] = call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBst(i32 1, i32 0, i32 2, i32 %[[HANDLE_IDX]], ptr @CBArr.str)
+; CHECK-NEXT: %[[LOAD:.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.i32.i32.i32.i32.tdx.CBuffer_s___cblayout_CBst(target("dx.CBuffer", %__cblayout_CB) %[[HANDLE]], i32 %[[ROW]])
+ %ptr = phi ptr addrspace(2) [ %ptr0, %entry ], [ %ptr1, %then ]
+ %rowptr = getelementptr %__cblayout_CB, ptr addrspace(2) %ptr, i32 %row
+ %value = load <3 x i32>, ptr addrspace(2) %rowptr, align 16
+ ret <3 x i32> %value
+}
+
+; CHECK-LABEL: define void @cb_phi_handle(
+; CHECK-SAME: ptr %[[DST:.*]], i1 %[[COND:.*]], i32 %[[IDX:.*]])
+define void @cb_phi_handle(ptr %dst, i1 %cond, i32 %idx) {
+entry:
+ %h0 = call target("dx.CBuffer", %__cblayout_CB2) @llvm.dx.resource.handlefromimplicitbinding(i32 1, i32 0, i32 2, i32 0, ptr @CB.str)
+ %p0 = call ptr addrspace(2) @llvm.dx.resource.getpointer(target("dx.CBuffer", %__cblayout_CB2) %h0, i32 0)
+ br i1 %cond, label %if.then, label %main
+
+if.then:
+ %h1 = call target("dx.CBuffer", %__cblayout_CB2) @llvm.dx.resource.handlefromimplicitbinding(i32 1, i32 0, i32 2, i32 1, ptr @CB.str)
+ %p1 = call ptr addrspace(2) @llvm.dx.resource.getpointer(target("dx.CBuffer", %__cblayout_CB2) %h1, i32 0)
+ br label %main
+
+main:
+; CHECK: main:
+; CHECK-NEXT: %[[HANDLE_IDX:.*]] = phi i32 [ 0, %entry ], [ 1, %if.then ]
+; CHECK-NEXT: %[[HANDLE:.*]] = call target("dx.CBuffer", %__cblayout_CB2) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CB2st(i32 1, i32 0, i32 2, i32 %[[HANDLE_IDX]], ptr @CB.str)
+; CHECK-NEXT: %[[LOAD:.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.i32.i32.i32.i32.tdx.CBuffer_s___cblayout_CB2st(target("dx.CBuffer", %__cblayout_CB2) %[[HANDLE]], i32 %[[IDX]])
+ %pp = phi ptr addrspace(2) [ %p0, %entry ], [ %p1, %if.then ]
+ %gep = getelementptr <{ <3 x i32>, target("dx.Padding", 4) }>, ptr addrspace(2) %pp, i32 %idx
+ %ld = load <3 x i32>, ptr addrspace(2) %gep, align 16
+ %e = extractelement <3 x i32> %ld, i32 0
+ store i32 %e, ptr %dst, align 4
+ ret void
+}
More information about the llvm-commits
mailing list