[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