Add semantic::Struct::SizeNoPadding

This is the size of the structure without the trailing alignment
padding. This is what the Dawn needs from the Inspector.

Fixed: tint:653
Change-Id: Iaa01ba949e114973e4a33e084fc10ef9e111016c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/45120
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index 2447ce4..88e7600 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -392,6 +392,7 @@
     entry.bind_group = binding_info.group->value();
     entry.binding = binding_info.binding->value();
     entry.size = sem->Size();
+    entry.size_no_padding = sem->SizeNoPadding();
 
     result.push_back(entry);
   }
@@ -567,6 +568,7 @@
     entry.bind_group = binding_info.group->value();
     entry.binding = binding_info.binding->value();
     entry.size = sem->Size();
+    entry.size_no_padding = sem->SizeNoPadding();
 
     result.push_back(entry);
   }
diff --git a/src/inspector/inspector.h b/src/inspector/inspector.h
index ec91efb..3d9efcd 100644
--- a/src/inspector/inspector.h
+++ b/src/inspector/inspector.h
@@ -114,6 +114,9 @@
   uint32_t binding;
   /// Size for this binding, in bytes, if defined.
   uint64_t size;
+  /// Size for this binding without trailing structure padding, in bytes, if
+  /// defined.
+  uint64_t size_no_padding;
   /// Dimensionality of this binding, if defined.
   TextureDimension dim;
   /// Kind of data being sampled, if defined.
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index 1ecb28b..c1a3a42 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -1573,6 +1573,7 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(4u, result[0].size);
+  EXPECT_EQ(4u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleMembers) {
@@ -1600,6 +1601,35 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(12u, result[0].size);
+  EXPECT_EQ(12u, result[0].size_no_padding);
+}
+
+TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingPadding) {
+  type::Struct* foo_struct_type =
+      MakeUniformBufferType("foo_type", {ty.vec3<f32>()});
+  AddUniformBuffer("foo_ub", foo_struct_type, 0, 0);
+
+  MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
+                                          {{0, ty.vec3<f32>()}});
+
+  MakeCallerBodyFunction(
+      "ep_func", {"ub_func"},
+      ast::DecorationList{
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+      });
+
+  Inspector& inspector = Build();
+
+  auto result = inspector.GetUniformBufferResourceBindings("ep_func");
+  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+  ASSERT_EQ(1u, result.size());
+
+  EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
+            result[0].resource_type);
+  EXPECT_EQ(0u, result[0].bind_group);
+  EXPECT_EQ(0u, result[0].binding);
+  EXPECT_EQ(16u, result[0].size);
+  EXPECT_EQ(12u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleUniformBuffers) {
@@ -1641,18 +1671,21 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(12u, result[0].size);
+  EXPECT_EQ(12u, result[0].size_no_padding);
 
   EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
             result[1].resource_type);
   EXPECT_EQ(0u, result[1].bind_group);
   EXPECT_EQ(1u, result[1].binding);
   EXPECT_EQ(12u, result[1].size);
+  EXPECT_EQ(12u, result[1].size_no_padding);
 
   EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
             result[2].resource_type);
   EXPECT_EQ(2u, result[2].bind_group);
   EXPECT_EQ(0u, result[2].binding);
   EXPECT_EQ(12u, result[2].size);
+  EXPECT_EQ(12u, result[2].size_no_padding);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingArray) {
@@ -1682,6 +1715,7 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(20u, result[0].size);
+  EXPECT_EQ(20u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple) {
@@ -1710,6 +1744,7 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(4u, result[0].size);
+  EXPECT_EQ(4u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleMembers) {
@@ -1739,6 +1774,7 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(12u, result[0].size);
+  EXPECT_EQ(12u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
@@ -1785,18 +1821,21 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(12u, result[0].size);
+  EXPECT_EQ(12u, result[0].size_no_padding);
 
   EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
             result[1].resource_type);
   EXPECT_EQ(0u, result[1].bind_group);
   EXPECT_EQ(1u, result[1].binding);
   EXPECT_EQ(12u, result[1].size);
+  EXPECT_EQ(12u, result[1].size_no_padding);
 
   EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
             result[2].resource_type);
   EXPECT_EQ(2u, result[2].bind_group);
   EXPECT_EQ(0u, result[2].binding);
   EXPECT_EQ(12u, result[2].size);
+  EXPECT_EQ(12u, result[2].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingArray) {
@@ -1825,6 +1864,7 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(20u, result[0].size);
+  EXPECT_EQ(20u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingRuntimeArray) {
@@ -1853,6 +1893,37 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(8u, result[0].size);
+  EXPECT_EQ(8u, result[0].size_no_padding);
+}
+
+TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingPadding) {
+  type::Struct* foo_struct_type;
+  type::AccessControl* foo_control_type;
+  std::tie(foo_struct_type, foo_control_type) =
+      MakeStorageBufferTypes("foo_type", {ty.vec3<f32>()});
+  AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
+
+  MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
+                                          {{0, ty.vec3<f32>()}});
+
+  MakeCallerBodyFunction(
+      "ep_func", {"sb_func"},
+      ast::DecorationList{
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+      });
+
+  Inspector& inspector = Build();
+
+  auto result = inspector.GetStorageBufferResourceBindings("ep_func");
+  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+  ASSERT_EQ(1u, result.size());
+
+  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
+            result[0].resource_type);
+  EXPECT_EQ(0u, result[0].bind_group);
+  EXPECT_EQ(0u, result[0].binding);
+  EXPECT_EQ(16u, result[0].size);
+  EXPECT_EQ(12u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, SkipReadOnly) {
@@ -1903,6 +1974,7 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(4u, result[0].size);
+  EXPECT_EQ(4u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
@@ -1950,18 +2022,21 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(12u, result[0].size);
+  EXPECT_EQ(12u, result[0].size_no_padding);
 
   EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
             result[1].resource_type);
   EXPECT_EQ(0u, result[1].bind_group);
   EXPECT_EQ(1u, result[1].binding);
   EXPECT_EQ(12u, result[1].size);
+  EXPECT_EQ(12u, result[1].size_no_padding);
 
   EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
             result[2].resource_type);
   EXPECT_EQ(2u, result[2].bind_group);
   EXPECT_EQ(0u, result[2].binding);
   EXPECT_EQ(12u, result[2].size);
+  EXPECT_EQ(12u, result[2].size_no_padding);
 }
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingArray) {
@@ -1990,6 +2065,7 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(20u, result[0].size);
+  EXPECT_EQ(20u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
@@ -2019,6 +2095,7 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(8u, result[0].size);
+  EXPECT_EQ(8u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, SkipNonReadOnly) {
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index c5711bf..fcb9164 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -1448,10 +1448,11 @@
     struct_align = std::max(struct_align, align);
   }
 
+  auto size_no_padding = struct_size;
   struct_size = utils::RoundUp(struct_align, struct_size);
 
-  auto* sem = builder_->create<semantic::Struct>(str, std::move(sem_members),
-                                                 struct_align, struct_size);
+  auto* sem = builder_->create<semantic::Struct>(
+      str, std::move(sem_members), struct_align, struct_size, size_no_padding);
   builder_->Sem().Add(str, sem);
   return sem;
 }
diff --git a/src/resolver/struct_layout_test.cc b/src/resolver/struct_layout_test.cc
index 53dd37b..f77e5e3 100644
--- a/src/resolver/struct_layout_test.cc
+++ b/src/resolver/struct_layout_test.cc
@@ -36,13 +36,17 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 12u);
+  EXPECT_EQ(sem->SizeNoPadding(), 12u);
   EXPECT_EQ(sem->Align(), 4u);
   ASSERT_EQ(sem->Members().size(), 3u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
   EXPECT_EQ(sem->Members()[0]->Size(), 4u);
   EXPECT_EQ(sem->Members()[1]->Offset(), 4u);
+  EXPECT_EQ(sem->Members()[1]->Align(), 4u);
   EXPECT_EQ(sem->Members()[1]->Size(), 4u);
   EXPECT_EQ(sem->Members()[2]->Offset(), 8u);
+  EXPECT_EQ(sem->Members()[2]->Align(), 4u);
   EXPECT_EQ(sem->Members()[2]->Size(), 4u);
 }
 
@@ -57,11 +61,14 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 8u);
+  EXPECT_EQ(sem->SizeNoPadding(), 8u);
   EXPECT_EQ(sem->Align(), 4u);
   ASSERT_EQ(sem->Members().size(), 2u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
   EXPECT_EQ(sem->Members()[0]->Size(), 4u);
   EXPECT_EQ(sem->Members()[1]->Offset(), 4u);
+  EXPECT_EQ(sem->Members()[1]->Align(), 4u);
   EXPECT_EQ(sem->Members()[1]->Size(), 4u);
 }
 
@@ -77,13 +84,17 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 36u);
+  EXPECT_EQ(sem->SizeNoPadding(), 36u);
   EXPECT_EQ(sem->Align(), 4u);
   ASSERT_EQ(sem->Members().size(), 3u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
   EXPECT_EQ(sem->Members()[0]->Size(), 12u);
   EXPECT_EQ(sem->Members()[1]->Offset(), 12u);
+  EXPECT_EQ(sem->Members()[1]->Align(), 4u);
   EXPECT_EQ(sem->Members()[1]->Size(), 20u);
   EXPECT_EQ(sem->Members()[2]->Offset(), 32u);
+  EXPECT_EQ(sem->Members()[2]->Align(), 4u);
   EXPECT_EQ(sem->Members()[2]->Size(), 4u);
 }
 
@@ -99,13 +110,17 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 136u);
+  EXPECT_EQ(sem->SizeNoPadding(), 136u);
   EXPECT_EQ(sem->Align(), 4u);
   ASSERT_EQ(sem->Members().size(), 3u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
   EXPECT_EQ(sem->Members()[0]->Size(), 24u);
   EXPECT_EQ(sem->Members()[1]->Offset(), 24u);
+  EXPECT_EQ(sem->Members()[1]->Align(), 4u);
   EXPECT_EQ(sem->Members()[1]->Size(), 80u);
   EXPECT_EQ(sem->Members()[2]->Offset(), 104u);
+  EXPECT_EQ(sem->Members()[2]->Align(), 4u);
   EXPECT_EQ(sem->Members()[2]->Size(), 32u);
 }
 
@@ -119,9 +134,11 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 4u);
+  EXPECT_EQ(sem->SizeNoPadding(), 4u);
   EXPECT_EQ(sem->Align(), 4u);
   ASSERT_EQ(sem->Members().size(), 1u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
   EXPECT_EQ(sem->Members()[0]->Size(), 4u);
 }
 
@@ -135,9 +152,11 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 32u);
+  EXPECT_EQ(sem->SizeNoPadding(), 32u);
   EXPECT_EQ(sem->Align(), 4u);
   ASSERT_EQ(sem->Members().size(), 1u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
   EXPECT_EQ(sem->Members()[0]->Size(), 32u);
 }
 
@@ -153,9 +172,11 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 384u);
+  EXPECT_EQ(sem->SizeNoPadding(), 384u);
   EXPECT_EQ(sem->Align(), 4u);
   ASSERT_EQ(sem->Members().size(), 1u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
   EXPECT_EQ(sem->Members()[0]->Size(), 384u);
 }
 
@@ -175,9 +196,11 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 576u);
+  EXPECT_EQ(sem->SizeNoPadding(), 576u);
   EXPECT_EQ(sem->Align(), 16u);
   ASSERT_EQ(sem->Members().size(), 1u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  EXPECT_EQ(sem->Members()[0]->Align(), 16u);
   EXPECT_EQ(sem->Members()[0]->Size(), 576u);
 }
 
@@ -193,13 +216,17 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 48u);
+  EXPECT_EQ(sem->SizeNoPadding(), 48u);
   EXPECT_EQ(sem->Align(), 16u);
   ASSERT_EQ(sem->Members().size(), 3u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);  // vec2
+  EXPECT_EQ(sem->Members()[0]->Align(), 8u);
   EXPECT_EQ(sem->Members()[0]->Size(), 8u);
   EXPECT_EQ(sem->Members()[1]->Offset(), 16u);  // vec3
+  EXPECT_EQ(sem->Members()[1]->Align(), 16u);
   EXPECT_EQ(sem->Members()[1]->Size(), 12u);
   EXPECT_EQ(sem->Members()[2]->Offset(), 32u);  // vec4
+  EXPECT_EQ(sem->Members()[2]->Align(), 16u);
   EXPECT_EQ(sem->Members()[2]->Size(), 16u);
 }
 
@@ -221,25 +248,35 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 368u);
+  EXPECT_EQ(sem->SizeNoPadding(), 368u);
   EXPECT_EQ(sem->Align(), 16u);
   ASSERT_EQ(sem->Members().size(), 9u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);  // mat2x2
+  EXPECT_EQ(sem->Members()[0]->Align(), 8u);
   EXPECT_EQ(sem->Members()[0]->Size(), 16u);
   EXPECT_EQ(sem->Members()[1]->Offset(), 16u);  // mat2x3
+  EXPECT_EQ(sem->Members()[1]->Align(), 16u);
   EXPECT_EQ(sem->Members()[1]->Size(), 32u);
   EXPECT_EQ(sem->Members()[2]->Offset(), 48u);  // mat2x4
+  EXPECT_EQ(sem->Members()[2]->Align(), 16u);
   EXPECT_EQ(sem->Members()[2]->Size(), 32u);
   EXPECT_EQ(sem->Members()[3]->Offset(), 80u);  // mat3x2
+  EXPECT_EQ(sem->Members()[3]->Align(), 8u);
   EXPECT_EQ(sem->Members()[3]->Size(), 24u);
   EXPECT_EQ(sem->Members()[4]->Offset(), 112u);  // mat3x3
+  EXPECT_EQ(sem->Members()[4]->Align(), 16u);
   EXPECT_EQ(sem->Members()[4]->Size(), 48u);
   EXPECT_EQ(sem->Members()[5]->Offset(), 160u);  // mat3x4
+  EXPECT_EQ(sem->Members()[5]->Align(), 16u);
   EXPECT_EQ(sem->Members()[5]->Size(), 48u);
   EXPECT_EQ(sem->Members()[6]->Offset(), 208u);  // mat4x2
+  EXPECT_EQ(sem->Members()[6]->Align(), 8u);
   EXPECT_EQ(sem->Members()[6]->Size(), 32u);
   EXPECT_EQ(sem->Members()[7]->Offset(), 240u);  // mat4x3
+  EXPECT_EQ(sem->Members()[7]->Align(), 16u);
   EXPECT_EQ(sem->Members()[7]->Size(), 64u);
   EXPECT_EQ(sem->Members()[8]->Offset(), 304u);  // mat4x4
+  EXPECT_EQ(sem->Members()[8]->Align(), 16u);
   EXPECT_EQ(sem->Members()[8]->Size(), 64u);
 }
 
@@ -258,13 +295,17 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 80u);
+  EXPECT_EQ(sem->SizeNoPadding(), 68u);
   EXPECT_EQ(sem->Align(), 16u);
   ASSERT_EQ(sem->Members().size(), 3u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
   EXPECT_EQ(sem->Members()[0]->Size(), 4u);
   EXPECT_EQ(sem->Members()[1]->Offset(), 16u);
+  EXPECT_EQ(sem->Members()[1]->Align(), 16u);
   EXPECT_EQ(sem->Members()[1]->Size(), 48u);
   EXPECT_EQ(sem->Members()[2]->Offset(), 64u);
+  EXPECT_EQ(sem->Members()[2]->Align(), 4u);
   EXPECT_EQ(sem->Members()[2]->Size(), 4u);
 }
 
@@ -286,15 +327,20 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 76u);
+  EXPECT_EQ(sem->SizeNoPadding(), 76u);
   EXPECT_EQ(sem->Align(), 4u);
   ASSERT_EQ(sem->Members().size(), 4u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
   EXPECT_EQ(sem->Members()[0]->Size(), 4u);
   EXPECT_EQ(sem->Members()[1]->Offset(), 4u);
+  EXPECT_EQ(sem->Members()[1]->Align(), 4u);
   EXPECT_EQ(sem->Members()[1]->Size(), 8u);
   EXPECT_EQ(sem->Members()[2]->Offset(), 12u);
+  EXPECT_EQ(sem->Members()[2]->Align(), 4u);
   EXPECT_EQ(sem->Members()[2]->Size(), 32u);
   EXPECT_EQ(sem->Members()[3]->Offset(), 44u);
+  EXPECT_EQ(sem->Members()[3]->Align(), 4u);
   EXPECT_EQ(sem->Members()[3]->Size(), 32u);
 }
 
@@ -316,18 +362,41 @@
   auto* sem = Sem().Get(s);
   ASSERT_NE(sem, nullptr);
   EXPECT_EQ(sem->Size(), 96u);
+  EXPECT_EQ(sem->SizeNoPadding(), 68u);
   EXPECT_EQ(sem->Align(), 32u);
   ASSERT_EQ(sem->Members().size(), 4u);
   EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  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(), 8u);
   EXPECT_EQ(sem->Members()[1]->Size(), 4u);
   EXPECT_EQ(sem->Members()[2]->Offset(), 16u);
+  EXPECT_EQ(sem->Members()[2]->Align(), 16u);
   EXPECT_EQ(sem->Members()[2]->Size(), 32u);
   EXPECT_EQ(sem->Members()[3]->Offset(), 64u);
+  EXPECT_EQ(sem->Members()[3]->Align(), 32u);
   EXPECT_EQ(sem->Members()[3]->Size(), 4u);
 }
 
+TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) {
+  auto* s = Structure("S", {
+                               Member("a", ty.i32(), {MemberAlign(1024)}),
+                           });
+
+  ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+  auto* sem = Sem().Get(s);
+  ASSERT_NE(sem, nullptr);
+  EXPECT_EQ(sem->Size(), 1024u);
+  EXPECT_EQ(sem->SizeNoPadding(), 4u);
+  EXPECT_EQ(sem->Align(), 1024u);
+  ASSERT_EQ(sem->Members().size(), 1u);
+  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+  EXPECT_EQ(sem->Members()[0]->Align(), 1024u);
+  EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+}
+
 }  // namespace
 }  // namespace resolver
 }  // namespace tint
diff --git a/src/semantic/sem_struct.cc b/src/semantic/sem_struct.cc
index 7050385..c1379f8 100644
--- a/src/semantic/sem_struct.cc
+++ b/src/semantic/sem_struct.cc
@@ -23,8 +23,13 @@
 Struct::Struct(type::Struct* type,
                StructMemberList members,
                uint32_t align,
-               uint32_t size)
-    : type_(type), members_(std::move(members)), align_(align), size_(size) {}
+               uint32_t size,
+               uint32_t size_no_padding)
+    : type_(type),
+      members_(std::move(members)),
+      align_(align),
+      size_(size),
+      size_no_padding_(size_no_padding) {}
 
 Struct::~Struct() = default;
 
diff --git a/src/semantic/struct.h b/src/semantic/struct.h
index 0a80a0e..08db295 100644
--- a/src/semantic/struct.h
+++ b/src/semantic/struct.h
@@ -46,10 +46,13 @@
   /// @param members the structure members
   /// @param align the byte alignment of the structure
   /// @param size the byte size of the structure
+  /// @param size_no_padding size of the members without the end of structure
+  /// alignment padding
   Struct(type::Struct* type,
          StructMemberList members,
          uint32_t align,
-         uint32_t size);
+         uint32_t size,
+         uint32_t size_no_padding);
 
   /// Destructor
   ~Struct() override;
@@ -72,11 +75,16 @@
   /// decoration.
   uint32_t Size() const { return size_; }
 
+  /// @returns the byte size of the members without the end of structure
+  /// alignment padding
+  uint32_t SizeNoPadding() const { return size_no_padding_; }
+
  private:
   type::Struct* const type_;
   StructMemberList const members_;
   uint32_t const align_;
   uint32_t const size_;
+  uint32_t const size_no_padding_;
 };
 
 /// StructMember holds the semantic information for structure members.