Justin Bogner c3039a7dc5
[DirectX] Avoid precalculating GEPs in DXILResourceAccess (#172720)
Instead of trying to precalculate GEP offsets ahead of time and then
process resource accesses based off of these offsets, traverse the GEP
chain inline for each access. This makes it easier to get the types
correct when translating GEPs for cbuffer and structured buffer
accesses, which in turn lets us access individual elements of those
structures directly.

Fixes #160208, #164517, and #169430
2025-12-18 22:15:12 +00:00

96 lines
3.5 KiB
LLVM

; 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
%i = getelementptr i32, ptr %v.i, i32 %vecidx
store i32 %data, ptr %i
ret void
}