// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,DXIL // RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,SPV // NOTE: SPIRV codegen for resource methods is not yet implemented StructuredBuffer SB1 : register(t0); RWStructuredBuffer RWSB1 : register(u0); RWStructuredBuffer RWSB2 : register(u1); AppendStructuredBuffer ASB : register(u2); ConsumeStructuredBuffer CSB : register(u3); // DXIL: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", float, 0, 0) } // DXIL: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0), target("dx.RawBuffer", float, 1, 0) } // DXIL: %"class.hlsl::RWStructuredBuffer.0" = type { target("dx.RawBuffer", <4 x i32>, 1, 0), target("dx.RawBuffer", <4 x i32>, 1, 0) } // DXIL: %"class.hlsl::AppendStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0), target("dx.RawBuffer", float, 1, 0) } // DXIL: %"class.hlsl::ConsumeStructuredBuffer" = type { target("dx.RawBuffer", double, 1, 0), target("dx.RawBuffer", double, 1, 0) } export int TestIncrementCounter() { return RWSB1.IncrementCounter(); } // CHECK: define noundef i32 @TestIncrementCounter()() // CHECK: %[[TOK:.*]] = call token @llvm.experimental.convergence.entry() // CHECK: call noundef i32 @hlsl::RWStructuredBuffer::IncrementCounter()(ptr {{.*}} @RWSB1) {{.*}} [ "convergencectrl"(token %[[TOK]]) ] // CHECK: ret // CHECK: define {{.*}} noundef i32 @hlsl::RWStructuredBuffer::IncrementCounter()(ptr {{.*}} %this) // CHECK: %__counter_handle = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer", ptr %{{.*}}, i32 0, i32 1 // DXIL-NEXT: %[[COUNTER_HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 0), ptr %__counter_handle // DXIL-NEXT: %[[COUNTER:.*]] = call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %[[COUNTER_HANDLE]], i8 1) // CHECK-NEXT: ret i32 %[[COUNTER]] export int TestDecrementCounter() { return RWSB2.DecrementCounter(); } // CHECK: define {{.*}} i32 @TestDecrementCounter()() // CHECK: %[[TOK:.*]] = call token @llvm.experimental.convergence.entry() // CHECK: call noundef i32 @hlsl::RWStructuredBuffer::DecrementCounter()(ptr {{.*}} @RWSB2) {{.*}} [ "convergencectrl"(token %[[TOK]]) ] // CHECK: ret // CHECK: define {{.*}} noundef i32 @hlsl::RWStructuredBuffer::DecrementCounter()(ptr {{.*}} %this) // CHECK: %__counter_handle = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer.0", ptr %{{.*}}, i32 0, i32 1 // DXIL-NEXT: %[[COUNTER_HANDLE:.*]] = load target("dx.RawBuffer", <4 x i32>, 1, 0), ptr %__counter_handle // DXIL-NEXT: %[[COUNTER:.*]] = call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_v4i32_1_0t(target("dx.RawBuffer", <4 x i32>, 1, 0) %[[COUNTER_HANDLE]], i8 -1) // CHECK-NEXT: ret i32 %[[COUNTER]] export void TestAppend(float value) { ASB.Append(value); } // CHECK: define void @TestAppend(float)(float {{.*}} %value) // CHECK: %[[TOK:.*]] = call token @llvm.experimental.convergence.entry() // CHECK: call void @hlsl::AppendStructuredBuffer::Append(float)(ptr {{.*}} @ASB, float noundef nofpclass(nan inf) %[[#]]) {{.*}} [ "convergencectrl"(token %[[TOK]]) ] // CHECK: ret void // CHECK: define {{.*}} void @hlsl::AppendStructuredBuffer::Append(float)(ptr {{.*}} %this, float noundef nofpclass(nan inf) %value) // CHECK: %[[VALUE:.*]] = load float, ptr %value.addr // CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::AppendStructuredBuffer", ptr %{{.*}}, i32 0, i32 0 // DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 0), ptr %__handle // CHECK-NEXT: %__counter_handle = getelementptr inbounds nuw %"class.hlsl::AppendStructuredBuffer", ptr %{{.*}}, i32 0, i32 1 // DXIL-NEXT: %[[COUNTER_HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 0), ptr %__counter_handle // DXIL-NEXT: %[[COUNTER:.*]] = call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %[[COUNTER_HANDLE]], i8 1) // DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t.i32(target("dx.RawBuffer", float, 1, 0) %[[HANDLE]], i32 %[[COUNTER]]) // CHECK-NEXT: store float %[[VALUE]], ptr %[[PTR]] // CHECK-NEXT: ret void export double TestConsume() { return CSB.Consume(); } // CHECK: define {{.*}} double @TestConsume()() // CHECK: %[[TOK:.*]] = call token @llvm.experimental.convergence.entry() // CHECK: call {{.*}} double @hlsl::ConsumeStructuredBuffer::Consume()(ptr {{.*}} @CSB) {{.*}} [ "convergencectrl"(token %[[TOK]]) ] // CHECK: ret double // CHECK: define {{.*}} double @hlsl::ConsumeStructuredBuffer::Consume()(ptr {{.*}} %this) // CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::ConsumeStructuredBuffer", ptr %{{.*}}, i32 0, i32 0 // DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", double, 1, 0), ptr %__handle // CHECK-NEXT: %__counter_handle = getelementptr inbounds nuw %"class.hlsl::ConsumeStructuredBuffer", ptr %{{.*}}, i32 0, i32 1 // DXIL-NEXT: %[[COUNTER_HANDLE:.*]] = load target("dx.RawBuffer", double, 1, 0), ptr %__counter_handle // DXIL-NEXT: %[[COUNTER:.*]] = call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f64_1_0t(target("dx.RawBuffer", double, 1, 0) %[[COUNTER_HANDLE]], i8 -1) // DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f64_1_0t.i32(target("dx.RawBuffer", double, 1, 0) %[[HANDLE]], i32 %[[COUNTER]]) // CHECK-NEXT: %[[VAL:.*]] = load double, ptr %[[PTR]], align 8 // CHECK-NEXT: ret double %[[VAL]] export float TestLoad() { return RWSB1.Load(1) + SB1.Load(2); } // CHECK: define noundef nofpclass(nan inf) float @TestLoad()() // CHECK: %[[TOK:.*]] = call token @llvm.experimental.convergence.entry() // CHECK: call {{.*}} float @hlsl::RWStructuredBuffer::Load(unsigned int) const(ptr {{.*}} @RWSB1, i32 noundef 1) {{.*}} [ "convergencectrl"(token %[[TOK]]) ] // CHECK: call {{.*}} float @hlsl::StructuredBuffer::Load(unsigned int) const(ptr {{.*}} @SB1, i32 noundef 2) {{.*}} [ "convergencectrl"(token %[[TOK]]) ] // CHECK: add // CHECK: ret float // CHECK: define {{.*}} float @hlsl::RWStructuredBuffer::Load(unsigned int) const(ptr {{.*}} %this, i32 noundef %Index) // CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer", ptr %{{.*}}, i32 0, i32 0 // DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 0), ptr %__handle // CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr // DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t.i32(target("dx.RawBuffer", float, 1, 0) %[[HANDLE]], i32 %[[INDEX]]) // CHECK-NEXT: %[[VAL:.*]] = load float, ptr %[[PTR]] // CHECK-NEXT: ret float %[[VAL]] // CHECK: define {{.*}} float @hlsl::StructuredBuffer::Load(unsigned int) const(ptr {{.*}} %this, i32 noundef %Index) // CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %{{.*}}, i32 0, i32 0 // DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 0, 0), ptr %__handle // CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr // DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_0_0t.i32(target("dx.RawBuffer", float, 0, 0) %[[HANDLE]], i32 %[[INDEX]]) // CHECK-NEXT: %[[VAL:.*]] = load float, ptr %[[PTR]] // CHECK-NEXT: ret float %[[VAL]] export float TestLoadWithStatus() { uint s1; uint s2; float ret = RWSB1.Load(1, s1) + SB1.Load(2, s2); ret += float(s1 + s2); return ret; } // CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()() // CHECK: %[[TOK:.*]] = call token @llvm.experimental.convergence.entry() // CHECK: call {{.*}} float @hlsl::RWStructuredBuffer::Load(unsigned int, unsigned int&) const(ptr {{.*}} @RWSB1, i32 noundef 1, ptr {{.*}} %tmp) {{.*}} [ "convergencectrl"(token %[[TOK]]) ] // CHECK: call {{.*}} float @hlsl::StructuredBuffer::Load(unsigned int, unsigned int&) const(ptr {{.*}} @SB1, i32 noundef 2, ptr {{.*}} %tmp2) {{.*}} [ "convergencectrl"(token %[[TOK]]) ] // CHECK: add // CHECK: ret float // CHECK: define {{.*}} float @hlsl::RWStructuredBuffer::Load(unsigned int, unsigned int&) const(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status) // CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer", ptr %{{.*}}, i32 0, i32 0 // DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 0), ptr %__handle // CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr // CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr // DXIL-NEXT: %[[STRUCT:.*]] = call { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %[[HANDLE]], i32 %[[INDEX]], i32 0) // CHECK-NEXT: %[[VALUE:.*]] = extractvalue { float, i1 } %[[STRUCT]], 0 // CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { float, i1 } %[[STRUCT]], 1 // CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32 // CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4 // CHECK-NEXT: ret float %[[VALUE]] // CHECK: define {{.*}} float @hlsl::StructuredBuffer::Load(unsigned int, unsigned int&) const(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status) // CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %{{.*}}, i32 0, i32 0 // DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 0, 0), ptr %__handle // CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr // CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4 // DXIL-NEXT: %[[STRUCT:.*]] = call { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_f32_0_0t(target("dx.RawBuffer", float, 0, 0) %[[HANDLE]], i32 %[[INDEX]], i32 0) // CHECK-NEXT: %[[VALUE:.*]] = extractvalue { float, i1 } %[[STRUCT]], 0 // CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { float, i1 } %[[STRUCT]], 1 // CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32 // CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4 // CHECK-NEXT: ret float %[[VALUE]] export uint TestGetDimensions() { uint dim1, dim2, dim3, stride1, stride2, stride3; SB1.GetDimensions(dim1, stride1); RWSB2.GetDimensions(dim2, stride2); CSB.GetDimensions(dim3, stride3); return dim1 + dim2 + dim3 + stride1 + stride2 + stride3; } // CHECK: define noundef i32 @TestGetDimensions()() // CHECK: %[[TOK:.*]] = call token @llvm.experimental.convergence.entry() // CHECK: call void @hlsl::StructuredBuffer::GetDimensions(unsigned int&, unsigned int&)(ptr {{.*}} @SB1, ptr {{.*}}, ptr {{.*}}) {{.*}} [ "convergencectrl"(token %[[TOK]]) ] // CHECK: call void @hlsl::RWStructuredBuffer::GetDimensions(unsigned int&, unsigned int&)(ptr {{.*}} @RWSB2, ptr {{.*}}, ptr {{.*}}) {{.*}} [ "convergencectrl"(token %[[TOK]]) ] // CHECK: call void @hlsl::ConsumeStructuredBuffer::GetDimensions(unsigned int&, unsigned int&)(ptr {{.*}} @CSB, ptr {{.*}}, ptr {{.*}}) {{.*}} [ "convergencectrl"(token %[[TOK]]) ] // CHECK: add // CHECK: ret // CHECK: define {{.*}} void @hlsl::StructuredBuffer::GetDimensions(unsigned int&, unsigned int&)(ptr {{.*}}, ptr {{.*}} %numStructs, ptr {{.*}} %stride) // CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %{{.*}}, i32 0, i32 0 // CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 0, 0), ptr %__handle // DXIL-NEXT: %[[NUMSTRUCTS:.*]] = call i32 @llvm.dx.resource.getdimensions.x.tdx.RawBuffer_f32_0_0t(target("dx.RawBuffer", float, 0, 0) %[[HANDLE]]) // CHECK-NEXT: %[[NUMSTRUCTS_PTR:.*]] = load ptr, ptr %numStructs.addr // CHECK-NEXT: store i32 %[[NUMSTRUCTS]], ptr %[[NUMSTRUCTS_PTR]] // CHECK-NEXT: %[[STRIDEPTR:.*]] = load ptr, ptr %stride.addr // CHECK-NEXT: store i32 4, ptr %[[STRIDEPTR]] // CHECK-NEXT: ret void // CHECK: define {{.*}} void @hlsl::RWStructuredBuffer::GetDimensions(unsigned int&, unsigned int&)(ptr {{.*}} %this, {{.*}} %numStructs, {{.*}} %stride) // CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer.0", ptr %{{.*}}, i32 0, i32 0 // CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", <4 x i32>, 1, 0), ptr %__handle // DXIL-NEXT: %[[NUMSTRUCTS:.*]] = call i32 @llvm.dx.resource.getdimensions.x.tdx.RawBuffer_v4i32_1_0t(target("dx.RawBuffer", <4 x i32>, 1, 0) %[[HANDLE]]) // CHECK-NEXT: %[[NUMSTRUCTS_PTR:.*]] = load ptr, ptr %numStructs.addr // CHECK-NEXT: store i32 %[[NUMSTRUCTS]], ptr %[[NUMSTRUCTS_PTR]] // CHECK-NEXT: %[[STRIDEPTR:.*]] = load ptr, ptr %stride.addr // CHECK-NEXT: store i32 16, ptr %[[STRIDEPTR]] // CHECK-NEXT: ret void // CHECK: define {{.*}} void @hlsl::ConsumeStructuredBuffer::GetDimensions(unsigned int&, unsigned int&)(ptr {{.*}} %this, {{.*}} %numStructs, {{.*}} %stride) // CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::ConsumeStructuredBuffer", ptr %{{.*}}, i32 0, i32 0 // CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", double, 1, 0), ptr %__handle // DXIL-NEXT: %[[NUMSTRUCTS:.*]] = call i32 @llvm.dx.resource.getdimensions.x.tdx.RawBuffer_f64_1_0t(target("dx.RawBuffer", double, 1, 0) %[[HANDLE]]) // CHECK-NEXT: %[[NUMSTRUCTS_PTR:.*]] = load ptr, ptr %numStructs.addr // CHECK-NEXT: store i32 %[[NUMSTRUCTS]], ptr %[[NUMSTRUCTS_PTR]] // CHECK-NEXT: %[[STRIDEPTR:.*]] = load ptr, ptr %stride.addr // CHECK-NEXT: store i32 8, ptr %[[STRIDEPTR]] // CHECK-NEXT: ret void // DXIL: declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8) // DXIL: declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_v4i32_1_0t(target("dx.RawBuffer", <4 x i32>, 1, 0), i8) // DXIL: declare ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t.i32(target("dx.RawBuffer", float, 1, 0), i32) // DXIL: declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f64_1_0t(target("dx.RawBuffer", double, 1, 0), i8) // DXIL: declare ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f64_1_0t.i32(target("dx.RawBuffer", double, 1, 0), i32) // DXIL: declare ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_0_0t.i32(target("dx.RawBuffer", float, 0, 0), i32) // DXIL: declare i32 @llvm.dx.resource.getdimensions.x.tdx.RawBuffer_f32_0_0t(target("dx.RawBuffer", float, 0, 0)) // DXIL: declare i32 @llvm.dx.resource.getdimensions.x.tdx.RawBuffer_v4i32_1_0t(target("dx.RawBuffer", <4 x i32>, 1, 0)) // DXIL: declare i32 @llvm.dx.resource.getdimensions.x.tdx.RawBuffer_f64_1_0t(target("dx.RawBuffer", double, 1, 0))