[llvm] [DirectX] Disallow ElementIndex for raw buffer accesses (PR #173320)
Justin Bogner via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 23 12:31:01 PST 2025
https://github.com/bogner updated https://github.com/llvm/llvm-project/pull/173320
>From 5b1cdc339582062fab6f6a87768758059912d19d Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Mon, 22 Dec 2025 15:19:53 -0700
Subject: [PATCH 1/3] [DirectX] Disallow ElementIndex for raw buffer accesses
Raw (as in ByteAddress) buffer accesses in DXIL must specify
ElementIndex as undef, and Structured buffer accesses must specify a
value. Ensure that we do this correctly in DXILResourceAccess, and
enforce that the operations are valid in DXILOpLowering.
Fixes #173316
---
llvm/docs/DirectX/DXILResources.rst | 11 ++-
llvm/lib/Target/DirectX/DXILOpLowering.cpp | 27 +++++++
.../lib/Target/DirectX/DXILResourceAccess.cpp | 47 ++++++++---
llvm/test/CodeGen/DirectX/BufferLoad-sm61.ll | 4 +-
llvm/test/CodeGen/DirectX/BufferStore-sm61.ll | 8 +-
llvm/test/CodeGen/DirectX/RawBuffer-errors.ll | 78 +++++++++++++++++++
llvm/test/CodeGen/DirectX/RawBufferLoad.ll | 12 +--
llvm/test/CodeGen/DirectX/RawBufferStore.ll | 12 +--
.../DirectX/ResourceAccess/load_rawbuffer.ll | 6 +-
.../DirectX/ResourceAccess/store_rawbuffer.ll | 6 +-
10 files changed, 174 insertions(+), 37 deletions(-)
create mode 100644 llvm/test/CodeGen/DirectX/RawBuffer-errors.ll
diff --git a/llvm/docs/DirectX/DXILResources.rst b/llvm/docs/DirectX/DXILResources.rst
index db7d4a4342eb7..fb8d6fa580c67 100644
--- a/llvm/docs/DirectX/DXILResources.rst
+++ b/llvm/docs/DirectX/DXILResources.rst
@@ -402,6 +402,11 @@ which matches DXIL. Unlike in the `RawBufferLoad`_ operation, we do not need
arguments for the mask/type size and alignment, since we can calculate these
from the return type of the load during lowering.
+Note that RawBuffer loads represent either "structured" accesses, as in HLSL's
+StructuredBuffer<T>, or a "raw" access, as in HLSL's "ByteAddressBuffer". The
+`%offset` parameter is only used for structured accesses, and *must* be
+`poison` for raw accesses.
+
.. _RawBufferLoad: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#rawbufferload
.. list-table:: ``@llvm.dx.resource.load.rawbuffer``
@@ -442,7 +447,7 @@ Examples:
@llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_i8_0_0_0t(
target("dx.RawBuffer", i8, 0, 0, 0) %buffer,
i32 %byte_offset,
- i32 0)
+ i32 poison)
; float4
%ret = call {<4 x float>, i1}
@@ -454,7 +459,7 @@ Examples:
@llvm.dx.resource.load.rawbuffer.v4f32.tdx.RawBuffer_i8_0_0_0t(
target("dx.RawBuffer", i8, 0, 0, 0) %buffer,
i32 %byte_offset,
- i32 0)
+ i32 poison)
; struct S0 { float4 f; int4 i; };
%ret = call {<4 x float>, i1}
@@ -488,7 +493,7 @@ Examples:
@llvm.dx.resource.load.rawbuffer.v4i64.tdx.RawBuffer_i8_0_0t(
target("dx.RawBuffer", i8, 0, 0, 0) %buffer,
i32 %byte_offset,
- i32 0)
+ i32 poison)
Stores
------
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index e46a393e50906..d1cc2db59190f 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -272,6 +272,21 @@ class OpLowerer {
return false;
}
+ Error validateRawBufferElementIndex(Value *Resource, Value *ElementIndex) {
+ bool IsStruct = cast<RawBufferExtType>(Resource->getType())->isStructured();
+ bool IsPoison = isa<PoisonValue>(ElementIndex);
+
+ if (IsStruct && IsPoison)
+ return make_error<StringError>(
+ "Element index of structured buffer may not be poison",
+ inconvertibleErrorCode());
+ else if (!IsStruct && !IsPoison)
+ return make_error<StringError>(
+ "Element index of raw buffer must be poison",
+ inconvertibleErrorCode());
+ return Error::success();
+ }
+
[[nodiscard]] bool lowerToCreateHandle(Function &F) {
IRBuilder<> &IRB = OpBuilder.getIRB();
Type *Int8Ty = IRB.getInt8Ty();
@@ -560,6 +575,11 @@ class OpLowerer {
Value *Align =
ConstantInt::get(Int32Ty, DL.getPrefTypeAlign(ScalarTy).value());
+ if (Error E = validateRawBufferElementIndex(CI->getOperand(0), Index1))
+ return E;
+ if (isa<PoisonValue>(Index1))
+ Index1 = UndefValue::get(Index1->getType());
+
Expected<CallInst *> OpCall =
MMDI.DXILVersion >= VersionTuple(1, 2)
? OpBuilder.tryCreateOp(OpCode::RawBufferLoad,
@@ -671,6 +691,13 @@ class OpLowerer {
Value *Index0 = CI->getArgOperand(1);
Value *Index1 = IsRaw ? CI->getArgOperand(2) : UndefValue::get(Int32Ty);
+ if (IsRaw) {
+ if (Error E = validateRawBufferElementIndex(CI->getOperand(0), Index1))
+ return E;
+ if (isa<PoisonValue>(Index1))
+ Index1 = UndefValue::get(Index1->getType());
+ }
+
Value *Data = CI->getArgOperand(IsRaw ? 3 : 2);
Type *DataTy = Data->getType();
Type *ScalarTy = DataTy->getScalarType();
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index 37a7c0f572c69..28d1ffb7ca6f0 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -120,19 +120,33 @@ static void createTypedBufferStore(IntrinsicInst *II, StoreInst *SI,
SI->replaceAllUsesWith(Inst);
}
-static void createRawStore(IntrinsicInst *II, StoreInst *SI) {
+static void createRawStore(IntrinsicInst *II, StoreInst *SI,
+ dxil::ResourceTypeInfo &RTI) {
const DataLayout &DL = SI->getDataLayout();
IRBuilder<> Builder(SI);
Value *V = SI->getValueOperand();
+ assert(!V->getType()->isAggregateType() &&
+ "Resource store should be scalar or vector type");
+
+ Value *Index = II->getOperand(1);
// The offset for the rawbuffer load and store ops is always in bytes.
uint64_t AccessSize = 1;
Value *Offset =
traverseGEPOffsets(DL, Builder, SI->getPointerOperand(), AccessSize);
- // TODO: break up larger types
- auto *Inst = Builder.CreateIntrinsic(
- Builder.getVoidTy(), Intrinsic::dx_resource_store_rawbuffer,
- {II->getOperand(0), II->getOperand(1), Offset, V});
+
+ // For raw buffer (ie, HLSL's ByteAddressBuffer), we need to fold the access
+ // entirely into the index.
+ if (!RTI.isStruct()) {
+ auto *ConstantOffset = dyn_cast<ConstantInt>(Offset);
+ if (!ConstantOffset || !ConstantOffset->isZero())
+ Index = Builder.CreateAdd(Index, Offset);
+ Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
+ }
+
+ auto *Inst = Builder.CreateIntrinsic(Builder.getVoidTy(),
+ Intrinsic::dx_resource_store_rawbuffer,
+ {II->getOperand(0), Index, Offset, V});
SI->replaceAllUsesWith(Inst);
}
@@ -143,7 +157,7 @@ static void createStoreIntrinsic(IntrinsicInst *II, StoreInst *SI,
return createTypedBufferStore(II, SI, RTI);
case dxil::ResourceKind::RawBuffer:
case dxil::ResourceKind::StructuredBuffer:
- return createRawStore(II, SI);
+ return createRawStore(II, SI, RTI);
case dxil::ResourceKind::Texture1D:
case dxil::ResourceKind::Texture2D:
case dxil::ResourceKind::Texture2DMS:
@@ -198,20 +212,33 @@ static void createTypedBufferLoad(IntrinsicInst *II, LoadInst *LI,
LI->replaceAllUsesWith(V);
}
-static void createRawLoad(IntrinsicInst *II, LoadInst *LI) {
+static void createRawLoad(IntrinsicInst *II, LoadInst *LI,
+ dxil::ResourceTypeInfo &RTI) {
const DataLayout &DL = LI->getDataLayout();
IRBuilder<> Builder(LI);
- // TODO: break up larger types
Type *LoadType = StructType::get(LI->getType(), Builder.getInt1Ty());
+ assert(!LI->getType()->isAggregateType() &&
+ "Resource load should be scalar or vector type");
+ Value *Index = II->getOperand(1);
// The offset for the rawbuffer load and store ops is always in bytes.
uint64_t AccessSize = 1;
Value *Offset =
traverseGEPOffsets(DL, Builder, LI->getPointerOperand(), AccessSize);
+
+ // For raw buffer (ie, HLSL's ByteAddressBuffer), we need to fold the access
+ // entirely into the index.
+ if (!RTI.isStruct()) {
+ auto *ConstantOffset = dyn_cast<ConstantInt>(Offset);
+ if (!ConstantOffset || !ConstantOffset->isZero())
+ Index = Builder.CreateAdd(Index, Offset);
+ Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
+ }
+
Value *V =
Builder.CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_rawbuffer,
- {II->getOperand(0), II->getOperand(1), Offset});
+ {II->getOperand(0), Index, Offset});
V = Builder.CreateExtractValue(V, {0});
LI->replaceAllUsesWith(V);
@@ -367,7 +394,7 @@ static void createLoadIntrinsic(IntrinsicInst *II, LoadInst *LI,
return createTypedBufferLoad(II, LI, RTI);
case dxil::ResourceKind::RawBuffer:
case dxil::ResourceKind::StructuredBuffer:
- return createRawLoad(II, LI);
+ return createRawLoad(II, LI, RTI);
case dxil::ResourceKind::CBuffer:
return createCBufferLoad(II, LI, RTI);
case dxil::ResourceKind::Texture1D:
diff --git a/llvm/test/CodeGen/DirectX/BufferLoad-sm61.ll b/llvm/test/CodeGen/DirectX/BufferLoad-sm61.ll
index b433bcee9029c..51c025262970c 100644
--- a/llvm/test/CodeGen/DirectX/BufferLoad-sm61.ll
+++ b/llvm/test/CodeGen/DirectX/BufferLoad-sm61.ll
@@ -25,12 +25,12 @@ define void @loadv4f32_byte(i32 %offset) {
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0_0(
i32 0, i32 0, i32 1, i32 0, ptr null)
- ; CHECK: [[DATA:%.*]] = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle %{{.*}}, i32 %offset, i32 0)
+ ; CHECK: [[DATA:%.*]] = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle %{{.*}}, i32 %offset, i32 undef)
%load = call {<4 x float>, i1}
@llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_i8_0_0_0t(
target("dx.RawBuffer", i8, 0, 0, 0) %buffer,
i32 %offset,
- i32 0)
+ i32 poison)
ret void
}
diff --git a/llvm/test/CodeGen/DirectX/BufferStore-sm61.ll b/llvm/test/CodeGen/DirectX/BufferStore-sm61.ll
index 188ac75c5d1ab..b945b6ca82513 100644
--- a/llvm/test/CodeGen/DirectX/BufferStore-sm61.ll
+++ b/llvm/test/CodeGen/DirectX/BufferStore-sm61.ll
@@ -23,10 +23,10 @@ define void @storef32_byte(i32 %offset, float %data) {
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0_0(
i32 0, i32 0, i32 1, i32 0, ptr null)
- ; CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.*}}, i32 %offset, i32 0, float %data, float undef, float undef, float undef, i8 1)
+ ; CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.*}}, i32 %offset, i32 undef, float %data, float undef, float undef, float undef, i8 1)
call void @llvm.dx.resource.store.rawbuffer.f32(
target("dx.RawBuffer", i8, 1, 0, 0) %buffer,
- i32 %offset, i32 0, float %data)
+ i32 %offset, i32 poison, float %data)
ret void
}
@@ -59,10 +59,10 @@ define void @storev4f32_byte(i32 %offset, <4 x float> %data) {
; CHECK: [[DATA1:%.*]] = extractelement <4 x float> %data, i32 1
; CHECK: [[DATA2:%.*]] = extractelement <4 x float> %data, i32 2
; CHECK: [[DATA3:%.*]] = extractelement <4 x float> %data, i32 3
- ; CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.*}}, i32 %offset, i32 0, float [[DATA0]], float [[DATA1]], float [[DATA2]], float [[DATA3]], i8 15)
+ ; CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.*}}, i32 %offset, i32 undef, float [[DATA0]], float [[DATA1]], float [[DATA2]], float [[DATA3]], i8 15)
call void @llvm.dx.resource.store.rawbuffer.v4f32(
target("dx.RawBuffer", i8, 1, 0, 0) %buffer,
- i32 %offset, i32 0, <4 x float> %data)
+ i32 %offset, i32 poison, <4 x float> %data)
ret void
}
diff --git a/llvm/test/CodeGen/DirectX/RawBuffer-errors.ll b/llvm/test/CodeGen/DirectX/RawBuffer-errors.ll
new file mode 100644
index 0000000000000..b413cf1dfe4dc
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/RawBuffer-errors.ll
@@ -0,0 +1,78 @@
+; We use llc for this test so that we don't abort after the first error.
+; RUN: not llc %s -o /dev/null 2>&1 | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+declare void @f32_user(float)
+
+; CHECK: error:
+; CHECK-SAME: in function loadrawzero
+; CHECK-SAME: Element index of raw buffer must be poison
+define void @loadrawzero(i32 %offset) "hlsl.export" {
+ %buffer = call target("dx.RawBuffer", i8, 0, 0, 0)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+
+ %load = call {float, i1}
+ @llvm.dx.resource.load.rawbuffer(
+ target("dx.RawBuffer", i8, 0, 0, 0) %buffer,
+ i32 %offset,
+ i32 0)
+ %data = extractvalue {float, i1} %load, 0
+
+ call void @f32_user(float %data)
+
+ ret void
+}
+
+; CHECK: error:
+; CHECK-SAME: in function loadstructundef
+; CHECK-SAME: Element index of structured buffer may not be poison
+define void @loadstructundef(i32 %index) "hlsl.export" {
+ %buffer = call target("dx.RawBuffer", float, 0, 0, 0)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+
+ %load = call {float, i1}
+ @llvm.dx.resource.load.rawbuffer(
+ target("dx.RawBuffer", float, 0, 0, 0) %buffer,
+ i32 %index,
+ i32 poison)
+ %data = extractvalue {float, i1} %load, 0
+ call void @f32_user(float %data)
+
+ ret void
+}
+
+; CHECK: error:
+; CHECK-SAME: in function storerawzero
+; CHECK-SAME: Element index of raw buffer must be poison
+define void @storerawzero(i32 %offset, float %data) {
+ %buffer = call target("dx.RawBuffer", i8, 1, 0, 0)
+ @llvm.dx.resource.handlefrombinding(
+ i32 0, i32 0, i32 1, i32 0, ptr null)
+
+ call void @llvm.dx.resource.store.rawbuffer(
+ target("dx.RawBuffer", i8, 1, 0, 0) %buffer,
+ i32 %offset, i32 0, float %data)
+
+ ret void
+}
+
+; CHECK: error:
+; CHECK-SAME: in function storestructundef
+; CHECK-SAME: Element index of structured buffer may not be poison
+define void @storestructundef(i32 %index, float %data) {
+ %buffer = call target("dx.RawBuffer", float, 1, 0, 0)
+ @llvm.dx.resource.handlefrombinding(
+ i32 0, i32 0, i32 1, i32 0, ptr null)
+
+ call void @llvm.dx.resource.store.rawbuffer(
+ target("dx.RawBuffer", float, 1, 0, 0) %buffer,
+ i32 %index, i32 poison, float %data)
+
+ ret void
+}
+
+declare { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_i8_0_0_0t(target("dx.RawBuffer", i8, 0, 0, 0), i32, i32)
+declare { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_f32_0_0_0t(target("dx.RawBuffer", float, 0, 0, 0), i32, i32)
+declare void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.f32(target("dx.RawBuffer", i8, 1, 0, 0), i32, i32, float)
+declare void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f32_1_0_0t.f32(target("dx.RawBuffer", float, 1, 0, 0), i32, i32, float)
diff --git a/llvm/test/CodeGen/DirectX/RawBufferLoad.ll b/llvm/test/CodeGen/DirectX/RawBufferLoad.ll
index 37260326071bb..66713ef3e7d6d 100644
--- a/llvm/test/CodeGen/DirectX/RawBufferLoad.ll
+++ b/llvm/test/CodeGen/DirectX/RawBufferLoad.ll
@@ -36,12 +36,12 @@ define void @loadf32_byte(i32 %offset) {
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0_0(
i32 0, i32 0, i32 1, i32 0, ptr null)
- ; CHECK: [[DATA:%.*]] = call %dx.types.ResRet.f32 @dx.op.rawBufferLoad.f32(i32 139, %dx.types.Handle %{{.*}}, i32 %offset, i32 0, i8 1, i32 4)
+ ; CHECK: [[DATA:%.*]] = call %dx.types.ResRet.f32 @dx.op.rawBufferLoad.f32(i32 139, %dx.types.Handle %{{.*}}, i32 %offset, i32 undef, i8 1, i32 4)
%load = call {float, i1}
@llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_i8_0_0_0t(
target("dx.RawBuffer", i8, 0, 0, 0) %buffer,
i32 %offset,
- i32 0)
+ i32 poison)
%data = extractvalue {float, i1} %load, 0
; CHECK: [[VAL:%.*]] = extractvalue %dx.types.ResRet.f32 [[DATA]], 0
@@ -85,12 +85,12 @@ define void @loadv4f32_byte(i32 %offset) {
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0_0(
i32 0, i32 0, i32 1, i32 0, ptr null)
- ; CHECK: [[DATA:%.*]] = call %dx.types.ResRet.f32 @dx.op.rawBufferLoad.f32(i32 139, %dx.types.Handle %{{.*}}, i32 %offset, i32 0, i8 15, i32 4)
+ ; CHECK: [[DATA:%.*]] = call %dx.types.ResRet.f32 @dx.op.rawBufferLoad.f32(i32 139, %dx.types.Handle %{{.*}}, i32 %offset, i32 undef, i8 15, i32 4)
%load = call {<4 x float>, i1}
@llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_i8_0_0_0t(
target("dx.RawBuffer", i8, 0, 0, 0) %buffer,
i32 %offset,
- i32 0)
+ i32 poison)
%data = extractvalue {<4 x float>, i1} %load, 0
; CHECK: extractvalue %dx.types.ResRet.f32 [[DATA]], 0
@@ -212,9 +212,9 @@ define void @loadv4f64_byte(i32 %offset) {
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0_0(
i32 0, i32 0, i32 1, i32 0, ptr null)
- ; CHECK: [[DATA:%.*]] = call %dx.types.ResRet.f64 @dx.op.rawBufferLoad.f64(i32 139, %dx.types.Handle %{{.*}}, i32 %offset, i32 0, i8 15, i32 8)
+ ; CHECK: [[DATA:%.*]] = call %dx.types.ResRet.f64 @dx.op.rawBufferLoad.f64(i32 139, %dx.types.Handle %{{.*}}, i32 %offset, i32 undef, i8 15, i32 8)
%load = call {<4 x double>, i1} @llvm.dx.resource.load.rawbuffer.v4i64(
- target("dx.RawBuffer", i8, 0, 0, 0) %buffer, i32 %offset, i32 0)
+ target("dx.RawBuffer", i8, 0, 0, 0) %buffer, i32 %offset, i32 poison)
%data = extractvalue {<4 x double>, i1} %load, 0
; CHECK: extractvalue %dx.types.ResRet.f64 [[DATA]], 0
diff --git a/llvm/test/CodeGen/DirectX/RawBufferStore.ll b/llvm/test/CodeGen/DirectX/RawBufferStore.ll
index 856f9d1034227..fa71f6d7ffcfa 100644
--- a/llvm/test/CodeGen/DirectX/RawBufferStore.ll
+++ b/llvm/test/CodeGen/DirectX/RawBufferStore.ll
@@ -22,10 +22,10 @@ define void @storef32_byte(i32 %offset, float %data) {
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0_0(
i32 0, i32 0, i32 1, i32 0, ptr null)
- ; CHECK: call void @dx.op.rawBufferStore.f32(i32 140, %dx.types.Handle %buffer_annot, i32 %offset, i32 0, float %data, float undef, float undef, float undef, i8 1, i32 4)
+ ; CHECK: call void @dx.op.rawBufferStore.f32(i32 140, %dx.types.Handle %buffer_annot, i32 %offset, i32 undef, float %data, float undef, float undef, float undef, i8 1, i32 4)
call void @llvm.dx.resource.store.rawbuffer.f32(
target("dx.RawBuffer", i8, 1, 0, 0) %buffer,
- i32 %offset, i32 0, float %data)
+ i32 %offset, i32 poison, float %data)
ret void
}
@@ -58,10 +58,10 @@ define void @storev4f32_byte(i32 %offset, <4 x float> %data) {
; CHECK: [[DATA1:%.*]] = extractelement <4 x float> %data, i32 1
; CHECK: [[DATA2:%.*]] = extractelement <4 x float> %data, i32 2
; CHECK: [[DATA3:%.*]] = extractelement <4 x float> %data, i32 3
- ; CHECK: call void @dx.op.rawBufferStore.f32(i32 140, %dx.types.Handle %buffer_annot, i32 %offset, i32 0, float [[DATA0]], float [[DATA1]], float [[DATA2]], float [[DATA3]], i8 15, i32 4)
+ ; CHECK: call void @dx.op.rawBufferStore.f32(i32 140, %dx.types.Handle %buffer_annot, i32 %offset, i32 undef, float [[DATA0]], float [[DATA1]], float [[DATA2]], float [[DATA3]], i8 15, i32 4)
call void @llvm.dx.resource.store.rawbuffer.v4f32(
target("dx.RawBuffer", i8, 1, 0, 0) %buffer,
- i32 %offset, i32 0, <4 x float> %data)
+ i32 %offset, i32 poison, <4 x float> %data)
ret void
}
@@ -135,10 +135,10 @@ define void @storev4f64_byte(i32 %offset, <4 x double> %data) {
; CHECK: [[DATA1:%.*]] = extractelement <4 x double> %data, i32 1
; CHECK: [[DATA2:%.*]] = extractelement <4 x double> %data, i32 2
; CHECK: [[DATA3:%.*]] = extractelement <4 x double> %data, i32 3
- ; CHECK: call void @dx.op.rawBufferStore.f64(i32 140, %dx.types.Handle %buffer_annot, i32 %offset, i32 0, double [[DATA0]], double [[DATA1]], double [[DATA2]], double [[DATA3]], i8 15, i32 8)
+ ; CHECK: call void @dx.op.rawBufferStore.f64(i32 140, %dx.types.Handle %buffer_annot, i32 %offset, i32 undef, double [[DATA0]], double [[DATA1]], double [[DATA2]], double [[DATA3]], i8 15, i32 8)
call void @llvm.dx.resource.store.rawbuffer.v4i64(
target("dx.RawBuffer", i8, 1, 0, 0) %buffer,
- i32 %offset, i32 0, <4 x double> %data)
+ i32 %offset, i32 poison, <4 x double> %data)
ret void
}
diff --git a/llvm/test/CodeGen/DirectX/ResourceAccess/load_rawbuffer.ll b/llvm/test/CodeGen/DirectX/ResourceAccess/load_rawbuffer.ll
index ae5e992184f4c..f3a2f6233d6eb 100644
--- a/llvm/test/CodeGen/DirectX/ResourceAccess/load_rawbuffer.ll
+++ b/llvm/test/CodeGen/DirectX/ResourceAccess/load_rawbuffer.ll
@@ -38,7 +38,7 @@ define void @loadf32_byte(i32 %offset) {
%ptr = call ptr @llvm.dx.resource.getpointer(
target("dx.RawBuffer", i8, 0, 0, 0) %buffer, i32 %offset)
- ; CHECK: %[[LOAD:.*]] = call { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_i8_0_0_0t(target("dx.RawBuffer", i8, 0, 0, 0) %buffer, i32 %offset, i32 0)
+ ; CHECK: %[[LOAD:.*]] = call { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_i8_0_0_0t(target("dx.RawBuffer", i8, 0, 0, 0) %buffer, i32 %offset, i32 poison)
; CHECK: %[[VAL:.*]] = extractvalue { float, i1 } %[[LOAD]], 0
; CHECK: call void @f32_user(float %[[VAL]])
%data = load float, ptr %ptr
@@ -76,7 +76,7 @@ define void @loadv4f32_byte(i32 %offset) {
%ptr = call ptr @llvm.dx.resource.getpointer(
target("dx.RawBuffer", i8, 0, 0, 0) %buffer, i32 %offset)
- ; CHECK: %[[LOAD:.*]] = call { <4 x float>, i1 } @llvm.dx.resource.load.rawbuffer.v4f32.tdx.RawBuffer_i8_0_0_0t(target("dx.RawBuffer", i8, 0, 0, 0) %buffer, i32 %offset, i32 0)
+ ; CHECK: %[[LOAD:.*]] = call { <4 x float>, i1 } @llvm.dx.resource.load.rawbuffer.v4f32.tdx.RawBuffer_i8_0_0_0t(target("dx.RawBuffer", i8, 0, 0, 0) %buffer, i32 %offset, i32 poison)
; CHECK: %[[VAL:.*]] = extractvalue { <4 x float>, i1 } %[[LOAD]], 0
; CHECK: call void @v4f32_user(<4 x float> %[[VAL]]
%data = load <4 x float>, ptr %ptr
@@ -157,7 +157,7 @@ define void @loadv4f64_byte(i32 %offset) {
%ptr = call ptr @llvm.dx.resource.getpointer(
target("dx.RawBuffer", i8, 0, 0, 0) %buffer, i32 %offset)
- ; CHECK: %[[LOAD:.*]] = call { <4 x double>, i1 } @llvm.dx.resource.load.rawbuffer.v4f64.tdx.RawBuffer_i8_0_0_0t(target("dx.RawBuffer", i8, 0, 0, 0) %buffer, i32 %offset, i32 0)
+ ; CHECK: %[[LOAD:.*]] = call { <4 x double>, i1 } @llvm.dx.resource.load.rawbuffer.v4f64.tdx.RawBuffer_i8_0_0_0t(target("dx.RawBuffer", i8, 0, 0, 0) %buffer, i32 %offset, i32 poison)
; CHECK: %[[VAL:.*]] = extractvalue { <4 x double>, i1 } %[[LOAD]], 0
; CHECK: call void @v4f64_user(<4 x double> %[[VAL]])
%data = load <4 x double>, ptr %ptr
diff --git a/llvm/test/CodeGen/DirectX/ResourceAccess/store_rawbuffer.ll b/llvm/test/CodeGen/DirectX/ResourceAccess/store_rawbuffer.ll
index 2ddf615be4a67..6ddb77587fb2c 100644
--- a/llvm/test/CodeGen/DirectX/ResourceAccess/store_rawbuffer.ll
+++ b/llvm/test/CodeGen/DirectX/ResourceAccess/store_rawbuffer.ll
@@ -26,7 +26,7 @@ define void @storef32_byte(i32 %offset, float %data) {
%ptr = call ptr @llvm.dx.resource.getpointer(
target("dx.RawBuffer", i8, 1, 0, 0) %buffer, i32 %offset)
- ; CHECK: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.f32(target("dx.RawBuffer", i8, 1, 0, 0) %buffer, i32 %offset, i32 0, float %data)
+ ; CHECK: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.f32(target("dx.RawBuffer", i8, 1, 0, 0) %buffer, i32 %offset, i32 poison, float %data)
store float %data, ptr %ptr
ret void
@@ -56,7 +56,7 @@ define void @storev4f32_byte(i32 %offset, <4 x float> %data) {
%ptr = call ptr @llvm.dx.resource.getpointer(
target("dx.RawBuffer", i8, 1, 0, 0) %buffer, i32 %offset)
- ; CHECK: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.v4f32(target("dx.RawBuffer", i8, 1, 0, 0) %buffer, i32 %offset, i32 0, <4 x float> %data)
+ ; CHECK: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.v4f32(target("dx.RawBuffer", i8, 1, 0, 0) %buffer, i32 %offset, i32 poison, <4 x float> %data)
store <4 x float> %data, ptr %ptr
ret void
@@ -117,7 +117,7 @@ define void @storev4f64_byte(i32 %offset, <4 x double> %data) {
%ptr = call ptr @llvm.dx.resource.getpointer(
target("dx.RawBuffer", i8, 1, 0, 0) %buffer, i32 %offset)
- ; CHECK: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.v4f64(target("dx.RawBuffer", i8, 1, 0, 0) %buffer, i32 %offset, i32 0, <4 x double> %data)
+ ; CHECK: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i8_1_0_0t.v4f64(target("dx.RawBuffer", i8, 1, 0, 0) %buffer, i32 %offset, i32 poison, <4 x double> %data)
store <4 x double> %data, ptr %ptr
ret void
>From 6aa9864049404acca06727a03eec87cf3b177d68 Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Tue, 23 Dec 2025 12:44:42 -0700
Subject: [PATCH 2/3] fixup: rename variable
---
llvm/lib/Target/DirectX/DXILOpLowering.cpp | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index d1cc2db59190f..405d55967d9d9 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -273,14 +273,15 @@ class OpLowerer {
}
Error validateRawBufferElementIndex(Value *Resource, Value *ElementIndex) {
- bool IsStruct = cast<RawBufferExtType>(Resource->getType())->isStructured();
+ bool IsStructured =
+ cast<RawBufferExtType>(Resource->getType())->isStructured();
bool IsPoison = isa<PoisonValue>(ElementIndex);
- if (IsStruct && IsPoison)
+ if (IsStructured && IsPoison)
return make_error<StringError>(
"Element index of structured buffer may not be poison",
inconvertibleErrorCode());
- else if (!IsStruct && !IsPoison)
+ else if (!IsStructured && !IsPoison)
return make_error<StringError>(
"Element index of raw buffer must be poison",
inconvertibleErrorCode());
>From 9264b83814e5b7ff48a7fbf38cc5af60622169a7 Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Tue, 23 Dec 2025 13:30:36 -0700
Subject: [PATCH 3/3] fixup: avoid else-after-return
---
llvm/lib/Target/DirectX/DXILOpLowering.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index 405d55967d9d9..0c0830cc92aa7 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -281,10 +281,12 @@ class OpLowerer {
return make_error<StringError>(
"Element index of structured buffer may not be poison",
inconvertibleErrorCode());
- else if (!IsStructured && !IsPoison)
+
+ if (!IsStructured && !IsPoison)
return make_error<StringError>(
"Element index of raw buffer must be poison",
inconvertibleErrorCode());
+
return Error::success();
}
More information about the llvm-commits
mailing list