blob: e669bedea763fd658a87baacf67c4746072971e3 [file] [edit]
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/hlsl/writer/raise/array_offset_from_uniform.h"
#include <utility>
#include "src/tint/lang/core/ir/transform/helper_test.h"
#include "src/tint/lang/hlsl/ir/member_builtin_call.h"
#include "src/tint/lang/hlsl/type/byte_address_buffer.h"
namespace tint::hlsl::writer::raise {
namespace {
using namespace tint::core::fluent_types; // NOLINT
using namespace tint::core::number_suffixes; // NOLINT
struct IR_ArrayOffsetFromUniformTest : core::ir::transform::TransformTest {
IR_ArrayOffsetFromUniformTest() { capabilities = kArrayOffsetFromUniformCapabilities; }
};
// Test that offset is added to byte_address_buffer.Load
TEST_F(IR_ArrayOffsetFromUniformTest, Basic) {
auto* byte_address_buffer_readonly_ty =
ty.Get<hlsl::type::ByteAddressBuffer>(core::Access::kRead);
auto* buffer = b.Var("buffer", byte_address_buffer_readonly_ty);
buffer->SetBindingPoint(0, 0);
mod.root_block->Append(buffer);
auto* func = b.ComputeFunction("foo");
b.Append(func->Block(), [&] {
auto base_offset = u32(42);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.u32(), hlsl::BuiltinFn::kLoad, buffer,
base_offset);
b.Return(func);
});
auto* src = R"(
$B1: { # root
%buffer:hlsl.byte_address_buffer<read> = var undef @binding_point(0, 0)
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%3:u32 = %buffer.Load 42u
ret
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
$B1: { # root
%buffer:hlsl.byte_address_buffer<read> = var undef @binding_point(0, 0)
%tint_storage_buffer_dynamic_offsets:ptr<uniform, array<u32, 21>, read> = var undef @binding_point(1, 2)
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%4:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 20u
%5:u32 = load %4
%6:u32 = add 42u, %5
%7:u32 = %buffer.Load %6
ret
}
}
)";
std::unordered_map<BindingPoint, uint32_t> bindpoint_to_offset_index;
bindpoint_to_offset_index[{0, 0}] = 20;
Run(ArrayOffsetFromUniform, BindingPoint{1, 2}, bindpoint_to_offset_index);
EXPECT_EQ(expect, str());
}
// Test that nothing changes if no bindpoint_to_offset_index is provided
TEST_F(IR_ArrayOffsetFromUniformTest, NoModify_EmptyBindpointToOffsetIndex) {
auto* byte_address_buffer_readonly_ty =
ty.Get<hlsl::type::ByteAddressBuffer>(core::Access::kRead);
auto* buffer = b.Var("buffer", byte_address_buffer_readonly_ty);
buffer->SetBindingPoint(0, 0);
mod.root_block->Append(buffer);
auto* func = b.ComputeFunction("foo");
b.Append(func->Block(), [&] {
auto base_offset = u32(42);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.u32(), hlsl::BuiltinFn::kLoad, buffer,
base_offset);
b.Return(func);
});
auto* src = R"(
$B1: { # root
%buffer:hlsl.byte_address_buffer<read> = var undef @binding_point(0, 0)
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%3:u32 = %buffer.Load 42u
ret
}
}
)";
EXPECT_EQ(src, str());
auto* expect = src;
std::unordered_map<BindingPoint, uint32_t> bindpoint_to_offset_index;
Run(ArrayOffsetFromUniform, BindingPoint{1, 2}, bindpoint_to_offset_index);
EXPECT_EQ(expect, str());
}
// Test that nothing changes if no bindpoint_to_offset_index is provided
TEST_F(IR_ArrayOffsetFromUniformTest, NoModify_NoMatchingBindpointToOffsetIndex) {
auto* byte_address_buffer_readonly_ty =
ty.Get<hlsl::type::ByteAddressBuffer>(core::Access::kRead);
auto* buffer = b.Var("buffer", byte_address_buffer_readonly_ty);
buffer->SetBindingPoint(0, 0);
mod.root_block->Append(buffer);
auto* func = b.ComputeFunction("foo");
b.Append(func->Block(), [&] {
auto base_offset = u32(42);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.u32(), hlsl::BuiltinFn::kLoad, buffer,
base_offset);
b.Return(func);
});
auto* src = R"(
$B1: { # root
%buffer:hlsl.byte_address_buffer<read> = var undef @binding_point(0, 0)
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%3:u32 = %buffer.Load 42u
ret
}
}
)";
EXPECT_EQ(src, str());
auto* expect = src;
std::unordered_map<BindingPoint, uint32_t> bindpoint_to_offset_index;
bindpoint_to_offset_index[{0, 1}] = 20; // Doesn't match binding point
Run(ArrayOffsetFromUniform, BindingPoint{1, 2}, bindpoint_to_offset_index);
EXPECT_EQ(expect, str());
}
// Test that nothing changes if we call a builtin that takes a byte_address_buffer but no offset
TEST_F(IR_ArrayOffsetFromUniformTest, NoModify_ByteAddressBufferBuiltinWithNoOffsetParam) {
auto* byte_address_buffer_readonly_ty =
ty.Get<hlsl::type::ByteAddressBuffer>(core::Access::kRead);
auto* buffer = b.Var("buffer", byte_address_buffer_readonly_ty);
buffer->SetBindingPoint(0, 0);
mod.root_block->Append(buffer);
auto* func = b.ComputeFunction("foo");
b.Append(func->Block(), [&] {
auto* v = b.Var("width", ty.ptr<function, u32, read_write>());
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kGetDimensions,
buffer, v);
b.Return(func);
});
auto* src = R"(
$B1: { # root
%buffer:hlsl.byte_address_buffer<read> = var undef @binding_point(0, 0)
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%width:ptr<function, u32, read_write> = var undef
%4:void = %buffer.GetDimensions %width
ret
}
}
)";
EXPECT_EQ(src, str());
auto* expect = src;
std::unordered_map<BindingPoint, uint32_t> bindpoint_to_offset_index;
bindpoint_to_offset_index[{0, 0}] = 20;
Run(ArrayOffsetFromUniform, BindingPoint{1, 2}, bindpoint_to_offset_index);
EXPECT_EQ(expect, str());
}
TEST_F(IR_ArrayOffsetFromUniformTest, AllLoadsAndStoresU32) {
auto* byte_address_buffer_readonly_ty =
ty.Get<hlsl::type::ByteAddressBuffer>(core::Access::kRead);
auto* byte_address_buffer_readwrite_ty =
ty.Get<hlsl::type::ByteAddressBuffer>(core::Access::kReadWrite);
auto* buffer_ro = b.Var("buffer", byte_address_buffer_readonly_ty);
auto* buffer_rw = b.Var("buffer", byte_address_buffer_readwrite_ty);
buffer_ro->SetBindingPoint(5, 6);
buffer_rw->SetBindingPoint(7, 8);
mod.root_block->Append(buffer_ro);
mod.root_block->Append(buffer_rw);
auto* func = b.ComputeFunction("foo");
b.Append(func->Block(), [&] {
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.u32(), hlsl::BuiltinFn::kLoad, buffer_ro,
u32(42));
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.vec2u(), hlsl::BuiltinFn::kLoad2, buffer_ro,
u32(43));
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.vec3u(), hlsl::BuiltinFn::kLoad3, buffer_ro,
u32(44));
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.vec4u(), hlsl::BuiltinFn::kLoad4, buffer_ro,
u32(45));
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kStore, buffer_rw,
u32(46), 123_u);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kStore2, buffer_rw,
u32(47), b.Composite(ty.vec2u(), 123_u, 124_u));
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kStore3, buffer_rw,
u32(47),
b.Composite(ty.vec3u(), 123_u, 124_u, 125_u));
b.MemberCall<hlsl::ir::MemberBuiltinCall>(
ty.void_(), hlsl::BuiltinFn::kStore4, buffer_rw, u32(47),
b.Composite(ty.vec4u(), 123_u, 124_u, 125_u, 126_u));
b.Return(func);
});
auto* src = R"(
$B1: { # root
%buffer:hlsl.byte_address_buffer<read> = var undef @binding_point(5, 6)
%buffer_1:hlsl.byte_address_buffer<read_write> = var undef @binding_point(7, 8) # %buffer_1: 'buffer'
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%4:u32 = %buffer.Load 42u
%5:vec2<u32> = %buffer.Load2 43u
%6:vec3<u32> = %buffer.Load3 44u
%7:vec4<u32> = %buffer.Load4 45u
%8:void = %buffer_1.Store 46u, 123u
%9:void = %buffer_1.Store2 47u, vec2<u32>(123u, 124u)
%10:void = %buffer_1.Store3 47u, vec3<u32>(123u, 124u, 125u)
%11:void = %buffer_1.Store4 47u, vec4<u32>(123u, 124u, 125u, 126u)
ret
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
$B1: { # root
%buffer:hlsl.byte_address_buffer<read> = var undef @binding_point(5, 6)
%buffer_1:hlsl.byte_address_buffer<read_write> = var undef @binding_point(7, 8) # %buffer_1: 'buffer'
%tint_storage_buffer_dynamic_offsets:ptr<uniform, array<u32, 58>, read> = var undef @binding_point(1, 2)
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%5:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%6:u32 = load %5
%7:u32 = add 42u, %6
%8:u32 = %buffer.Load %7
%9:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%10:u32 = load %9
%11:u32 = add 43u, %10
%12:vec2<u32> = %buffer.Load2 %11
%13:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%14:u32 = load %13
%15:u32 = add 44u, %14
%16:vec3<u32> = %buffer.Load3 %15
%17:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%18:u32 = load %17
%19:u32 = add 45u, %18
%20:vec4<u32> = %buffer.Load4 %19
%21:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 57u
%22:u32 = load %21
%23:u32 = add 46u, %22
%24:void = %buffer_1.Store %23, 123u
%25:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 57u
%26:u32 = load %25
%27:u32 = add 47u, %26
%28:void = %buffer_1.Store2 %27, vec2<u32>(123u, 124u)
%29:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 57u
%30:u32 = load %29
%31:u32 = add 47u, %30
%32:void = %buffer_1.Store3 %31, vec3<u32>(123u, 124u, 125u)
%33:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 57u
%34:u32 = load %33
%35:u32 = add 47u, %34
%36:void = %buffer_1.Store4 %35, vec4<u32>(123u, 124u, 125u, 126u)
ret
}
}
)";
std::unordered_map<BindingPoint, uint32_t> bindpoint_to_offset_index;
bindpoint_to_offset_index[{5, 6}] = 26;
bindpoint_to_offset_index[{7, 8}] = 57;
Run(ArrayOffsetFromUniform, BindingPoint{1, 2}, bindpoint_to_offset_index);
EXPECT_EQ(expect, str());
}
TEST_F(IR_ArrayOffsetFromUniformTest, AllLoadsAndStoresF16) {
auto* byte_address_buffer_readonly_ty =
ty.Get<hlsl::type::ByteAddressBuffer>(core::Access::kRead);
auto* byte_address_buffer_readwrite_ty =
ty.Get<hlsl::type::ByteAddressBuffer>(core::Access::kReadWrite);
auto* buffer_ro = b.Var("buffer", byte_address_buffer_readonly_ty);
auto* buffer_rw = b.Var("buffer", byte_address_buffer_readwrite_ty);
buffer_ro->SetBindingPoint(5, 6);
buffer_rw->SetBindingPoint(7, 8);
mod.root_block->Append(buffer_ro);
mod.root_block->Append(buffer_rw);
auto* func = b.ComputeFunction("foo");
b.Append(func->Block(), [&] {
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.f16(), hlsl::BuiltinFn::kLoadF16, buffer_ro,
42_u);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.vec2h(), hlsl::BuiltinFn::kLoad2F16, buffer_ro,
43_u);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.vec3h(), hlsl::BuiltinFn::kLoad3F16, buffer_ro,
44_u);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.vec4h(), hlsl::BuiltinFn::kLoad4F16, buffer_ro,
45_u);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kStoreF16, buffer_rw,
46_u, 123.0_h);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kStore2F16,
buffer_rw, 47_u,
b.Composite(ty.vec2h(), 123.0_h, 124.0_h));
b.MemberCall<hlsl::ir::MemberBuiltinCall>(
ty.void_(), hlsl::BuiltinFn::kStore3F16, buffer_rw, 47_u,
b.Composite(ty.vec3h(), 123.0_h, 124.0_h, 125.0_h));
b.MemberCall<hlsl::ir::MemberBuiltinCall>(
ty.void_(), hlsl::BuiltinFn::kStore4F16, buffer_rw, 47_u,
b.Composite(ty.vec4h(), 123.0_h, 124.0_h, 125.0_h, 126.0_h));
b.Return(func);
});
auto* src = R"(
$B1: { # root
%buffer:hlsl.byte_address_buffer<read> = var undef @binding_point(5, 6)
%buffer_1:hlsl.byte_address_buffer<read_write> = var undef @binding_point(7, 8) # %buffer_1: 'buffer'
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%4:f16 = %buffer.LoadF16 42u
%5:vec2<f16> = %buffer.Load2F16 43u
%6:vec3<f16> = %buffer.Load3F16 44u
%7:vec4<f16> = %buffer.Load4F16 45u
%8:void = %buffer_1.StoreF16 46u, 123.0h
%9:void = %buffer_1.Store2F16 47u, vec2<f16>(123.0h, 124.0h)
%10:void = %buffer_1.Store3F16 47u, vec3<f16>(123.0h, 124.0h, 125.0h)
%11:void = %buffer_1.Store4F16 47u, vec4<f16>(123.0h, 124.0h, 125.0h, 126.0h)
ret
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
$B1: { # root
%buffer:hlsl.byte_address_buffer<read> = var undef @binding_point(5, 6)
%buffer_1:hlsl.byte_address_buffer<read_write> = var undef @binding_point(7, 8) # %buffer_1: 'buffer'
%tint_storage_buffer_dynamic_offsets:ptr<uniform, array<u32, 58>, read> = var undef @binding_point(1, 2)
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%5:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%6:u32 = load %5
%7:u32 = add 42u, %6
%8:f16 = %buffer.LoadF16 %7
%9:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%10:u32 = load %9
%11:u32 = add 43u, %10
%12:vec2<f16> = %buffer.Load2F16 %11
%13:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%14:u32 = load %13
%15:u32 = add 44u, %14
%16:vec3<f16> = %buffer.Load3F16 %15
%17:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%18:u32 = load %17
%19:u32 = add 45u, %18
%20:vec4<f16> = %buffer.Load4F16 %19
%21:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 57u
%22:u32 = load %21
%23:u32 = add 46u, %22
%24:void = %buffer_1.StoreF16 %23, 123.0h
%25:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 57u
%26:u32 = load %25
%27:u32 = add 47u, %26
%28:void = %buffer_1.Store2F16 %27, vec2<f16>(123.0h, 124.0h)
%29:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 57u
%30:u32 = load %29
%31:u32 = add 47u, %30
%32:void = %buffer_1.Store3F16 %31, vec3<f16>(123.0h, 124.0h, 125.0h)
%33:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 57u
%34:u32 = load %33
%35:u32 = add 47u, %34
%36:void = %buffer_1.Store4F16 %35, vec4<f16>(123.0h, 124.0h, 125.0h, 126.0h)
ret
}
}
)";
std::unordered_map<BindingPoint, uint32_t> bindpoint_to_offset_index;
bindpoint_to_offset_index[{5, 6}] = 26;
bindpoint_to_offset_index[{7, 8}] = 57;
Run(ArrayOffsetFromUniform, BindingPoint{1, 2}, bindpoint_to_offset_index);
EXPECT_EQ(expect, str());
}
// Test that offset is only added to bindpoint_to_offset_index entries
TEST_F(IR_ArrayOffsetFromUniformTest, OffsetOnlyEntriesInMap) {
auto* byte_address_buffer_readonly_ty =
ty.Get<hlsl::type::ByteAddressBuffer>(core::Access::kRead);
auto* buffer0 = b.Var("buffer0", byte_address_buffer_readonly_ty);
auto* buffer1 = b.Var("buffer1", byte_address_buffer_readonly_ty);
buffer0->SetBindingPoint(0, 0);
buffer1->SetBindingPoint(0, 1);
mod.root_block->Append(buffer0);
mod.root_block->Append(buffer1);
auto* func = b.ComputeFunction("foo");
b.Append(func->Block(), [&] {
auto base_offset = u32(42);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.u32(), hlsl::BuiltinFn::kLoad, buffer0,
base_offset);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.u32(), hlsl::BuiltinFn::kLoad, buffer1,
base_offset);
b.Return(func);
});
auto* src = R"(
$B1: { # root
%buffer0:hlsl.byte_address_buffer<read> = var undef @binding_point(0, 0)
%buffer1:hlsl.byte_address_buffer<read> = var undef @binding_point(0, 1)
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%4:u32 = %buffer0.Load 42u
%5:u32 = %buffer1.Load 42u
ret
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
$B1: { # root
%buffer0:hlsl.byte_address_buffer<read> = var undef @binding_point(0, 0)
%buffer1:hlsl.byte_address_buffer<read> = var undef @binding_point(0, 1)
%tint_storage_buffer_dynamic_offsets:ptr<uniform, array<u32, 21>, read> = var undef @binding_point(1, 2)
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%5:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 20u
%6:u32 = load %5
%7:u32 = add 42u, %6
%8:u32 = %buffer0.Load %7
%9:u32 = %buffer1.Load 42u
ret
}
}
)";
std::unordered_map<BindingPoint, uint32_t> bindpoint_to_offset_index;
bindpoint_to_offset_index[{0, 0}] = 20;
Run(ArrayOffsetFromUniform, BindingPoint{1, 2}, bindpoint_to_offset_index);
EXPECT_EQ(expect, str());
}
TEST_F(IR_ArrayOffsetFromUniformTest, AllAtomicOps) {
auto* byte_address_buffer_readwrite_ty =
ty.Get<hlsl::type::ByteAddressBuffer>(core::Access::kReadWrite);
auto* buffer_rw = b.Var("buffer", byte_address_buffer_readwrite_ty);
buffer_rw->SetBindingPoint(5, 6);
mod.root_block->Append(buffer_rw);
auto* func = b.ComputeFunction("foo");
b.Append(func->Block(), [&] {
auto base_offset = u32(42);
auto* pa = b.Var("a", ty.ptr<function, u32, read_write>());
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(),
hlsl::BuiltinFn::kInterlockedCompareExchange,
buffer_rw, base_offset, 1_u, 2_u, pa);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kInterlockedExchange,
buffer_rw, base_offset, 2_u, pa);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kInterlockedAdd,
buffer_rw, base_offset, 2_u, pa);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kInterlockedMax,
buffer_rw, base_offset, 2_u, pa);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kInterlockedMin,
buffer_rw, base_offset, 2_u, pa);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kInterlockedAnd,
buffer_rw, base_offset, 2_u, pa);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kInterlockedOr,
buffer_rw, base_offset, 2_u, pa);
b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), hlsl::BuiltinFn::kInterlockedXor,
buffer_rw, base_offset, 2_u, pa);
b.Return(func);
});
auto* src = R"(
$B1: { # root
%buffer:hlsl.byte_address_buffer<read_write> = var undef @binding_point(5, 6)
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%a:ptr<function, u32, read_write> = var undef
%4:void = %buffer.InterlockedCompareExchange 42u, 1u, 2u, %a
%5:void = %buffer.InterlockedExchange 42u, 2u, %a
%6:void = %buffer.InterlockedAdd 42u, 2u, %a
%7:void = %buffer.InterlockedMax 42u, 2u, %a
%8:void = %buffer.InterlockedMin 42u, 2u, %a
%9:void = %buffer.InterlockedAnd 42u, 2u, %a
%10:void = %buffer.InterlockedOr 42u, 2u, %a
%11:void = %buffer.InterlockedXor 42u, 2u, %a
ret
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
$B1: { # root
%buffer:hlsl.byte_address_buffer<read_write> = var undef @binding_point(5, 6)
%tint_storage_buffer_dynamic_offsets:ptr<uniform, array<u32, 27>, read> = var undef @binding_point(1, 2)
}
%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
$B2: {
%a:ptr<function, u32, read_write> = var undef
%5:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%6:u32 = load %5
%7:u32 = add 42u, %6
%8:void = %buffer.InterlockedCompareExchange %7, 1u, 2u, %a
%9:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%10:u32 = load %9
%11:u32 = add 42u, %10
%12:void = %buffer.InterlockedExchange %11, 2u, %a
%13:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%14:u32 = load %13
%15:u32 = add 42u, %14
%16:void = %buffer.InterlockedAdd %15, 2u, %a
%17:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%18:u32 = load %17
%19:u32 = add 42u, %18
%20:void = %buffer.InterlockedMax %19, 2u, %a
%21:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%22:u32 = load %21
%23:u32 = add 42u, %22
%24:void = %buffer.InterlockedMin %23, 2u, %a
%25:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%26:u32 = load %25
%27:u32 = add 42u, %26
%28:void = %buffer.InterlockedAnd %27, 2u, %a
%29:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%30:u32 = load %29
%31:u32 = add 42u, %30
%32:void = %buffer.InterlockedOr %31, 2u, %a
%33:ptr<uniform, u32, read> = access %tint_storage_buffer_dynamic_offsets, 26u
%34:u32 = load %33
%35:u32 = add 42u, %34
%36:void = %buffer.InterlockedXor %35, 2u, %a
ret
}
}
)";
std::unordered_map<BindingPoint, uint32_t> bindpoint_to_offset_index;
bindpoint_to_offset_index[{5, 6}] = 26;
Run(ArrayOffsetFromUniform, BindingPoint{1, 2}, bindpoint_to_offset_index);
EXPECT_EQ(expect, str());
}
} // namespace
} // namespace tint::hlsl::writer::raise