From 59c93775354e088317b11169a1936a0197bc5722 Mon Sep 17 00:00:00 2001 From: James Price Date: Thu, 12 Sep 2024 15:36:51 +0000 Subject: [PATCH] [msl] Key PackedVec3 helpers on pointer type Using the same composite type from multiple address spaces was causing collisions in the helper functions that meant they were being reused across different address spaces. Fixed: 366037039 Change-Id: I72927b90febd26fa23cb7acd4153b70af1c69fbe Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/206375 Reviewed-by: Antonio Maiorano --- src/tint/lang/msl/writer/raise/packed_vec3.cc | 16 +- .../lang/msl/writer/raise/packed_vec3_test.cc | 395 ++++++++++++++++++ test/tint/bug/tint/366037039.wgsl | 20 + .../bug/tint/366037039.wgsl.expected.dxc.hlsl | 76 ++++ .../bug/tint/366037039.wgsl.expected.fxc.hlsl | 76 ++++ .../bug/tint/366037039.wgsl.expected.glsl | 45 ++ .../tint/366037039.wgsl.expected.ir.dxc.hlsl | 111 +++++ .../tint/366037039.wgsl.expected.ir.fxc.hlsl | 111 +++++ .../bug/tint/366037039.wgsl.expected.ir.glsl | 50 +++ .../bug/tint/366037039.wgsl.expected.ir.msl | 111 +++++ .../tint/bug/tint/366037039.wgsl.expected.msl | 72 ++++ .../bug/tint/366037039.wgsl.expected.spvasm | 128 ++++++ .../bug/tint/366037039.wgsl.expected.wgsl | 19 + 13 files changed, 1222 insertions(+), 8 deletions(-) create mode 100644 test/tint/bug/tint/366037039.wgsl create mode 100644 test/tint/bug/tint/366037039.wgsl.expected.dxc.hlsl create mode 100644 test/tint/bug/tint/366037039.wgsl.expected.fxc.hlsl create mode 100644 test/tint/bug/tint/366037039.wgsl.expected.glsl create mode 100644 test/tint/bug/tint/366037039.wgsl.expected.ir.dxc.hlsl create mode 100644 test/tint/bug/tint/366037039.wgsl.expected.ir.fxc.hlsl create mode 100644 test/tint/bug/tint/366037039.wgsl.expected.ir.glsl create mode 100644 test/tint/bug/tint/366037039.wgsl.expected.ir.msl create mode 100644 test/tint/bug/tint/366037039.wgsl.expected.msl create mode 100644 test/tint/bug/tint/366037039.wgsl.expected.spvasm create mode 100644 test/tint/bug/tint/366037039.wgsl.expected.wgsl diff --git a/src/tint/lang/msl/writer/raise/packed_vec3.cc b/src/tint/lang/msl/writer/raise/packed_vec3.cc index 586b9d19a67..058bb037f76 100644 --- a/src/tint/lang/msl/writer/raise/packed_vec3.cc +++ b/src/tint/lang/msl/writer/raise/packed_vec3.cc @@ -64,11 +64,11 @@ struct State { /// when inside an array. Hashmap packed_array_element_types{}; - // A map from an unpacked type to a helper function that will load it from a packed pointer. - Hashmap packed_load_helpers{}; + // A map from a packed pointer type to a helper function that will load it to an unpacked type. + Hashmap packed_load_helpers{}; - // A map from an unpacked type to a helper function that will store it to a packed pointer. - Hashmap packed_store_helpers{}; + // A map from a packed pointer type to a helper function that will store an unpacked type to it. + Hashmap packed_store_helpers{}; /// Process the module. void Process() { @@ -410,7 +410,7 @@ struct State { /// @returns the helper function core::ir::Function* LoadPackedArrayHelper(const core::type::Array* unpacked_arr, const core::type::Pointer* packed_ptr_type) { - return packed_load_helpers.GetOrAdd(unpacked_arr, [&] { + return packed_load_helpers.GetOrAdd(packed_ptr_type, [&] { auto* func = b.Function(sym.New("tint_load_array_packed_vec3").Name(), unpacked_arr); auto* from = b.FunctionParam("from", packed_ptr_type); func->SetParams({from}); @@ -472,7 +472,7 @@ struct State { /// @returns the helper function core::ir::Function* LoadPackedStructHelper(const core::type::Struct* unpacked_str, const core::type::Pointer* packed_ptr_type) { - return packed_load_helpers.GetOrAdd(unpacked_str, [&] { + return packed_load_helpers.GetOrAdd(packed_ptr_type, [&] { auto* func = b.Function(sym.New("tint_load_struct_packed_vec3").Name(), unpacked_str); auto* from = b.FunctionParam("from", packed_ptr_type); func->SetParams({from}); @@ -547,7 +547,7 @@ struct State { /// @returns the helper function core::ir::Function* StorePackedArrayHelper(const core::type::Array* unpacked_arr, const core::type::Pointer* packed_ptr_type) { - return packed_store_helpers.GetOrAdd(unpacked_arr, [&] { + return packed_store_helpers.GetOrAdd(packed_ptr_type, [&] { auto* func = b.Function(sym.New("tint_store_array_packed_vec3").Name(), ty.void_()); auto* to = b.FunctionParam("to", packed_ptr_type); auto* value = b.FunctionParam("value", unpacked_arr); @@ -603,7 +603,7 @@ struct State { /// @returns the helper function core::ir::Function* StorePackedStructHelper(const core::type::Struct* unpacked_str, const core::type::Pointer* packed_ptr_type) { - return packed_store_helpers.GetOrAdd(unpacked_str, [&] { + return packed_store_helpers.GetOrAdd(packed_ptr_type, [&] { auto* func = b.Function(sym.New("tint_store_array_packed_vec3").Name(), ty.void_()); auto* to = b.FunctionParam("to", packed_ptr_type); auto* value = b.FunctionParam("value", unpacked_str); diff --git a/src/tint/lang/msl/writer/raise/packed_vec3_test.cc b/src/tint/lang/msl/writer/raise/packed_vec3_test.cc index c97702803eb..e7704aa7c50 100644 --- a/src/tint/lang/msl/writer/raise/packed_vec3_test.cc +++ b/src/tint/lang/msl/writer/raise/packed_vec3_test.cc @@ -3297,5 +3297,400 @@ tint_packed_vec3_f32_array_element = struct @align(16) { EXPECT_EQ(expect, str()); } +TEST_F(MslWriter_PackedVec3Test, MultipleAddressSpaces_LoadArray) { + auto* uvar = b.Var, 2>>("u"); + uvar->SetBindingPoint(0, 0); + mod.root_block->Append(uvar); + auto* svar = b.Var, 2>>("s"); + svar->SetBindingPoint(0, 1); + mod.root_block->Append(svar); + auto* wvar = b.Var, 2>>("w"); + mod.root_block->Append(wvar); + + auto* func = b.Function("foo", ty.void_()); + b.Append(func->Block(), [&] { // + b.Let("u_load", b.Load(uvar)); + b.Let("s_load", b.Load(svar)); + b.Let("w_load", b.Load(wvar)); + b.Return(func); + }); + + auto* src = R"( +$B1: { # root + %u:ptr, 2>, read> = var @binding_point(0, 0) + %s:ptr, 2>, read_write> = var @binding_point(0, 1) + %w:ptr, 2>, read_write> = var +} + +%foo = func():void { + $B2: { + %5:array, 2> = load %u + %u_load:array, 2> = let %5 + %7:array, 2> = load %s + %s_load:array, 2> = let %7 + %9:array, 2> = load %w + %w_load:array, 2> = let %9 + ret + } +} +)"; + EXPECT_EQ(src, str()); + + auto* expect = R"( +tint_packed_vec3_f32_array_element = struct @align(16) { + packed:__packed_vec3 @offset(0) +} + +$B1: { # root + %u:ptr, read> = var @binding_point(0, 0) + %s:ptr, read_write> = var @binding_point(0, 1) + %w:ptr, read_write> = var +} + +%foo = func():void { + $B2: { + %5:array, 2> = call %tint_load_array_packed_vec3, %u + %u_load:array, 2> = let %5 + %8:array, 2> = call %tint_load_array_packed_vec3_1, %s + %s_load:array, 2> = let %8 + %11:array, 2> = call %tint_load_array_packed_vec3_2, %w + %w_load:array, 2> = let %11 + ret + } +} +%tint_load_array_packed_vec3 = func(%from:ptr, read>):array, 2> { + $B3: { + %15:ptr, read> = access %from, 0u, 0u + %16:__packed_vec3 = load %15 + %17:vec3 = convert %16 + %18:ptr, read> = access %from, 1u, 0u + %19:__packed_vec3 = load %18 + %20:vec3 = convert %19 + %21:array, 2> = construct %17, %20 + ret %21 + } +} +%tint_load_array_packed_vec3_1 = func(%from_1:ptr, read_write>):array, 2> { # %from_1: 'from' + $B4: { + %23:ptr, read_write> = access %from_1, 0u, 0u + %24:__packed_vec3 = load %23 + %25:vec3 = convert %24 + %26:ptr, read_write> = access %from_1, 1u, 0u + %27:__packed_vec3 = load %26 + %28:vec3 = convert %27 + %29:array, 2> = construct %25, %28 + ret %29 + } +} +%tint_load_array_packed_vec3_2 = func(%from_2:ptr, read_write>):array, 2> { # %from_2: 'from' + $B5: { + %31:ptr, read_write> = access %from_2, 0u, 0u + %32:__packed_vec3 = load %31 + %33:vec3 = convert %32 + %34:ptr, read_write> = access %from_2, 1u, 0u + %35:__packed_vec3 = load %34 + %36:vec3 = convert %35 + %37:array, 2> = construct %33, %36 + ret %37 + } +} +)"; + + Run(PackedVec3); + + EXPECT_EQ(expect, str()); +} + +TEST_F(MslWriter_PackedVec3Test, MultipleAddressSpaces_StoreArray) { + auto* svar = b.Var, 2>>("s"); + svar->SetBindingPoint(0, 0); + mod.root_block->Append(svar); + auto* wvar = b.Var, 2>>("w"); + mod.root_block->Append(wvar); + + auto* func = b.Function("foo", ty.void_()); + b.Append(func->Block(), [&] { // + b.Store(svar, b.Zero, 2>>()); + b.Store(wvar, b.Zero, 2>>()); + b.Return(func); + }); + + auto* src = R"( +$B1: { # root + %s:ptr, 2>, read_write> = var @binding_point(0, 0) + %w:ptr, 2>, read_write> = var +} + +%foo = func():void { + $B2: { + store %s, array, 2>(vec3(0.0f)) + store %w, array, 2>(vec3(0.0f)) + ret + } +} +)"; + EXPECT_EQ(src, str()); + + auto* expect = R"( +tint_packed_vec3_f32_array_element = struct @align(16) { + packed:__packed_vec3 @offset(0) +} + +$B1: { # root + %s:ptr, read_write> = var @binding_point(0, 0) + %w:ptr, read_write> = var +} + +%foo = func():void { + $B2: { + %4:void = call %tint_store_array_packed_vec3, %s, array, 2>(vec3(0.0f)) + %6:void = call %tint_store_array_packed_vec3_1, %w, array, 2>(vec3(0.0f)) + ret + } +} +%tint_store_array_packed_vec3 = func(%to:ptr, read_write>, %value:array, 2>):void { + $B3: { + %10:vec3 = access %value, 0u + %11:ptr, read_write> = access %to, 0u, 0u + %12:__packed_vec3 = convert %10 + store %11, %12 + %13:vec3 = access %value, 1u + %14:ptr, read_write> = access %to, 1u, 0u + %15:__packed_vec3 = convert %13 + store %14, %15 + ret + } +} +%tint_store_array_packed_vec3_1 = func(%to_1:ptr, read_write>, %value_1:array, 2>):void { # %to_1: 'to', %value_1: 'value' + $B4: { + %18:vec3 = access %value_1, 0u + %19:ptr, read_write> = access %to_1, 0u, 0u + %20:__packed_vec3 = convert %18 + store %19, %20 + %21:vec3 = access %value_1, 1u + %22:ptr, read_write> = access %to_1, 1u, 0u + %23:__packed_vec3 = convert %21 + store %22, %23 + ret + } +} +)"; + + Run(PackedVec3); + + EXPECT_EQ(expect, str()); +} + +TEST_F(MslWriter_PackedVec3Test, MultipleAddressSpaces_LoadStruct) { + auto* s = ty.Struct(mod.symbols.New("S"), { + {mod.symbols.Register("vec"), ty.vec3()}, + {mod.symbols.Register("u"), ty.u32()}, + }); + + auto* uvar = b.Var("u", ty.ptr(s)); + uvar->SetBindingPoint(0, 0); + mod.root_block->Append(uvar); + auto* svar = b.Var("s", ty.ptr(s)); + svar->SetBindingPoint(0, 1); + mod.root_block->Append(svar); + auto* wvar = b.Var("w", ty.ptr(s)); + mod.root_block->Append(wvar); + + auto* func = b.Function("foo", ty.void_()); + b.Append(func->Block(), [&] { // + b.Let("u_load", b.Load(uvar)); + b.Let("s_load", b.Load(svar)); + b.Let("w_load", b.Load(wvar)); + b.Return(func); + }); + + auto* src = R"( +S = struct @align(16) { + vec:vec3 @offset(0) + u:u32 @offset(12) +} + +$B1: { # root + %u:ptr = var @binding_point(0, 0) + %s:ptr = var @binding_point(0, 1) + %w:ptr = var +} + +%foo = func():void { + $B2: { + %5:S = load %u + %u_load:S = let %5 + %7:S = load %s + %s_load:S = let %7 + %9:S = load %w + %w_load:S = let %9 + ret + } +} +)"; + EXPECT_EQ(src, str()); + + auto* expect = R"( +S = struct @align(16) { + vec:vec3 @offset(0) + u:u32 @offset(12) +} + +S_packed_vec3 = struct @align(16) { + vec:__packed_vec3 @offset(0) + u:u32 @offset(12) +} + +$B1: { # root + %u:ptr = var @binding_point(0, 0) + %s:ptr = var @binding_point(0, 1) + %w:ptr = var +} + +%foo = func():void { + $B2: { + %5:S = call %tint_load_struct_packed_vec3, %u + %u_load:S = let %5 + %8:S = call %tint_load_struct_packed_vec3_1, %s + %s_load:S = let %8 + %11:S = call %tint_load_struct_packed_vec3_2, %w + %w_load:S = let %11 + ret + } +} +%tint_load_struct_packed_vec3 = func(%from:ptr):S { + $B3: { + %15:ptr, read> = access %from, 0u + %16:__packed_vec3 = load %15 + %17:vec3 = convert %16 + %18:ptr = access %from, 1u + %19:u32 = load %18 + %20:S = construct %17, %19 + ret %20 + } +} +%tint_load_struct_packed_vec3_1 = func(%from_1:ptr):S { # %from_1: 'from' + $B4: { + %22:ptr, read_write> = access %from_1, 0u + %23:__packed_vec3 = load %22 + %24:vec3 = convert %23 + %25:ptr = access %from_1, 1u + %26:u32 = load %25 + %27:S = construct %24, %26 + ret %27 + } +} +%tint_load_struct_packed_vec3_2 = func(%from_2:ptr):S { # %from_2: 'from' + $B5: { + %29:ptr, read_write> = access %from_2, 0u + %30:__packed_vec3 = load %29 + %31:vec3 = convert %30 + %32:ptr = access %from_2, 1u + %33:u32 = load %32 + %34:S = construct %31, %33 + ret %34 + } +} +)"; + + Run(PackedVec3); + + EXPECT_EQ(expect, str()); +} + +TEST_F(MslWriter_PackedVec3Test, MultipleAddressSpaces_StoreStruct) { + auto* s = ty.Struct(mod.symbols.New("S"), { + {mod.symbols.Register("vec"), ty.vec3()}, + {mod.symbols.Register("u"), ty.u32()}, + }); + + auto* svar = b.Var("s", ty.ptr(s)); + svar->SetBindingPoint(0, 0); + mod.root_block->Append(svar); + auto* wvar = b.Var("w", ty.ptr(s)); + mod.root_block->Append(wvar); + + auto* func = b.Function("foo", ty.void_()); + b.Append(func->Block(), [&] { // + b.Store(svar, b.Zero(s)); + b.Store(wvar, b.Zero(s)); + b.Return(func); + }); + + auto* src = R"( +S = struct @align(16) { + vec:vec3 @offset(0) + u:u32 @offset(12) +} + +$B1: { # root + %s:ptr = var @binding_point(0, 0) + %w:ptr = var +} + +%foo = func():void { + $B2: { + store %s, S(vec3(0u), 0u) + store %w, S(vec3(0u), 0u) + ret + } +} +)"; + EXPECT_EQ(src, str()); + + auto* expect = R"( +S = struct @align(16) { + vec:vec3 @offset(0) + u:u32 @offset(12) +} + +S_packed_vec3 = struct @align(16) { + vec:__packed_vec3 @offset(0) + u:u32 @offset(12) +} + +$B1: { # root + %s:ptr = var @binding_point(0, 0) + %w:ptr = var +} + +%foo = func():void { + $B2: { + %4:void = call %tint_store_array_packed_vec3, %s, S(vec3(0u), 0u) + %6:void = call %tint_store_array_packed_vec3_1, %w, S(vec3(0u), 0u) + ret + } +} +%tint_store_array_packed_vec3 = func(%to:ptr, %value:S):void { + $B3: { + %10:vec3 = access %value, 0u + %11:ptr, read_write> = access %to, 0u + %12:__packed_vec3 = convert %10 + store %11, %12 + %13:u32 = access %value, 1u + %14:ptr = access %to, 1u + store %14, %13 + ret + } +} +%tint_store_array_packed_vec3_1 = func(%to_1:ptr, %value_1:S):void { # %to_1: 'to', %value_1: 'value' + $B4: { + %17:vec3 = access %value_1, 0u + %18:ptr, read_write> = access %to_1, 0u + %19:__packed_vec3 = convert %17 + store %18, %19 + %20:u32 = access %value_1, 1u + %21:ptr = access %to_1, 1u + store %21, %20 + ret + } +} +)"; + + Run(PackedVec3); + + EXPECT_EQ(expect, str()); +} + } // namespace } // namespace tint::msl::writer::raise diff --git a/test/tint/bug/tint/366037039.wgsl b/test/tint/bug/tint/366037039.wgsl new file mode 100644 index 00000000000..73fcbcca01e --- /dev/null +++ b/test/tint/bug/tint/366037039.wgsl @@ -0,0 +1,20 @@ +struct S { + a : vec3u, + b : u32, + c : array, +} + +@group(0) @binding(0) +var ubuffer : S; +@group(0) @binding(1) +var sbuffer : S; +var wbuffer : S; + +fn foo() { + let u = ubuffer; + let s = sbuffer; + let w = sbuffer; + + sbuffer = S(); + wbuffer = S(); +} diff --git a/test/tint/bug/tint/366037039.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/366037039.wgsl.expected.dxc.hlsl new file mode 100644 index 00000000000..1d64aeaaba1 --- /dev/null +++ b/test/tint/bug/tint/366037039.wgsl.expected.dxc.hlsl @@ -0,0 +1,76 @@ +[numthreads(1, 1, 1)] +void unused_entry_point() { + return; +} + +struct S { + uint3 a; + uint b; + uint3 c[4]; +}; + +cbuffer cbuffer_ubuffer : register(b0) { + uint4 ubuffer[5]; +}; +RWByteAddressBuffer sbuffer : register(u1); +groupshared S wbuffer; + +typedef uint3 ubuffer_load_3_ret[4]; +ubuffer_load_3_ret ubuffer_load_3(uint offset) { + uint3 arr[4] = (uint3[4])0; + { + for(uint i = 0u; (i < 4u); i = (i + 1u)) { + const uint scalar_offset = ((offset + (i * 16u))) / 4; + arr[i] = ubuffer[scalar_offset / 4].xyz; + } + } + return arr; +} + +S ubuffer_load(uint offset) { + const uint scalar_offset_1 = ((offset + 0u)) / 4; + const uint scalar_offset_2 = ((offset + 12u)) / 4; + S tint_symbol = {ubuffer[scalar_offset_1 / 4].xyz, ubuffer[scalar_offset_2 / 4][scalar_offset_2 % 4], ubuffer_load_3((offset + 16u))}; + return tint_symbol; +} + +typedef uint3 sbuffer_load_3_ret[4]; +sbuffer_load_3_ret sbuffer_load_3(uint offset) { + uint3 arr_1[4] = (uint3[4])0; + { + for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) { + arr_1[i_1] = sbuffer.Load3((offset + (i_1 * 16u))); + } + } + return arr_1; +} + +S sbuffer_load(uint offset) { + S tint_symbol_1 = {sbuffer.Load3((offset + 0u)), sbuffer.Load((offset + 12u)), sbuffer_load_3((offset + 16u))}; + return tint_symbol_1; +} + +void sbuffer_store_3(uint offset, uint3 value[4]) { + uint3 array_1[4] = value; + { + for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) { + sbuffer.Store3((offset + (i_2 * 16u)), asuint(array_1[i_2])); + } + } +} + +void sbuffer_store(uint offset, S value) { + sbuffer.Store3((offset + 0u), asuint(value.a)); + sbuffer.Store((offset + 12u), asuint(value.b)); + sbuffer_store_3((offset + 16u), value.c); +} + +void foo() { + S u = ubuffer_load(0u); + S s = sbuffer_load(0u); + S w = sbuffer_load(0u); + S tint_symbol_2 = (S)0; + sbuffer_store(0u, tint_symbol_2); + S tint_symbol_3 = (S)0; + wbuffer = tint_symbol_3; +} diff --git a/test/tint/bug/tint/366037039.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/366037039.wgsl.expected.fxc.hlsl new file mode 100644 index 00000000000..1d64aeaaba1 --- /dev/null +++ b/test/tint/bug/tint/366037039.wgsl.expected.fxc.hlsl @@ -0,0 +1,76 @@ +[numthreads(1, 1, 1)] +void unused_entry_point() { + return; +} + +struct S { + uint3 a; + uint b; + uint3 c[4]; +}; + +cbuffer cbuffer_ubuffer : register(b0) { + uint4 ubuffer[5]; +}; +RWByteAddressBuffer sbuffer : register(u1); +groupshared S wbuffer; + +typedef uint3 ubuffer_load_3_ret[4]; +ubuffer_load_3_ret ubuffer_load_3(uint offset) { + uint3 arr[4] = (uint3[4])0; + { + for(uint i = 0u; (i < 4u); i = (i + 1u)) { + const uint scalar_offset = ((offset + (i * 16u))) / 4; + arr[i] = ubuffer[scalar_offset / 4].xyz; + } + } + return arr; +} + +S ubuffer_load(uint offset) { + const uint scalar_offset_1 = ((offset + 0u)) / 4; + const uint scalar_offset_2 = ((offset + 12u)) / 4; + S tint_symbol = {ubuffer[scalar_offset_1 / 4].xyz, ubuffer[scalar_offset_2 / 4][scalar_offset_2 % 4], ubuffer_load_3((offset + 16u))}; + return tint_symbol; +} + +typedef uint3 sbuffer_load_3_ret[4]; +sbuffer_load_3_ret sbuffer_load_3(uint offset) { + uint3 arr_1[4] = (uint3[4])0; + { + for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) { + arr_1[i_1] = sbuffer.Load3((offset + (i_1 * 16u))); + } + } + return arr_1; +} + +S sbuffer_load(uint offset) { + S tint_symbol_1 = {sbuffer.Load3((offset + 0u)), sbuffer.Load((offset + 12u)), sbuffer_load_3((offset + 16u))}; + return tint_symbol_1; +} + +void sbuffer_store_3(uint offset, uint3 value[4]) { + uint3 array_1[4] = value; + { + for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) { + sbuffer.Store3((offset + (i_2 * 16u)), asuint(array_1[i_2])); + } + } +} + +void sbuffer_store(uint offset, S value) { + sbuffer.Store3((offset + 0u), asuint(value.a)); + sbuffer.Store((offset + 12u), asuint(value.b)); + sbuffer_store_3((offset + 16u), value.c); +} + +void foo() { + S u = ubuffer_load(0u); + S s = sbuffer_load(0u); + S w = sbuffer_load(0u); + S tint_symbol_2 = (S)0; + sbuffer_store(0u, tint_symbol_2); + S tint_symbol_3 = (S)0; + wbuffer = tint_symbol_3; +} diff --git a/test/tint/bug/tint/366037039.wgsl.expected.glsl b/test/tint/bug/tint/366037039.wgsl.expected.glsl new file mode 100644 index 00000000000..784a03ff759 --- /dev/null +++ b/test/tint/bug/tint/366037039.wgsl.expected.glsl @@ -0,0 +1,45 @@ +#version 310 es + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; +void unused_entry_point() { + return; +} +struct S { + uvec3 a; + uint b; + uvec3 c[4]; +}; + +layout(binding = 0, std140) uniform ubuffer_block_ubo { + S inner; +} ubuffer; + +layout(binding = 1, std430) buffer ubuffer_block_ssbo { + S inner; +} sbuffer; + +shared S wbuffer; +void assign_and_preserve_padding_1_sbuffer_inner_c(uvec3 value[4]) { + { + for(uint i = 0u; (i < 4u); i = (i + 1u)) { + sbuffer.inner.c[i] = value[i]; + } + } +} + +void assign_and_preserve_padding_sbuffer_inner(S value) { + sbuffer.inner.a = value.a; + sbuffer.inner.b = value.b; + assign_and_preserve_padding_1_sbuffer_inner_c(value.c); +} + +void foo() { + S u = ubuffer.inner; + S s = sbuffer.inner; + S w = sbuffer.inner; + S tint_symbol = S(uvec3(0u), 0u, uvec3[4](uvec3(0u), uvec3(0u), uvec3(0u), uvec3(0u))); + assign_and_preserve_padding_sbuffer_inner(tint_symbol); + S tint_symbol_1 = S(uvec3(0u), 0u, uvec3[4](uvec3(0u), uvec3(0u), uvec3(0u), uvec3(0u))); + wbuffer = tint_symbol_1; +} + diff --git a/test/tint/bug/tint/366037039.wgsl.expected.ir.dxc.hlsl b/test/tint/bug/tint/366037039.wgsl.expected.ir.dxc.hlsl new file mode 100644 index 00000000000..6290db7395f --- /dev/null +++ b/test/tint/bug/tint/366037039.wgsl.expected.ir.dxc.hlsl @@ -0,0 +1,111 @@ +struct S { + uint3 a; + uint b; + uint3 c[4]; +}; + + +cbuffer cbuffer_ubuffer : register(b0) { + uint4 ubuffer[5]; +}; +RWByteAddressBuffer sbuffer : register(u1); +groupshared S wbuffer; +void v(uint offset, uint3 obj[4]) { + { + uint v_1 = 0u; + v_1 = 0u; + while(true) { + uint v_2 = v_1; + if ((v_2 >= 4u)) { + break; + } + sbuffer.Store3((offset + (v_2 * 16u)), obj[v_2]); + { + v_1 = (v_2 + 1u); + } + continue; + } + } +} + +void v_3(uint offset, S obj) { + sbuffer.Store3((offset + 0u), obj.a); + sbuffer.Store((offset + 12u), obj.b); + uint3 v_4[4] = obj.c; + v((offset + 16u), v_4); +} + +typedef uint3 ary_ret[4]; +ary_ret v_5(uint offset) { + uint3 a[4] = (uint3[4])0; + { + uint v_6 = 0u; + v_6 = 0u; + while(true) { + uint v_7 = v_6; + if ((v_7 >= 4u)) { + break; + } + a[v_7] = sbuffer.Load3((offset + (v_7 * 16u))); + { + v_6 = (v_7 + 1u); + } + continue; + } + } + uint3 v_8[4] = a; + return v_8; +} + +S v_9(uint offset) { + uint3 v_10 = sbuffer.Load3((offset + 0u)); + uint v_11 = sbuffer.Load((offset + 12u)); + uint3 v_12[4] = v_5((offset + 16u)); + S v_13 = {v_10, v_11, v_12}; + return v_13; +} + +typedef uint3 ary_ret_1[4]; +ary_ret_1 v_14(uint start_byte_offset) { + uint3 a[4] = (uint3[4])0; + { + uint v_15 = 0u; + v_15 = 0u; + while(true) { + uint v_16 = v_15; + if ((v_16 >= 4u)) { + break; + } + a[v_16] = ubuffer[((start_byte_offset + (v_16 * 16u)) / 16u)].xyz; + { + v_15 = (v_16 + 1u); + } + continue; + } + } + uint3 v_17[4] = a; + return v_17; +} + +S v_18(uint start_byte_offset) { + uint3 v_19 = ubuffer[(start_byte_offset / 16u)].xyz; + uint v_20 = ubuffer[((12u + start_byte_offset) / 16u)][(((12u + start_byte_offset) % 16u) / 4u)]; + uint3 v_21[4] = v_14((16u + start_byte_offset)); + S v_22 = {v_19, v_20, v_21}; + return v_22; +} + +void foo() { + S u = v_18(0u); + S s = v_9(0u); + S w = v_9(0u); + S v_23 = (S)0; + v_3(0u, v_23); + S v_24 = (S)0; + wbuffer = v_24; +} + +[numthreads(1, 1, 1)] +void unused_entry_point() { +} + diff --git a/test/tint/bug/tint/366037039.wgsl.expected.ir.fxc.hlsl b/test/tint/bug/tint/366037039.wgsl.expected.ir.fxc.hlsl new file mode 100644 index 00000000000..6290db7395f --- /dev/null +++ b/test/tint/bug/tint/366037039.wgsl.expected.ir.fxc.hlsl @@ -0,0 +1,111 @@ +struct S { + uint3 a; + uint b; + uint3 c[4]; +}; + + +cbuffer cbuffer_ubuffer : register(b0) { + uint4 ubuffer[5]; +}; +RWByteAddressBuffer sbuffer : register(u1); +groupshared S wbuffer; +void v(uint offset, uint3 obj[4]) { + { + uint v_1 = 0u; + v_1 = 0u; + while(true) { + uint v_2 = v_1; + if ((v_2 >= 4u)) { + break; + } + sbuffer.Store3((offset + (v_2 * 16u)), obj[v_2]); + { + v_1 = (v_2 + 1u); + } + continue; + } + } +} + +void v_3(uint offset, S obj) { + sbuffer.Store3((offset + 0u), obj.a); + sbuffer.Store((offset + 12u), obj.b); + uint3 v_4[4] = obj.c; + v((offset + 16u), v_4); +} + +typedef uint3 ary_ret[4]; +ary_ret v_5(uint offset) { + uint3 a[4] = (uint3[4])0; + { + uint v_6 = 0u; + v_6 = 0u; + while(true) { + uint v_7 = v_6; + if ((v_7 >= 4u)) { + break; + } + a[v_7] = sbuffer.Load3((offset + (v_7 * 16u))); + { + v_6 = (v_7 + 1u); + } + continue; + } + } + uint3 v_8[4] = a; + return v_8; +} + +S v_9(uint offset) { + uint3 v_10 = sbuffer.Load3((offset + 0u)); + uint v_11 = sbuffer.Load((offset + 12u)); + uint3 v_12[4] = v_5((offset + 16u)); + S v_13 = {v_10, v_11, v_12}; + return v_13; +} + +typedef uint3 ary_ret_1[4]; +ary_ret_1 v_14(uint start_byte_offset) { + uint3 a[4] = (uint3[4])0; + { + uint v_15 = 0u; + v_15 = 0u; + while(true) { + uint v_16 = v_15; + if ((v_16 >= 4u)) { + break; + } + a[v_16] = ubuffer[((start_byte_offset + (v_16 * 16u)) / 16u)].xyz; + { + v_15 = (v_16 + 1u); + } + continue; + } + } + uint3 v_17[4] = a; + return v_17; +} + +S v_18(uint start_byte_offset) { + uint3 v_19 = ubuffer[(start_byte_offset / 16u)].xyz; + uint v_20 = ubuffer[((12u + start_byte_offset) / 16u)][(((12u + start_byte_offset) % 16u) / 4u)]; + uint3 v_21[4] = v_14((16u + start_byte_offset)); + S v_22 = {v_19, v_20, v_21}; + return v_22; +} + +void foo() { + S u = v_18(0u); + S s = v_9(0u); + S w = v_9(0u); + S v_23 = (S)0; + v_3(0u, v_23); + S v_24 = (S)0; + wbuffer = v_24; +} + +[numthreads(1, 1, 1)] +void unused_entry_point() { +} + diff --git a/test/tint/bug/tint/366037039.wgsl.expected.ir.glsl b/test/tint/bug/tint/366037039.wgsl.expected.ir.glsl new file mode 100644 index 00000000000..a14b7664610 --- /dev/null +++ b/test/tint/bug/tint/366037039.wgsl.expected.ir.glsl @@ -0,0 +1,50 @@ +#version 310 es + + +struct S { + uvec3 a; + uint b; + uvec3 c[4]; +}; + +layout(binding = 0, std140) +uniform tint_symbol_1_1_ubo { + S tint_symbol; +} v; +layout(binding = 1, std430) +buffer tint_symbol_3_1_ssbo { + S tint_symbol_2; +} v_1; +shared S wbuffer; +void tint_store_and_preserve_padding_1(inout uvec3 target[4], uvec3 value_param[4]) { + { + uint v_2 = 0u; + v_2 = 0u; + while(true) { + uint v_3 = v_2; + if ((v_3 >= 4u)) { + break; + } + target[v_3] = value_param[v_3]; + { + v_2 = (v_3 + 1u); + } + continue; + } + } +} +void tint_store_and_preserve_padding(inout S target, S value_param) { + target.a = value_param.a; + target.b = value_param.b; + tint_store_and_preserve_padding_1(target.c, value_param.c); +} +void foo() { + S u = v.tint_symbol; + S s = v_1.tint_symbol_2; + S w = v_1.tint_symbol_2; + tint_store_and_preserve_padding(v_1.tint_symbol_2, S(uvec3(0u), 0u, uvec3[4](uvec3(0u), uvec3(0u), uvec3(0u), uvec3(0u)))); + wbuffer = S(uvec3(0u), 0u, uvec3[4](uvec3(0u), uvec3(0u), uvec3(0u), uvec3(0u))); +} +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; +void main() { +} diff --git a/test/tint/bug/tint/366037039.wgsl.expected.ir.msl b/test/tint/bug/tint/366037039.wgsl.expected.ir.msl new file mode 100644 index 00000000000..3da7d69d900 --- /dev/null +++ b/test/tint/bug/tint/366037039.wgsl.expected.ir.msl @@ -0,0 +1,111 @@ +#include +using namespace metal; + +template +struct tint_array { + const constant T& operator[](size_t i) const constant { return elements[i]; } + device T& operator[](size_t i) device { return elements[i]; } + const device T& operator[](size_t i) const device { return elements[i]; } + thread T& operator[](size_t i) thread { return elements[i]; } + const thread T& operator[](size_t i) const thread { return elements[i]; } + threadgroup T& operator[](size_t i) threadgroup { return elements[i]; } + const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; } + T elements[N]; +}; + +struct tint_packed_vec3_u32_array_element { + packed_uint3 packed; +}; + +struct S_packed_vec3 { + packed_uint3 a; + uint b; + tint_array c; +}; + +struct S { + uint3 a; + uint b; + tint_array c; +}; + +#define TINT_ISOLATE_UB(VOLATILE_NAME) \ + volatile bool VOLATILE_NAME = true; \ + if (VOLATILE_NAME) + +struct tint_module_vars_struct { + const constant S_packed_vec3* ubuffer; + device S_packed_vec3* sbuffer; + threadgroup S_packed_vec3* wbuffer; +}; + +void tint_store_array_packed_vec3_1(threadgroup tint_array* const to, tint_array value) { + (*to)[0u].packed = packed_uint3(value[0u]); + (*to)[1u].packed = packed_uint3(value[1u]); + (*to)[2u].packed = packed_uint3(value[2u]); + (*to)[3u].packed = packed_uint3(value[3u]); +} + +void tint_store_array_packed_vec3(threadgroup S_packed_vec3* const to, S value) { + (*to).a = packed_uint3(value.a); + (*to).b = value.b; + tint_store_array_packed_vec3_1((&(*to).c), value.c); +} + +void tint_store_and_preserve_padding_1(device tint_array* const target, tint_array value_param) { + { + uint v = 0u; + v = 0u; + TINT_ISOLATE_UB(tint_volatile_true) while(true) { + uint const v_1 = v; + if ((v_1 >= 4u)) { + break; + } + (*target)[v_1].packed = packed_uint3(value_param[v_1]); + { + v = (v_1 + 1u); + } + continue; + } + } +} + +void tint_store_and_preserve_padding(device S_packed_vec3* const target, S value_param) { + (*target).a = packed_uint3(value_param.a); + (*target).b = value_param.b; + tint_store_and_preserve_padding_1((&(*target).c), value_param.c); +} + +tint_array tint_load_array_packed_vec3_1(device tint_array* const from) { + uint3 const v_2 = uint3((*from)[0u].packed); + uint3 const v_3 = uint3((*from)[1u].packed); + uint3 const v_4 = uint3((*from)[2u].packed); + return tint_array{v_2, v_3, v_4, uint3((*from)[3u].packed)}; +} + +S tint_load_struct_packed_vec3_1(device S_packed_vec3* const from) { + uint3 const v_5 = uint3((*from).a); + uint const v_6 = (*from).b; + return S{.a=v_5, .b=v_6, .c=tint_load_array_packed_vec3_1((&(*from).c))}; +} + +tint_array tint_load_array_packed_vec3(const constant tint_array* const from) { + uint3 const v_7 = uint3((*from)[0u].packed); + uint3 const v_8 = uint3((*from)[1u].packed); + uint3 const v_9 = uint3((*from)[2u].packed); + return tint_array{v_7, v_8, v_9, uint3((*from)[3u].packed)}; +} + +S tint_load_struct_packed_vec3(const constant S_packed_vec3* const from) { + uint3 const v_10 = uint3((*from).a); + uint const v_11 = (*from).b; + return S{.a=v_10, .b=v_11, .c=tint_load_array_packed_vec3((&(*from).c))}; +} + +void foo(tint_module_vars_struct tint_module_vars) { + S const u = tint_load_struct_packed_vec3(tint_module_vars.ubuffer); + S const s = tint_load_struct_packed_vec3_1(tint_module_vars.sbuffer); + S const w = tint_load_struct_packed_vec3_1(tint_module_vars.sbuffer); + tint_store_and_preserve_padding(tint_module_vars.sbuffer, S{}); + tint_store_array_packed_vec3(tint_module_vars.wbuffer, S{}); +} diff --git a/test/tint/bug/tint/366037039.wgsl.expected.msl b/test/tint/bug/tint/366037039.wgsl.expected.msl new file mode 100644 index 00000000000..bf0f0650015 --- /dev/null +++ b/test/tint/bug/tint/366037039.wgsl.expected.msl @@ -0,0 +1,72 @@ +#include + +using namespace metal; + +template +struct tint_array { + const constant T& operator[](size_t i) const constant { return elements[i]; } + device T& operator[](size_t i) device { return elements[i]; } + const device T& operator[](size_t i) const device { return elements[i]; } + thread T& operator[](size_t i) thread { return elements[i]; } + const thread T& operator[](size_t i) const thread { return elements[i]; } + threadgroup T& operator[](size_t i) threadgroup { return elements[i]; } + const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; } + T elements[N]; +}; + +#define TINT_ISOLATE_UB(VOLATILE_NAME) \ + volatile bool VOLATILE_NAME = true; \ + if (VOLATILE_NAME) + +struct tint_packed_vec3_u32_array_element { + /* 0x0000 */ packed_uint3 elements; + /* 0x000c */ tint_array tint_pad; +}; + +struct S_tint_packed_vec3 { + /* 0x0000 */ packed_uint3 a; + /* 0x000c */ uint b; + /* 0x0010 */ tint_array c; +}; + +tint_array tint_unpack_vec3_in_composite(tint_array in) { + tint_array result = tint_array{uint3(in[0].elements), uint3(in[1].elements), uint3(in[2].elements), uint3(in[3].elements)}; + return result; +} + +struct S { + uint3 a; + uint b; + tint_array c; +}; + +S tint_unpack_vec3_in_composite_1(S_tint_packed_vec3 in) { + S result = {}; + result.a = uint3(in.a); + result.b = in.b; + result.c = tint_unpack_vec3_in_composite(in.c); + return result; +} + +void assign_and_preserve_padding_1(device tint_array* const dest, tint_array value) { + TINT_ISOLATE_UB(tint_volatile_true) for(uint i = 0u; (i < 4u); i = (i + 1u)) { + (*(dest))[i].elements = packed_uint3(value[i]); + } +} + +void assign_and_preserve_padding(device S_tint_packed_vec3* const dest, S value) { + (*(dest)).a = packed_uint3(value.a); + (*(dest)).b = value.b; + assign_and_preserve_padding_1(&((*(dest)).c), value.c); +} + +void foo(const constant S_tint_packed_vec3* const tint_symbol_2, device S_tint_packed_vec3* const tint_symbol_3, threadgroup S* const tint_symbol_4) { + S const u = tint_unpack_vec3_in_composite_1(*(tint_symbol_2)); + S const s = tint_unpack_vec3_in_composite_1(*(tint_symbol_3)); + S const w = tint_unpack_vec3_in_composite_1(*(tint_symbol_3)); + S const tint_symbol = S{}; + assign_and_preserve_padding(tint_symbol_3, tint_symbol); + S const tint_symbol_1 = S{}; + *(tint_symbol_4) = tint_symbol_1; +} + diff --git a/test/tint/bug/tint/366037039.wgsl.expected.spvasm b/test/tint/bug/tint/366037039.wgsl.expected.spvasm new file mode 100644 index 00000000000..b8facdf0921 --- /dev/null +++ b/test/tint/bug/tint/366037039.wgsl.expected.spvasm @@ -0,0 +1,128 @@ +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 1 +; Bound: 66 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %unused_entry_point "unused_entry_point" + OpExecutionMode %unused_entry_point LocalSize 1 1 1 + OpMemberName %S 0 "a" + OpMemberName %S 1 "b" + OpMemberName %S 2 "c" + OpName %S "S" + OpMemberName %tint_symbol_1 0 "tint_symbol" + OpName %tint_symbol_1 "tint_symbol_1" + OpMemberName %tint_symbol_3 0 "tint_symbol_2" + OpName %tint_symbol_3 "tint_symbol_3" + OpName %wbuffer "wbuffer" + OpName %foo "foo" + OpName %u "u" + OpName %s "s" + OpName %w "w" + OpName %tint_store_and_preserve_padding "tint_store_and_preserve_padding" + OpName %value_param "value_param" + OpName %tint_store_and_preserve_padding_0 "tint_store_and_preserve_padding" + OpName %value_param_0 "value_param" + OpName %unused_entry_point "unused_entry_point" + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 12 + OpDecorate %_arr_v3uint_uint_4 ArrayStride 16 + OpMemberDecorate %S 2 Offset 16 + OpMemberDecorate %tint_symbol_1 0 Offset 0 + OpDecorate %tint_symbol_1 Block + OpDecorate %1 DescriptorSet 0 + OpDecorate %1 Binding 0 + OpDecorate %1 NonWritable + OpMemberDecorate %tint_symbol_3 0 Offset 0 + OpDecorate %tint_symbol_3 Block + OpDecorate %9 DescriptorSet 0 + OpDecorate %9 Binding 1 + OpDecorate %9 Coherent + %uint = OpTypeInt 32 0 + %v3uint = OpTypeVector %uint 3 + %uint_4 = OpConstant %uint 4 +%_arr_v3uint_uint_4 = OpTypeArray %v3uint %uint_4 + %S = OpTypeStruct %v3uint %uint %_arr_v3uint_uint_4 +%tint_symbol_1 = OpTypeStruct %S +%_ptr_Uniform_tint_symbol_1 = OpTypePointer Uniform %tint_symbol_1 + %1 = OpVariable %_ptr_Uniform_tint_symbol_1 Uniform +%tint_symbol_3 = OpTypeStruct %S +%_ptr_StorageBuffer_tint_symbol_3 = OpTypePointer StorageBuffer %tint_symbol_3 + %9 = OpVariable %_ptr_StorageBuffer_tint_symbol_3 StorageBuffer +%_ptr_Workgroup_S = OpTypePointer Workgroup %S + %wbuffer = OpVariable %_ptr_Workgroup_S Workgroup + %void = OpTypeVoid + %16 = OpTypeFunction %void +%_ptr_Uniform_S = OpTypePointer Uniform %S + %uint_0 = OpConstant %uint 0 +%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S + %29 = OpConstantNull %S + %31 = OpTypeFunction %void %S +%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint + %uint_1 = OpConstant %uint 1 + %44 = OpTypeFunction %void %_arr_v3uint_uint_4 +%_ptr_Function__arr_v3uint_uint_4 = OpTypePointer Function %_arr_v3uint_uint_4 + %bool = OpTypeBool + %uint_2 = OpConstant %uint 2 +%_ptr_Function_v3uint = OpTypePointer Function %v3uint + %foo = OpFunction %void None %16 + %17 = OpLabel + %18 = OpAccessChain %_ptr_Uniform_S %1 %uint_0 + %u = OpLoad %S %18 None + %22 = OpAccessChain %_ptr_StorageBuffer_S %9 %uint_0 + %s = OpLoad %S %22 None + %25 = OpAccessChain %_ptr_StorageBuffer_S %9 %uint_0 + %w = OpLoad %S %25 None + %27 = OpFunctionCall %void %tint_store_and_preserve_padding %29 + OpStore %wbuffer %29 None + OpReturn + OpFunctionEnd +%tint_store_and_preserve_padding = OpFunction %void None %31 +%value_param = OpFunctionParameter %S + %32 = OpLabel + %33 = OpAccessChain %_ptr_StorageBuffer_v3uint %9 %uint_0 %uint_0 + %35 = OpCompositeExtract %v3uint %value_param 0 + OpStore %33 %35 None + %36 = OpAccessChain %_ptr_StorageBuffer_uint %9 %uint_0 %uint_1 + %39 = OpCompositeExtract %uint %value_param 1 + OpStore %36 %39 None + %40 = OpCompositeExtract %_arr_v3uint_uint_4 %value_param 2 + %41 = OpFunctionCall %void %tint_store_and_preserve_padding_0 %40 + OpReturn + OpFunctionEnd +%tint_store_and_preserve_padding_0 = OpFunction %void None %44 +%value_param_0 = OpFunctionParameter %_arr_v3uint_uint_4 + %45 = OpLabel + %46 = OpVariable %_ptr_Function__arr_v3uint_uint_4 Function + OpStore %46 %value_param_0 + OpBranch %48 + %48 = OpLabel + OpBranch %51 + %51 = OpLabel + %53 = OpPhi %uint %uint_0 %48 %54 %50 + OpLoopMerge %52 %50 None + OpBranch %49 + %49 = OpLabel + %55 = OpUGreaterThanEqual %bool %53 %uint_4 + OpSelectionMerge %57 None + OpBranchConditional %55 %58 %57 + %58 = OpLabel + OpBranch %52 + %57 = OpLabel + %59 = OpAccessChain %_ptr_StorageBuffer_v3uint %9 %uint_0 %uint_2 %53 + %61 = OpAccessChain %_ptr_Function_v3uint %46 %53 + %63 = OpLoad %v3uint %61 None + OpStore %59 %63 None + OpBranch %50 + %50 = OpLabel + %54 = OpIAdd %uint %53 %uint_1 + OpBranch %51 + %52 = OpLabel + OpReturn + OpFunctionEnd +%unused_entry_point = OpFunction %void None %16 + %65 = OpLabel + OpReturn + OpFunctionEnd diff --git a/test/tint/bug/tint/366037039.wgsl.expected.wgsl b/test/tint/bug/tint/366037039.wgsl.expected.wgsl new file mode 100644 index 00000000000..aa0d007b2f3 --- /dev/null +++ b/test/tint/bug/tint/366037039.wgsl.expected.wgsl @@ -0,0 +1,19 @@ +struct S { + a : vec3u, + b : u32, + c : array, +} + +@group(0) @binding(0) var ubuffer : S; + +@group(0) @binding(1) var sbuffer : S; + +var wbuffer : S; + +fn foo() { + let u = ubuffer; + let s = sbuffer; + let w = sbuffer; + sbuffer = S(); + wbuffer = S(); +}