tint: Don't override alignment with @offset
Overriding the alignment to 1 would cause nested structures to be
incorrectly laid out. The fix: Don't override the alignment.
All struct layout validation works on the sem offsets, so none of this
has to change.
Bug: tint:1776
Change-Id: Ic01d45fb2790cd823ed9a55e336860ebdc351aea
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/112603
Kokoro: Ben Clayton <bclayton@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 3ad8661..60f8207 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -3173,7 +3173,6 @@
AddError("offsets must be in ascending order", o->source);
return false;
}
- align = 1;
has_offset_attr = true;
return true;
},
diff --git a/src/tint/resolver/struct_layout_test.cc b/src/tint/resolver/struct_layout_test.cc
index 1e5ec45..acfe691 100644
--- a/src/tint/resolver/struct_layout_test.cc
+++ b/src/tint/resolver/struct_layout_test.cc
@@ -555,5 +555,47 @@
}
}
+TEST_F(ResolverStructLayoutTest, OffsetAttributes) {
+ auto* inner = Structure("Inner", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{MemberOffset(8_i)}),
+ Member("b", ty.f32(), utils::Vector{MemberOffset(16_i)}),
+ Member("c", ty.f32(), utils::Vector{MemberOffset(32_i)}),
+ });
+ auto* s = Structure("S", utils::Vector{
+ Member("a", ty.f32(), utils::Vector{MemberOffset(4_i)}),
+ Member("b", ty.u32(), utils::Vector{MemberOffset(8_i)}),
+ Member("c", ty.Of(inner), utils::Vector{MemberOffset(32_i)}),
+ Member("d", ty.i32()),
+ Member("e", ty.i32(), utils::Vector{MemberOffset(128_i)}),
+ });
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = TypeOf(s)->As<sem::Struct>();
+ ASSERT_NE(sem, nullptr);
+ EXPECT_EQ(sem->Size(), 132u);
+ EXPECT_EQ(sem->SizeNoPadding(), 132u);
+ EXPECT_EQ(sem->Align(), 4u);
+ ASSERT_EQ(sem->Members().size(), 5u);
+ EXPECT_EQ(sem->Members()[0]->Offset(), 4u);
+ EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+ EXPECT_EQ(sem->Members()[1]->Offset(), 8u);
+ EXPECT_EQ(sem->Members()[1]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[1]->Size(), 4u);
+ EXPECT_EQ(sem->Members()[2]->Offset(), 32u);
+ EXPECT_EQ(sem->Members()[2]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[2]->Size(), 36u);
+ EXPECT_EQ(sem->Members()[3]->Offset(), 68u);
+ EXPECT_EQ(sem->Members()[3]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[3]->Size(), 4u);
+ EXPECT_EQ(sem->Members()[4]->Offset(), 128u);
+ EXPECT_EQ(sem->Members()[4]->Align(), 4u);
+ EXPECT_EQ(sem->Members()[4]->Size(), 4u);
+ for (auto& m : sem->Members()) {
+ EXPECT_EQ(m->Struct()->Declaration(), s);
+ }
+}
+
} // namespace
} // namespace tint::resolver
diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc
index f701146..cfd512b 100644
--- a/src/tint/writer/wgsl/generator_impl.cc
+++ b/src/tint/writer/wgsl/generator_impl.cc
@@ -606,8 +606,8 @@
increment_indent();
uint32_t offset = 0;
for (auto* mem : str->members) {
- // TODO(crbug.com/tint/798) move the @offset attribute handling to the
- // transform::Wgsl sanitizer.
+ // TODO(crbug.com/tint/798) move the @offset attribute handling to the transform::Wgsl
+ // sanitizer.
if (auto* mem_sem = program_->Sem().Get(mem)) {
offset = utils::RoundUp(mem_sem->Align(), offset);
if (uint32_t padding = mem_sem->Offset() - offset) {
diff --git a/test/tint/bug/tint/1088.spvasm.expected.wgsl b/test/tint/bug/tint/1088.spvasm.expected.wgsl
index 54ce4f2..5468399 100644
--- a/test/tint/bug/tint/1088.spvasm.expected.wgsl
+++ b/test/tint/bug/tint/1088.spvasm.expected.wgsl
@@ -12,8 +12,6 @@
worldViewProjection : mat4x4<f32>,
/* @offset(64) */
time : f32,
- @size(12)
- padding : u32,
/* @offset(80) */
test2 : Arr,
/* @offset(208) */
diff --git a/test/tint/bug/tint/1520.spvasm.expected.wgsl b/test/tint/bug/tint/1520.spvasm.expected.wgsl
index 931944d..812b115 100644
--- a/test/tint/bug/tint/1520.spvasm.expected.wgsl
+++ b/test/tint/bug/tint/1520.spvasm.expected.wgsl
@@ -3,8 +3,6 @@
padding : u32,
/* @offset(16) */
unknownInput_S1_c0 : f32,
- @size(12)
- padding_1 : u32,
/* @offset(32) */
ucolorRed_S1_c0 : vec4<f32>,
/* @offset(48) */
diff --git a/test/tint/bug/tint/1776.spvasm b/test/tint/bug/tint/1776.spvasm
new file mode 100644
index 0000000..3e85c9e
--- /dev/null
+++ b/test/tint/bug/tint/1776.spvasm
@@ -0,0 +1,44 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 19
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %sb_block "sb_block"
+ OpMemberName %sb_block 0 "inner"
+ OpName %S "S"
+ OpMemberName %S 0 "a"
+ OpMemberName %S 1 "b"
+ OpName %sb "sb"
+ OpName %main "main"
+ OpDecorate %sb_block Block
+ OpMemberDecorate %sb_block 0 Offset 0
+ OpMemberDecorate %S 0 Offset 0
+ OpMemberDecorate %S 1 Offset 16
+ OpDecorate %_runtimearr_S ArrayStride 32
+ OpDecorate %sb NonWritable
+ OpDecorate %sb DescriptorSet 0
+ OpDecorate %sb Binding 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %int = OpTypeInt 32 1
+ %S = OpTypeStruct %v4float %int
+%_runtimearr_S = OpTypeRuntimeArray %S
+ %sb_block = OpTypeStruct %_runtimearr_S
+%_ptr_StorageBuffer_sb_block = OpTypePointer StorageBuffer %sb_block
+ %sb = OpVariable %_ptr_StorageBuffer_sb_block StorageBuffer
+ %void = OpTypeVoid
+ %9 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+ %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+ %main = OpFunction %void None %9
+ %12 = OpLabel
+ %17 = OpAccessChain %_ptr_StorageBuffer_S %sb %uint_0 %int_1
+ %18 = OpLoad %S %17
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/bug/tint/1776.spvasm.expected.dxc.hlsl b/test/tint/bug/tint/1776.spvasm.expected.dxc.hlsl
new file mode 100644
index 0000000..1cd2986
--- /dev/null
+++ b/test/tint/bug/tint/1776.spvasm.expected.dxc.hlsl
@@ -0,0 +1,22 @@
+struct S {
+ float4 a;
+ int b;
+};
+
+RWByteAddressBuffer sb : register(u0, space0);
+
+S tint_symbol(RWByteAddressBuffer buffer, uint offset) {
+ const S tint_symbol_3 = {asfloat(buffer.Load4((offset + 0u))), asint(buffer.Load((offset + 16u)))};
+ return tint_symbol_3;
+}
+
+void main_1() {
+ const S x_18 = tint_symbol(sb, 32u);
+ return;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ main_1();
+ return;
+}
diff --git a/test/tint/bug/tint/1776.spvasm.expected.fxc.hlsl b/test/tint/bug/tint/1776.spvasm.expected.fxc.hlsl
new file mode 100644
index 0000000..1cd2986
--- /dev/null
+++ b/test/tint/bug/tint/1776.spvasm.expected.fxc.hlsl
@@ -0,0 +1,22 @@
+struct S {
+ float4 a;
+ int b;
+};
+
+RWByteAddressBuffer sb : register(u0, space0);
+
+S tint_symbol(RWByteAddressBuffer buffer, uint offset) {
+ const S tint_symbol_3 = {asfloat(buffer.Load4((offset + 0u))), asint(buffer.Load((offset + 16u)))};
+ return tint_symbol_3;
+}
+
+void main_1() {
+ const S x_18 = tint_symbol(sb, 32u);
+ return;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ main_1();
+ return;
+}
diff --git a/test/tint/bug/tint/1776.spvasm.expected.glsl b/test/tint/bug/tint/1776.spvasm.expected.glsl
new file mode 100644
index 0000000..e73e547
--- /dev/null
+++ b/test/tint/bug/tint/1776.spvasm.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+
+struct S {
+ vec4 a;
+ int b;
+ uint pad;
+ uint pad_1;
+ uint pad_2;
+};
+
+layout(binding = 0, std430) buffer sb_block_ssbo {
+ S inner[];
+} sb;
+
+void main_1() {
+ S x_18 = sb.inner[1];
+ return;
+}
+
+void tint_symbol() {
+ main_1();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/bug/tint/1776.spvasm.expected.msl b/test/tint/bug/tint/1776.spvasm.expected.msl
new file mode 100644
index 0000000..0933ac0
--- /dev/null
+++ b/test/tint/bug/tint/1776.spvasm.expected.msl
@@ -0,0 +1,36 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+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 S {
+ /* 0x0000 */ float4 a;
+ /* 0x0010 */ int b;
+ /* 0x0014 */ tint_array<int8_t, 12> tint_pad;
+};
+
+struct sb_block {
+ /* 0x0000 */ tint_array<S, 1> inner;
+};
+
+void main_1(device sb_block* const tint_symbol_1) {
+ S const x_18 = (*(tint_symbol_1)).inner[1];
+ return;
+}
+
+kernel void tint_symbol(device sb_block* tint_symbol_2 [[buffer(0)]]) {
+ main_1(tint_symbol_2);
+ return;
+}
+
diff --git a/test/tint/bug/tint/1776.spvasm.expected.spvasm b/test/tint/bug/tint/1776.spvasm.expected.spvasm
new file mode 100644
index 0000000..6e076d1
--- /dev/null
+++ b/test/tint/bug/tint/1776.spvasm.expected.spvasm
@@ -0,0 +1,49 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 22
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %sb_block "sb_block"
+ OpMemberName %sb_block 0 "inner"
+ OpName %S "S"
+ OpMemberName %S 0 "a"
+ OpMemberName %S 1 "b"
+ OpName %sb "sb"
+ OpName %main_1 "main_1"
+ OpName %main "main"
+ OpDecorate %sb_block Block
+ OpMemberDecorate %sb_block 0 Offset 0
+ OpMemberDecorate %S 0 Offset 0
+ OpMemberDecorate %S 1 Offset 16
+ OpDecorate %_runtimearr_S ArrayStride 32
+ OpDecorate %sb DescriptorSet 0
+ OpDecorate %sb Binding 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %int = OpTypeInt 32 1
+ %S = OpTypeStruct %v4float %int
+%_runtimearr_S = OpTypeRuntimeArray %S
+ %sb_block = OpTypeStruct %_runtimearr_S
+%_ptr_StorageBuffer_sb_block = OpTypePointer StorageBuffer %sb_block
+ %sb = OpVariable %_ptr_StorageBuffer_sb_block StorageBuffer
+ %void = OpTypeVoid
+ %9 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+ %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+ %main_1 = OpFunction %void None %9
+ %12 = OpLabel
+ %17 = OpAccessChain %_ptr_StorageBuffer_S %sb %uint_0 %int_1
+ %18 = OpLoad %S %17
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %9
+ %20 = OpLabel
+ %21 = OpFunctionCall %void %main_1
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/bug/tint/1776.spvasm.expected.wgsl b/test/tint/bug/tint/1776.spvasm.expected.wgsl
new file mode 100644
index 0000000..c5f6bc7
--- /dev/null
+++ b/test/tint/bug/tint/1776.spvasm.expected.wgsl
@@ -0,0 +1,25 @@
+struct S {
+ /* @offset(0) */
+ a : vec4<f32>,
+ /* @offset(16) */
+ b : i32,
+}
+
+type RTArr = array<S>;
+
+struct sb_block {
+ /* @offset(0) */
+ inner : RTArr,
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : sb_block;
+
+fn main_1() {
+ let x_18 : S = sb.inner[1i];
+ return;
+}
+
+@compute @workgroup_size(1i, 1i, 1i)
+fn main() {
+ main_1();
+}
diff --git a/test/tint/bug/tint/1776.wgsl b/test/tint/bug/tint/1776.wgsl
new file mode 100644
index 0000000..893b64c
--- /dev/null
+++ b/test/tint/bug/tint/1776.wgsl
@@ -0,0 +1,11 @@
+struct S { /* size: 32 align: 16 */
+ a : vec4<f32>,
+ b : i32,
+}
+
+@group(0) @binding(0) var<storage> sb : array<S>;
+
+@compute @workgroup_size(1)
+fn main() {
+ let x = sb[1];
+}
diff --git a/test/tint/bug/tint/1776.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/1776.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..36f87a7
--- /dev/null
+++ b/test/tint/bug/tint/1776.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+struct S {
+ float4 a;
+ int b;
+};
+
+ByteAddressBuffer sb : register(t0, space0);
+
+S tint_symbol(ByteAddressBuffer buffer, uint offset) {
+ const S tint_symbol_3 = {asfloat(buffer.Load4((offset + 0u))), asint(buffer.Load((offset + 16u)))};
+ return tint_symbol_3;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const S x = tint_symbol(sb, 32u);
+ return;
+}
diff --git a/test/tint/bug/tint/1776.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/1776.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..36f87a7
--- /dev/null
+++ b/test/tint/bug/tint/1776.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+struct S {
+ float4 a;
+ int b;
+};
+
+ByteAddressBuffer sb : register(t0, space0);
+
+S tint_symbol(ByteAddressBuffer buffer, uint offset) {
+ const S tint_symbol_3 = {asfloat(buffer.Load4((offset + 0u))), asint(buffer.Load((offset + 16u)))};
+ return tint_symbol_3;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ const S x = tint_symbol(sb, 32u);
+ return;
+}
diff --git a/test/tint/bug/tint/1776.wgsl.expected.glsl b/test/tint/bug/tint/1776.wgsl.expected.glsl
new file mode 100644
index 0000000..6a83ec2
--- /dev/null
+++ b/test/tint/bug/tint/1776.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+struct S {
+ vec4 a;
+ int b;
+ uint pad;
+ uint pad_1;
+ uint pad_2;
+};
+
+layout(binding = 0, std430) buffer sb_block_ssbo {
+ S inner[];
+} sb;
+
+void tint_symbol() {
+ S x = sb.inner[1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/bug/tint/1776.wgsl.expected.msl b/test/tint/bug/tint/1776.wgsl.expected.msl
new file mode 100644
index 0000000..38097d0
--- /dev/null
+++ b/test/tint/bug/tint/1776.wgsl.expected.msl
@@ -0,0 +1,31 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+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 S {
+ /* 0x0000 */ float4 a;
+ /* 0x0010 */ int b;
+ /* 0x0014 */ tint_array<int8_t, 12> tint_pad;
+};
+
+struct tint_symbol_2 {
+ /* 0x0000 */ tint_array<S, 1> arr;
+};
+
+kernel void tint_symbol(const device tint_symbol_2* tint_symbol_1 [[buffer(0)]]) {
+ S const x = (*(tint_symbol_1)).arr[1];
+ return;
+}
+
diff --git a/test/tint/bug/tint/1776.wgsl.expected.spvasm b/test/tint/bug/tint/1776.wgsl.expected.spvasm
new file mode 100644
index 0000000..3e85c9e
--- /dev/null
+++ b/test/tint/bug/tint/1776.wgsl.expected.spvasm
@@ -0,0 +1,44 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 19
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %sb_block "sb_block"
+ OpMemberName %sb_block 0 "inner"
+ OpName %S "S"
+ OpMemberName %S 0 "a"
+ OpMemberName %S 1 "b"
+ OpName %sb "sb"
+ OpName %main "main"
+ OpDecorate %sb_block Block
+ OpMemberDecorate %sb_block 0 Offset 0
+ OpMemberDecorate %S 0 Offset 0
+ OpMemberDecorate %S 1 Offset 16
+ OpDecorate %_runtimearr_S ArrayStride 32
+ OpDecorate %sb NonWritable
+ OpDecorate %sb DescriptorSet 0
+ OpDecorate %sb Binding 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %int = OpTypeInt 32 1
+ %S = OpTypeStruct %v4float %int
+%_runtimearr_S = OpTypeRuntimeArray %S
+ %sb_block = OpTypeStruct %_runtimearr_S
+%_ptr_StorageBuffer_sb_block = OpTypePointer StorageBuffer %sb_block
+ %sb = OpVariable %_ptr_StorageBuffer_sb_block StorageBuffer
+ %void = OpTypeVoid
+ %9 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+ %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+ %main = OpFunction %void None %9
+ %12 = OpLabel
+ %17 = OpAccessChain %_ptr_StorageBuffer_S %sb %uint_0 %int_1
+ %18 = OpLoad %S %17
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/bug/tint/1776.wgsl.expected.wgsl b/test/tint/bug/tint/1776.wgsl.expected.wgsl
new file mode 100644
index 0000000..08733dc
--- /dev/null
+++ b/test/tint/bug/tint/1776.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+struct S {
+ a : vec4<f32>,
+ b : i32,
+}
+
+@group(0) @binding(0) var<storage> sb : array<S>;
+
+@compute @workgroup_size(1)
+fn main() {
+ let x = sb[1];
+}
diff --git a/test/tint/bug/tint/870.spvasm.expected.glsl b/test/tint/bug/tint/870.spvasm.expected.glsl
index 0cddbf5..f56b3de 100644
--- a/test/tint/bug/tint/870.spvasm.expected.glsl
+++ b/test/tint/bug/tint/870.spvasm.expected.glsl
@@ -6,6 +6,7 @@
vec4 offset;
int essence;
int orientation[6];
+ uint pad;
};
struct x_B4_BuildInformation {
diff --git a/test/tint/bug/tint/870.spvasm.expected.msl b/test/tint/bug/tint/870.spvasm.expected.msl
index 9a97441..408a9712 100644
--- a/test/tint/bug/tint/870.spvasm.expected.msl
+++ b/test/tint/bug/tint/870.spvasm.expected.msl
@@ -19,6 +19,7 @@
/* 0x0010 */ float4 offset;
/* 0x0020 */ int essence;
/* 0x0024 */ tint_array<int, 6> orientation;
+ /* 0x003c */ tint_array<int8_t, 4> tint_pad;
};
struct x_B4_BuildInformation {