[llvm] [DirectX] Avoid precalculating GEPs in DXILResourceAccess (PR #172720)

Helena Kotas via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 6 22:54:24 PST 2026


================
@@ -0,0 +1,95 @@
+; RUN: opt -S -dxil-resource-access %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.4-compute"
+
+; struct S {
+;   double d;
+;   uint4 v;
+; };
+%struct.S = type <{ double, <4 x i32> }>
+
+; struct T {
+;   uint x;
+;   S s[16];
+;   uint y;
+; };
+%struct.T = type { i32, [16 x %struct.S], i32 }
+
+; CHECK-LABEL: define void @store_offset_i32
+define void @store_offset_i32(i32 %idx, i32 %data) {
+  %buffer = call target("dx.RawBuffer", %struct.S, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+
+  ;; StructuredBuffer<S> In;
+  ;; In[0].v[idx] = data;
+  ;
+  ; CHECK: [[MUL:%.*]] = mul i32 %idx, 4
+  ; CHECK: [[ADD:%.*]] = add i32 [[MUL]], 8
+  ; CHECK: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_s_struct.Ss_0_0t.i32(target("dx.RawBuffer", %struct.S, 0, 0) %buffer, i32 0, i32 [[ADD]], i32 %data)
+  %ptr = call ptr @llvm.dx.resource.getpointer(
+      target("dx.RawBuffer", %struct.S, 0, 0) %buffer, i32 0)
+  %s.i = getelementptr inbounds nuw i8, ptr %ptr, i32 8
+  %v.i = getelementptr i32, ptr %s.i, i32 %idx
+  store i32 %data, ptr %v.i
+
+  ret void
+}
+
+; CHECK-LABEL: define void @store_double
+define void @store_double(i32 %idx, double %data) {
+  %buffer = call target("dx.RawBuffer", <4 x double>, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+
+  ;; StructuredBuffer<double4> In;
+  ;; In[0][idx] = data;
+  ;
+  ; CHECK: [[MUL:%.*]] = mul i32 %idx, 8
+  ; CHECK: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_v4f64_0_0t.f64(target("dx.RawBuffer", <4 x double>, 0, 0) %buffer, i32 0, i32 [[MUL]], double %data)
+  %ptr = call ptr @llvm.dx.resource.getpointer(
+      target("dx.RawBuffer", <4 x double>, 0, 0) %buffer, i32 0)
+  %v.i = getelementptr double, ptr %ptr, i32 %idx
+  store double %data, ptr %v.i
+
+  ret void
+}
+
+; CHECK-LABEL: define void @store_half
+define void @store_half(i32 %idx, half %data) {
+  %buffer = call target("dx.RawBuffer", <4 x half>, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+
+  ;; StructuredBuffer<half4> In;
+  ;; In[0][idx] = data;
+  ;
+  ; CHECK: [[MUL:%.*]] = mul i32 %idx, 2
+  ; CHECK: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_v4f16_0_0t.f16(target("dx.RawBuffer", <4 x half>, 0, 0) %buffer, i32 0, i32 [[MUL]], half %data)
+  %ptr = call ptr @llvm.dx.resource.getpointer(
+      target("dx.RawBuffer", <4 x half>, 0, 0) %buffer, i32 0)
+  %v.i = getelementptr half, ptr %ptr, i32 %idx
+  store half %data, ptr %v.i
+
+  ret void
+}
+
+; CHECK-LABEL: define void @store_nested
+define void @store_nested(i32 %idx, i32 %arrayidx, i32 %vecidx, i32 %data) {
+  %buffer = call target("dx.RawBuffer", %struct.T, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+
+  ;; StructuredBuffer<T> In;
+  ;; In[idx].s[arrayidx].v[vecidx];
+  ;
+  ; CHECK: [[MUL0:%.*]] = mul i32 %vecidx, 4
+  ; CHECK: [[ADD0:%.*]] = add i32 [[MUL0]], 1
+  ; CHECK: [[MUL1:%.*]] = mul i32 %arrayidx, 24
+  ; CHECK: [[ADD1:%.*]] = add i32 [[ADD0]], [[MUL1]]
+  ; CHECK: call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_s_struct.Ts_0_0t.i32(target("dx.RawBuffer", %struct.T, 0, 0) %buffer, i32 %idx, i32 [[ADD1]], i32 %data)
+  %ptr = call ptr @llvm.dx.resource.getpointer(
+      target("dx.RawBuffer", %struct.T, 0, 0) %buffer, i32 %idx)
+  %s.i = getelementptr inbounds nuw %struct.S, ptr %ptr, i32 %arrayidx
+  %v.i = getelementptr inbounds nuw i8, ptr %s.i, i32 12
----------------
hekota wrote:

Are these the GEPs that Clang generates? At first I thought this is wrong and that the GEPs should be
```
  %t.i = getelementptr inbounds nuw i8, ptr %ptr, i32 4       ; skip over uint x;
  %s.i = getelementptr inbounds nuw %struct.S, ptr %t.i, i32 %arrayidx
  %v.i = getelementptr inbounds nuw i8, ptr %s.i, i32 8       ; skip over double d;
```

But then I realized the resulting offset is the same. :)

https://github.com/llvm/llvm-project/pull/172720


More information about the llvm-commits mailing list