[hlsl] Add `arrayLength` tests.
Now that DecomposeMemoryAccess transform supports `arrayLength` this CL
adds various tests. The support for directly accessing the storage
buffer in the `arrayLength` call is added.
Bug: 349867642
Change-Id: Idf4a86323775e6d48b2f379398aad47b22bc7dc8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/196969
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/hlsl/hlsl.def b/src/tint/lang/hlsl/hlsl.def
index 627646d..4378ba6 100644
--- a/src/tint/lang/hlsl/hlsl.def
+++ b/src/tint/lang/hlsl/hlsl.def
@@ -74,6 +74,7 @@
match f32_f16: f32 | f16
match storage: address_space.storage
+match function: address_space.function
match readable
: access.read
@@ -119,5 +120,5 @@
@member_function fn Store3(byte_address_buffer<writable>, offset: u32, value: vec3<u32>)
@member_function fn Store4(byte_address_buffer<writable>, offset: u32, value: vec4<u32>)
-@member_function fn GetDimensions[A: access](byte_address_buffer<A>, u32)
+@member_function fn GetDimensions[A: access](byte_address_buffer<A>, ptr<function, u32, writable>)
diff --git a/src/tint/lang/hlsl/intrinsic/data.cc b/src/tint/lang/hlsl/intrinsic/data.cc
index dc2b89e..4232917 100644
--- a/src/tint/lang/hlsl/intrinsic/data.cc
+++ b/src/tint/lang/hlsl/intrinsic/data.cc
@@ -562,6 +562,19 @@
}
};
+/// EnumMatcher for 'match function'
+constexpr NumberMatcher kFunctionMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+ if (number.IsAny() || number.Value() == static_cast<uint32_t>(core::AddressSpace::kFunction)) {
+ return Number(static_cast<uint32_t>(core::AddressSpace::kFunction));
+ }
+ return Number::invalid;
+ },
+/* print */ [](MatchState*, StyledText& out) {
+ out<< style::Enum("function");
+ }
+};
+
/// EnumMatcher for 'match readable'
constexpr NumberMatcher kReadableMatcher {
/* match */ [](MatchState&, Number number) -> Number {
@@ -635,8 +648,9 @@
/* [2] */ TemplateNumberMatcher<2>::matcher,
/* [3] */ TemplateNumberMatcher<3>::matcher,
/* [4] */ kStorageMatcher,
- /* [5] */ kReadableMatcher,
- /* [6] */ kWritableMatcher,
+ /* [5] */ kFunctionMatcher,
+ /* [6] */ kReadableMatcher,
+ /* [7] */ kWritableMatcher,
};
constexpr MatcherIndex kMatcherIndices[] = {
@@ -656,49 +670,53 @@
/* [13] */ MatcherIndex(2),
/* [14] */ MatcherIndex(1),
/* [15] */ MatcherIndex(0),
- /* [16] */ MatcherIndex(12),
- /* [17] */ MatcherIndex(1),
- /* [18] */ MatcherIndex(4),
- /* [19] */ MatcherIndex(12),
- /* [20] */ MatcherIndex(1),
- /* [21] */ MatcherIndex(0),
- /* [22] */ MatcherIndex(12),
- /* [23] */ MatcherIndex(1),
- /* [24] */ MatcherIndex(5),
- /* [25] */ MatcherIndex(12),
- /* [26] */ MatcherIndex(1),
- /* [27] */ MatcherIndex(6),
- /* [28] */ MatcherIndex(12),
- /* [29] */ MatcherIndex(0),
- /* [30] */ MatcherIndex(5),
- /* [31] */ MatcherIndex(12),
- /* [32] */ MatcherIndex(0),
- /* [33] */ MatcherIndex(6),
- /* [34] */ MatcherIndex(12),
- /* [35] */ MatcherIndex(2),
+ /* [16] */ MatcherIndex(8),
+ /* [17] */ MatcherIndex(5),
+ /* [18] */ MatcherIndex(5),
+ /* [19] */ MatcherIndex(7),
+ /* [20] */ MatcherIndex(12),
+ /* [21] */ MatcherIndex(1),
+ /* [22] */ MatcherIndex(4),
+ /* [23] */ MatcherIndex(12),
+ /* [24] */ MatcherIndex(1),
+ /* [25] */ MatcherIndex(0),
+ /* [26] */ MatcherIndex(12),
+ /* [27] */ MatcherIndex(1),
+ /* [28] */ MatcherIndex(5),
+ /* [29] */ MatcherIndex(12),
+ /* [30] */ MatcherIndex(1),
+ /* [31] */ MatcherIndex(6),
+ /* [32] */ MatcherIndex(12),
+ /* [33] */ MatcherIndex(0),
+ /* [34] */ MatcherIndex(5),
+ /* [35] */ MatcherIndex(12),
/* [36] */ MatcherIndex(0),
- /* [37] */ MatcherIndex(23),
- /* [38] */ MatcherIndex(5),
- /* [39] */ MatcherIndex(9),
- /* [40] */ MatcherIndex(5),
- /* [41] */ MatcherIndex(10),
- /* [42] */ MatcherIndex(5),
- /* [43] */ MatcherIndex(11),
+ /* [37] */ MatcherIndex(6),
+ /* [38] */ MatcherIndex(12),
+ /* [39] */ MatcherIndex(2),
+ /* [40] */ MatcherIndex(0),
+ /* [41] */ MatcherIndex(23),
+ /* [42] */ MatcherIndex(6),
+ /* [43] */ MatcherIndex(9),
/* [44] */ MatcherIndex(5),
- /* [45] */ MatcherIndex(9),
- /* [46] */ MatcherIndex(7),
- /* [47] */ MatcherIndex(10),
- /* [48] */ MatcherIndex(7),
- /* [49] */ MatcherIndex(11),
+ /* [45] */ MatcherIndex(10),
+ /* [46] */ MatcherIndex(5),
+ /* [47] */ MatcherIndex(11),
+ /* [48] */ MatcherIndex(5),
+ /* [49] */ MatcherIndex(9),
/* [50] */ MatcherIndex(7),
- /* [51] */ MatcherIndex(23),
- /* [52] */ MatcherIndex(6),
- /* [53] */ MatcherIndex(23),
- /* [54] */ MatcherIndex(0),
- /* [55] */ MatcherIndex(25),
- /* [56] */ MatcherIndex(26),
- /* [57] */ MatcherIndex(24),
- /* [58] */ MatcherIndex(27),
+ /* [51] */ MatcherIndex(10),
+ /* [52] */ MatcherIndex(7),
+ /* [53] */ MatcherIndex(11),
+ /* [54] */ MatcherIndex(7),
+ /* [55] */ MatcherIndex(23),
+ /* [56] */ MatcherIndex(7),
+ /* [57] */ MatcherIndex(23),
+ /* [58] */ MatcherIndex(0),
+ /* [59] */ MatcherIndex(25),
+ /* [60] */ MatcherIndex(26),
+ /* [61] */ MatcherIndex(24),
+ /* [62] */ MatcherIndex(27),
};
static_assert(MatcherIndicesIndex::CanIndex(kMatcherIndices),
@@ -708,62 +726,62 @@
{
/* [0] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(51),
+ /* matcher_indices */ MatcherIndicesIndex(55),
},
{
/* [1] */
/* usage */ core::ParameterUsage::kOffset,
- /* matcher_indices */ MatcherIndicesIndex(24),
+ /* matcher_indices */ MatcherIndicesIndex(17),
},
{
/* [2] */
/* usage */ core::ParameterUsage::kValue,
- /* matcher_indices */ MatcherIndicesIndex(24),
+ /* matcher_indices */ MatcherIndicesIndex(17),
},
{
/* [3] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(51),
+ /* matcher_indices */ MatcherIndicesIndex(55),
},
{
/* [4] */
/* usage */ core::ParameterUsage::kOffset,
- /* matcher_indices */ MatcherIndicesIndex(24),
+ /* matcher_indices */ MatcherIndicesIndex(17),
},
{
/* [5] */
/* usage */ core::ParameterUsage::kValue,
- /* matcher_indices */ MatcherIndicesIndex(39),
+ /* matcher_indices */ MatcherIndicesIndex(43),
},
{
/* [6] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(51),
+ /* matcher_indices */ MatcherIndicesIndex(55),
},
{
/* [7] */
/* usage */ core::ParameterUsage::kOffset,
- /* matcher_indices */ MatcherIndicesIndex(24),
+ /* matcher_indices */ MatcherIndicesIndex(17),
},
{
/* [8] */
/* usage */ core::ParameterUsage::kValue,
- /* matcher_indices */ MatcherIndicesIndex(41),
+ /* matcher_indices */ MatcherIndicesIndex(45),
},
{
/* [9] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(51),
+ /* matcher_indices */ MatcherIndicesIndex(55),
},
{
/* [10] */
/* usage */ core::ParameterUsage::kOffset,
- /* matcher_indices */ MatcherIndicesIndex(24),
+ /* matcher_indices */ MatcherIndicesIndex(17),
},
{
/* [11] */
/* usage */ core::ParameterUsage::kValue,
- /* matcher_indices */ MatcherIndicesIndex(43),
+ /* matcher_indices */ MatcherIndicesIndex(47),
},
{
/* [12] */
@@ -773,12 +791,12 @@
{
/* [13] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(19),
+ /* matcher_indices */ MatcherIndicesIndex(23),
},
{
/* [14] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(34),
+ /* matcher_indices */ MatcherIndicesIndex(38),
},
{
/* [15] */
@@ -798,22 +816,22 @@
{
/* [18] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(37),
+ /* matcher_indices */ MatcherIndicesIndex(41),
},
{
/* [19] */
/* usage */ core::ParameterUsage::kOffset,
- /* matcher_indices */ MatcherIndicesIndex(24),
+ /* matcher_indices */ MatcherIndicesIndex(17),
},
{
/* [20] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(53),
+ /* matcher_indices */ MatcherIndicesIndex(57),
},
{
/* [21] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(24),
+ /* matcher_indices */ MatcherIndicesIndex(16),
},
{
/* [22] */
@@ -823,17 +841,22 @@
{
/* [23] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(27),
+ /* matcher_indices */ MatcherIndicesIndex(31),
},
{
/* [24] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(31),
+ /* matcher_indices */ MatcherIndicesIndex(35),
},
{
/* [25] */
/* usage */ core::ParameterUsage::kNone,
- /* matcher_indices */ MatcherIndicesIndex(28),
+ /* matcher_indices */ MatcherIndicesIndex(17),
+ },
+ {
+ /* [26] */
+ /* usage */ core::ParameterUsage::kNone,
+ /* matcher_indices */ MatcherIndicesIndex(32),
},
};
@@ -844,7 +867,7 @@
{
/* [0] */
/* name */ "T",
- /* matcher_indices */ MatcherIndicesIndex(58),
+ /* matcher_indices */ MatcherIndicesIndex(62),
/* kind */ TemplateInfo::Kind::kType,
},
{
@@ -868,7 +891,7 @@
{
/* [4] */
/* name */ "T",
- /* matcher_indices */ MatcherIndicesIndex(58),
+ /* matcher_indices */ MatcherIndicesIndex(62),
/* kind */ TemplateInfo::Kind::kType,
},
{
@@ -886,7 +909,7 @@
{
/* [7] */
/* name */ "T",
- /* matcher_indices */ MatcherIndicesIndex(55),
+ /* matcher_indices */ MatcherIndicesIndex(59),
/* kind */ TemplateInfo::Kind::kType,
},
{
@@ -898,7 +921,7 @@
{
/* [9] */
/* name */ "T",
- /* matcher_indices */ MatcherIndicesIndex(56),
+ /* matcher_indices */ MatcherIndicesIndex(60),
/* kind */ TemplateInfo::Kind::kType,
},
{
@@ -910,7 +933,7 @@
{
/* [11] */
/* name */ "T",
- /* matcher_indices */ MatcherIndicesIndex(57),
+ /* matcher_indices */ MatcherIndicesIndex(61),
/* kind */ TemplateInfo::Kind::kType,
},
{
@@ -939,7 +962,7 @@
/* num_templates */ 3,
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(12),
- /* return_matcher_indices */ MatcherIndicesIndex(34),
+ /* return_matcher_indices */ MatcherIndicesIndex(38),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -950,7 +973,7 @@
/* num_templates */ 3,
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(14),
- /* return_matcher_indices */ MatcherIndicesIndex(19),
+ /* return_matcher_indices */ MatcherIndicesIndex(23),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -972,7 +995,7 @@
/* num_templates */ 1,
/* templates */ TemplateIndex(7),
/* parameters */ ParameterIndex(22),
- /* return_matcher_indices */ MatcherIndicesIndex(18),
+ /* return_matcher_indices */ MatcherIndicesIndex(22),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -983,7 +1006,7 @@
/* num_templates */ 2,
/* templates */ TemplateIndex(7),
/* parameters */ ParameterIndex(13),
- /* return_matcher_indices */ MatcherIndicesIndex(16),
+ /* return_matcher_indices */ MatcherIndicesIndex(20),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -994,7 +1017,7 @@
/* num_templates */ 1,
/* templates */ TemplateIndex(9),
/* parameters */ ParameterIndex(22),
- /* return_matcher_indices */ MatcherIndicesIndex(24),
+ /* return_matcher_indices */ MatcherIndicesIndex(17),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1005,7 +1028,7 @@
/* num_templates */ 2,
/* templates */ TemplateIndex(9),
/* parameters */ ParameterIndex(13),
- /* return_matcher_indices */ MatcherIndicesIndex(22),
+ /* return_matcher_indices */ MatcherIndicesIndex(26),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1016,7 +1039,7 @@
/* num_templates */ 1,
/* templates */ TemplateIndex(11),
/* parameters */ ParameterIndex(22),
- /* return_matcher_indices */ MatcherIndicesIndex(27),
+ /* return_matcher_indices */ MatcherIndicesIndex(31),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1027,7 +1050,7 @@
/* num_templates */ 2,
/* templates */ TemplateIndex(11),
/* parameters */ ParameterIndex(13),
- /* return_matcher_indices */ MatcherIndicesIndex(25),
+ /* return_matcher_indices */ MatcherIndicesIndex(29),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1038,7 +1061,7 @@
/* num_templates */ 0,
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(23),
- /* return_matcher_indices */ MatcherIndicesIndex(24),
+ /* return_matcher_indices */ MatcherIndicesIndex(17),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1049,7 +1072,7 @@
/* num_templates */ 1,
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(24),
- /* return_matcher_indices */ MatcherIndicesIndex(28),
+ /* return_matcher_indices */ MatcherIndicesIndex(32),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1059,8 +1082,8 @@
/* num_explicit_templates */ 0,
/* num_templates */ 0,
/* templates */ TemplateIndex(/* invalid */),
- /* parameters */ ParameterIndex(21),
- /* return_matcher_indices */ MatcherIndicesIndex(27),
+ /* parameters */ ParameterIndex(25),
+ /* return_matcher_indices */ MatcherIndicesIndex(31),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1070,8 +1093,8 @@
/* num_explicit_templates */ 0,
/* num_templates */ 1,
/* templates */ TemplateIndex(8),
- /* parameters */ ParameterIndex(25),
- /* return_matcher_indices */ MatcherIndicesIndex(31),
+ /* parameters */ ParameterIndex(26),
+ /* return_matcher_indices */ MatcherIndicesIndex(35),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1082,7 +1105,7 @@
/* num_templates */ 0,
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(18),
- /* return_matcher_indices */ MatcherIndicesIndex(24),
+ /* return_matcher_indices */ MatcherIndicesIndex(17),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1093,7 +1116,7 @@
/* num_templates */ 0,
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(18),
- /* return_matcher_indices */ MatcherIndicesIndex(39),
+ /* return_matcher_indices */ MatcherIndicesIndex(43),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1104,7 +1127,7 @@
/* num_templates */ 0,
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(18),
- /* return_matcher_indices */ MatcherIndicesIndex(41),
+ /* return_matcher_indices */ MatcherIndicesIndex(45),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1115,7 +1138,7 @@
/* num_templates */ 0,
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(18),
- /* return_matcher_indices */ MatcherIndicesIndex(43),
+ /* return_matcher_indices */ MatcherIndicesIndex(47),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1126,7 +1149,7 @@
/* num_templates */ 0,
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(18),
- /* return_matcher_indices */ MatcherIndicesIndex(46),
+ /* return_matcher_indices */ MatcherIndicesIndex(19),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1137,7 +1160,7 @@
/* num_templates */ 0,
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(18),
- /* return_matcher_indices */ MatcherIndicesIndex(45),
+ /* return_matcher_indices */ MatcherIndicesIndex(49),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1148,7 +1171,7 @@
/* num_templates */ 0,
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(18),
- /* return_matcher_indices */ MatcherIndicesIndex(47),
+ /* return_matcher_indices */ MatcherIndicesIndex(51),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1159,7 +1182,7 @@
/* num_templates */ 0,
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(18),
- /* return_matcher_indices */ MatcherIndicesIndex(49),
+ /* return_matcher_indices */ MatcherIndicesIndex(53),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -1340,7 +1363,7 @@
},
{
/* [18] */
- /* fn GetDimensions[A : access](byte_address_buffer<A>, u32) */
+ /* fn GetDimensions[A : access](byte_address_buffer<A>, ptr<function, u32, writable>) */
/* num overloads */ 1,
/* overloads */ OverloadIndex(25),
},
diff --git a/src/tint/lang/hlsl/writer/BUILD.bazel b/src/tint/lang/hlsl/writer/BUILD.bazel
index bcb889a..b66d284 100644
--- a/src/tint/lang/hlsl/writer/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/BUILD.bazel
@@ -90,6 +90,7 @@
alwayslink = True,
srcs = [
"access_test.cc",
+ "arraylength_test.cc",
"binary_test.cc",
"bitcast_test.cc",
"builtin_test.cc",
diff --git a/src/tint/lang/hlsl/writer/BUILD.cmake b/src/tint/lang/hlsl/writer/BUILD.cmake
index cb0fdde..1113e5f 100644
--- a/src/tint/lang/hlsl/writer/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/BUILD.cmake
@@ -101,6 +101,7 @@
################################################################################
tint_add_target(tint_lang_hlsl_writer_test test
lang/hlsl/writer/access_test.cc
+ lang/hlsl/writer/arraylength_test.cc
lang/hlsl/writer/binary_test.cc
lang/hlsl/writer/bitcast_test.cc
lang/hlsl/writer/builtin_test.cc
diff --git a/src/tint/lang/hlsl/writer/BUILD.gn b/src/tint/lang/hlsl/writer/BUILD.gn
index b4ff72d..13709f4 100644
--- a/src/tint/lang/hlsl/writer/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/BUILD.gn
@@ -93,6 +93,7 @@
tint_unittests_source_set("unittests") {
sources = [
"access_test.cc",
+ "arraylength_test.cc",
"binary_test.cc",
"bitcast_test.cc",
"builtin_test.cc",
diff --git a/src/tint/lang/hlsl/writer/access_test.cc b/src/tint/lang/hlsl/writer/access_test.cc
index cc47037..1a2cbd0 100644
--- a/src/tint/lang/hlsl/writer/access_test.cc
+++ b/src/tint/lang/hlsl/writer/access_test.cc
@@ -731,11 +731,12 @@
int v_2 = k;
uint v_3 = 0u;
sb.GetDimensions(v_3);
- uint v_4 = min(uint(v), (((v_3 - 16u) / 128u) - 1u));
- uint v_5 = min(v_1, 2u);
- uint v_6 = (uint(v_4) * 128u);
- uint v_7 = (uint(v_5) * 32u);
- float x = asfloat(sb.Load((((48u + v_6) + v_7) + (uint(min(uint(v_2), 2u)) * 4u))));
+ uint v_4 = (((v_3 - 16u) / 128u) - 1u);
+ uint v_5 = min(uint(v), v_4);
+ uint v_6 = min(v_1, 2u);
+ uint v_7 = (uint(v_5) * 128u);
+ uint v_8 = (uint(v_6) * 32u);
+ float x = asfloat(sb.Load((((48u + v_7) + v_8) + (uint(min(uint(v_2), 2u)) * 4u))));
}
)");
diff --git a/src/tint/lang/hlsl/writer/arraylength_test.cc b/src/tint/lang/hlsl/writer/arraylength_test.cc
new file mode 100644
index 0000000..4707eb5
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/arraylength_test.cc
@@ -0,0 +1,232 @@
+// Copyright 2024 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/core/fluent_types.h"
+#include "src/tint/lang/core/ir/function.h"
+#include "src/tint/lang/core/number.h"
+#include "src/tint/lang/hlsl/writer/helper_test.h"
+
+#include "gtest/gtest.h"
+
+using namespace tint::core::fluent_types; // NOLINT
+using namespace tint::core::number_suffixes; // NOLINT
+
+namespace tint::hlsl::writer {
+namespace {
+
+TEST_F(HlslWriterTest, ArrayLengthDirect) {
+ auto* sb = b.Var("sb", ty.ptr<storage, array<i32>>());
+ sb->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+ EXPECT_EQ(output_.hlsl, R"(
+RWByteAddressBuffer sb : register(u0);
+void foo() {
+ uint v = 0u;
+ sb.GetDimensions(v);
+ uint len = (v / 4u);
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, ArrayLengthInStruct) {
+ auto* SB =
+ ty.Struct(mod.symbols.New("SB"), {
+ {mod.symbols.New("x"), ty.i32()},
+ {mod.symbols.New("arr"), ty.runtime_array(ty.i32())},
+ });
+
+ auto* sb = b.Var("sb", ty.ptr(storage, SB));
+ sb->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength,
+ b.Access(ty.ptr<storage, array<i32>>(), sb, 1_u)));
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+ EXPECT_EQ(output_.hlsl, R"(
+RWByteAddressBuffer sb : register(u0);
+void foo() {
+ uint v = 0u;
+ sb.GetDimensions(v);
+ uint len = ((v - 4u) / 4u);
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, ArrayLengthOfStruct) {
+ auto* SB = ty.Struct(mod.symbols.New("SB"), {
+ {mod.symbols.New("f"), ty.f32()},
+ });
+
+ auto* sb = b.Var("sb", ty.ptr(storage, ty.runtime_array(SB), core::Access::kRead));
+ sb->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+ EXPECT_EQ(output_.hlsl, R"(
+ByteAddressBuffer sb : register(t0);
+void foo() {
+ uint v = 0u;
+ sb.GetDimensions(v);
+ uint len = (v / 4u);
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, ArrayLengthArrayOfArrayOfStruct) {
+ auto* SB = ty.Struct(mod.symbols.New("SB"), {
+ {mod.symbols.New("f"), ty.f32()},
+ });
+ auto* sb = b.Var("sb", ty.ptr(storage, ty.runtime_array(ty.array(SB, 4))));
+ sb->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+ EXPECT_EQ(output_.hlsl, R"(
+RWByteAddressBuffer sb : register(u0);
+void foo() {
+ uint v = 0u;
+ sb.GetDimensions(v);
+ uint len = (v / 16u);
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, ArrayLengthMultiple) {
+ auto* sb = b.Var("sb", ty.ptr<storage, array<i32>>());
+ sb->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Let("b", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Let("c", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+ EXPECT_EQ(output_.hlsl, R"(
+RWByteAddressBuffer sb : register(u0);
+void foo() {
+ uint v = 0u;
+ sb.GetDimensions(v);
+ uint a = (v / 4u);
+ uint v_1 = 0u;
+ sb.GetDimensions(v_1);
+ uint b = (v_1 / 4u);
+ uint v_2 = 0u;
+ sb.GetDimensions(v_2);
+ uint c = (v_2 / 4u);
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, ArrayLengthMultipleStorageBuffers) {
+ auto* SB1 =
+ ty.Struct(mod.symbols.New("SB1"), {
+ {mod.symbols.New("x"), ty.i32()},
+ {mod.symbols.New("arr1"), ty.runtime_array(ty.i32())},
+ });
+ auto* SB2 = ty.Struct(mod.symbols.New("SB2"),
+ {
+ {mod.symbols.New("x"), ty.i32()},
+ {mod.symbols.New("arr2"), ty.runtime_array(ty.vec4<f32>())},
+ });
+ auto* sb1 = b.Var("sb1", ty.ptr(storage, SB1));
+ sb1->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb1);
+
+ auto* sb2 = b.Var("sb2", ty.ptr(storage, SB2));
+ sb2->SetBindingPoint(0, 1);
+ b.ir.root_block->Append(sb2);
+
+ auto* sb3 = b.Var("sb3", ty.ptr(storage, ty.runtime_array(ty.i32())));
+ sb3->SetBindingPoint(0, 2);
+ b.ir.root_block->Append(sb3);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("len1", b.Call(ty.u32(), core::BuiltinFn::kArrayLength,
+ b.Access(ty.ptr<storage, array<i32>>(), sb1, 1_u)));
+ b.Let("len2", b.Call(ty.u32(), core::BuiltinFn::kArrayLength,
+ b.Access(ty.ptr<storage, array<vec4<f32>>>(), sb2, 1_u)));
+ b.Let("len3", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb3));
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+ EXPECT_EQ(output_.hlsl, R"(
+RWByteAddressBuffer sb1 : register(u0);
+RWByteAddressBuffer sb2 : register(u1);
+RWByteAddressBuffer sb3 : register(u2);
+void foo() {
+ uint v = 0u;
+ sb1.GetDimensions(v);
+ uint len1 = ((v - 4u) / 4u);
+ uint v_1 = 0u;
+ sb2.GetDimensions(v_1);
+ uint len2 = ((v_1 - 16u) / 16u);
+ uint v_2 = 0u;
+ sb3.GetDimensions(v_2);
+ uint len3 = (v_2 / 4u);
+}
+
+)");
+}
+
+} // namespace
+} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/raise/decompose_memory_access.cc b/src/tint/lang/hlsl/writer/raise/decompose_memory_access.cc
index 58ea58b..e26ea3b 100644
--- a/src/tint/lang/hlsl/writer/raise/decompose_memory_access.cc
+++ b/src/tint/lang/hlsl/writer/raise/decompose_memory_access.cc
@@ -93,7 +93,12 @@
[&](core::ir::Store* st) { usage_worklist.Push(st); },
[&](core::ir::Load* ld) { usage_worklist.Push(ld); },
[&](core::ir::Access* a) { usage_worklist.Push(a); },
- [&](core::ir::Let* l) { usage_worklist.Push(l); }, //
+ [&](core::ir::Let* l) { usage_worklist.Push(l); },
+ [&](core::ir::CoreBuiltinCall* call) {
+ TINT_ASSERT(call->Func() == core::BuiltinFn::kArrayLength);
+ usage_worklist.Push(call);
+ },
+ //
TINT_ICE_ON_NO_MATCH);
}
@@ -125,6 +130,9 @@
let->Result(0)->ReplaceAllUsesWith(result);
let->Destroy();
},
+ [&](core::ir::CoreBuiltinCall* call) {
+ ArrayLength(var, call, var_ty->StoreType(), 0);
+ }, //
TINT_ICE_ON_NO_MATCH);
}
@@ -133,6 +141,35 @@
}
}
+ void ArrayLength(core::ir::Var* var,
+ core::ir::CoreBuiltinCall* call,
+ const core::type::Type* type,
+ uint32_t offset) {
+ auto* arr_ty = type->As<core::type::Array>();
+ // If the `arrayLength` was called directly on the storage buffer then
+ // it _must_ be a runtime array.
+ TINT_ASSERT(arr_ty && arr_ty->Count()->As<core::type::RuntimeArrayCount>());
+
+ b.InsertBefore(call, [&] {
+ // The `GetDimensions` call uses out parameters for all return values, there is no
+ // return value. This ends up being the result value we care about.
+ //
+ // This creates a var with an access which means that when we emit the HLSL we'll emit
+ // the correct `var` name.
+ core::ir::Instruction* inst = b.Var(ty.ptr(function, ty.u32()));
+ b.MemberCall<hlsl::ir::MemberBuiltinCall>(ty.void_(), BuiltinFn::kGetDimensions, var,
+ inst->Result(0));
+
+ inst = b.Load(inst);
+ if (offset > 0) {
+ inst = b.Subtract(ty.u32(), inst, u32(offset));
+ }
+ auto* div = b.Divide(ty.u32(), inst, u32(arr_ty->Stride()));
+ call->Result(0)->ReplaceAllUsesWith(div->Result(0));
+ });
+ call->Destroy();
+ }
+
struct OffsetData {
uint32_t byte_offset = 0;
Vector<core::ir::Value*, 4> expr{};
@@ -446,26 +483,7 @@
// If this access chain is being used in an `arrayLength` call then the access
// chain _must_ have resolved to the runtime array member of the structure. So,
// we _must_ have set `obj` to the array member which is a runtime array.
- auto* arr_ty = obj->As<core::type::Array>();
- TINT_ASSERT(arr_ty && arr_ty->Count()->Is<core::type::RuntimeArrayCount>());
-
- b.InsertBefore(a, [&] {
- auto* val = b.Let(ty.u32());
- val->SetValue(b.Zero<u32>());
-
- b.MemberCall<hlsl::ir::MemberBuiltinCall>(
- ty.void_(), BuiltinFn::kGetDimensions, var, val);
-
- // Because the `runtime_array` must be the last element of the outer most
- // structure and we're calling `arrayLength` on the array then the access
- // chain must have only had a single item in it and that item must have been
- // a constant offset.
- auto* div =
- b.Divide(ty.u32(), b.Subtract(ty.u32(), val, u32(offset->byte_offset)),
- u32(arr_ty->Stride()));
- call->Result(0)->ReplaceAllUsesWith(div->Result(0));
- });
- call->Destroy();
+ ArrayLength(var, call, obj, offset->byte_offset);
}, //
TINT_ICE_ON_NO_MATCH);
}
diff --git a/src/tint/lang/hlsl/writer/raise/decompose_memory_access_test.cc b/src/tint/lang/hlsl/writer/raise/decompose_memory_access_test.cc
index c6b1662..22fe773 100644
--- a/src/tint/lang/hlsl/writer/raise/decompose_memory_access_test.cc
+++ b/src/tint/lang/hlsl/writer/raise/decompose_memory_access_test.cc
@@ -3581,5 +3581,403 @@
EXPECT_EQ(expect, str());
}
+TEST_F(HlslWriterDecomposeMemoryAccessTest, ArrayLengthDirect) {
+ auto* sb = b.Var("sb", ty.ptr<storage, array<i32>>());
+ sb->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Return(func);
+ });
+
+ auto* src = R"(
+$B1: { # root
+ %sb:ptr<storage, array<i32>, read_write> = var @binding_point(0, 0)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %3:u32 = arrayLength %sb
+ %len:u32 = let %3
+ ret
+ }
+}
+)";
+ ASSERT_EQ(src, str());
+
+ auto* expect = R"(
+$B1: { # root
+ %sb:hlsl.byte_address_buffer<read_write> = var @binding_point(0, 0)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %3:ptr<function, u32, read_write> = var
+ %4:void = %sb.GetDimensions %3
+ %5:u32 = load %3
+ %6:u32 = div %5, 4u
+ %len:u32 = let %6
+ ret
+ }
+}
+)";
+ Run(DecomposeMemoryAccess);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriterDecomposeMemoryAccessTest, ArrayLengthInStruct) {
+ auto* SB =
+ ty.Struct(mod.symbols.New("SB"), {
+ {mod.symbols.New("x"), ty.i32()},
+ {mod.symbols.New("arr"), ty.runtime_array(ty.i32())},
+ });
+
+ auto* sb = b.Var("sb", ty.ptr(storage, SB));
+ sb->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength,
+ b.Access(ty.ptr<storage, array<i32>>(), sb, 1_u)));
+ b.Return(func);
+ });
+
+ auto* src = R"(
+SB = struct @align(4) {
+ x:i32 @offset(0)
+ arr:array<i32> @offset(4)
+}
+
+$B1: { # root
+ %sb:ptr<storage, SB, read_write> = var @binding_point(0, 0)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %3:ptr<storage, array<i32>, read_write> = access %sb, 1u
+ %4:u32 = arrayLength %3
+ %len:u32 = let %4
+ ret
+ }
+}
+)";
+ ASSERT_EQ(src, str());
+
+ auto* expect = R"(
+SB = struct @align(4) {
+ x:i32 @offset(0)
+ arr:array<i32> @offset(4)
+}
+
+$B1: { # root
+ %sb:hlsl.byte_address_buffer<read_write> = var @binding_point(0, 0)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %3:ptr<function, u32, read_write> = var
+ %4:void = %sb.GetDimensions %3
+ %5:u32 = load %3
+ %6:u32 = sub %5, 4u
+ %7:u32 = div %6, 4u
+ %len:u32 = let %7
+ ret
+ }
+}
+)";
+ Run(DecomposeMemoryAccess);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriterDecomposeMemoryAccessTest, ArrayLengthOfStruct) {
+ auto* SB = ty.Struct(mod.symbols.New("SB"), {
+ {mod.symbols.New("f"), ty.f32()},
+ });
+
+ auto* sb = b.Var("sb", ty.ptr(storage, ty.runtime_array(SB), core::Access::kRead));
+ sb->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Return(func);
+ });
+
+ auto* src = R"(
+SB = struct @align(4) {
+ f:f32 @offset(0)
+}
+
+$B1: { # root
+ %sb:ptr<storage, array<SB>, read> = var @binding_point(0, 0)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %3:u32 = arrayLength %sb
+ %len:u32 = let %3
+ ret
+ }
+}
+)";
+ ASSERT_EQ(src, str());
+
+ auto* expect = R"(
+SB = struct @align(4) {
+ f:f32 @offset(0)
+}
+
+$B1: { # root
+ %sb:hlsl.byte_address_buffer<read> = var @binding_point(0, 0)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %3:ptr<function, u32, read_write> = var
+ %4:void = %sb.GetDimensions %3
+ %5:u32 = load %3
+ %6:u32 = div %5, 4u
+ %len:u32 = let %6
+ ret
+ }
+}
+)";
+ Run(DecomposeMemoryAccess);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriterDecomposeMemoryAccessTest, ArrayLengthArrayOfArrayOfStruct) {
+ auto* SB = ty.Struct(mod.symbols.New("SB"), {
+ {mod.symbols.New("f"), ty.f32()},
+ });
+ auto* sb = b.Var("sb", ty.ptr(storage, ty.runtime_array(ty.array(SB, 4))));
+ sb->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Return(func);
+ });
+
+ auto* src = R"(
+SB = struct @align(4) {
+ f:f32 @offset(0)
+}
+
+$B1: { # root
+ %sb:ptr<storage, array<array<SB, 4>>, read_write> = var @binding_point(0, 0)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %3:u32 = arrayLength %sb
+ %len:u32 = let %3
+ ret
+ }
+}
+)";
+ ASSERT_EQ(src, str());
+
+ auto* expect = R"(
+SB = struct @align(4) {
+ f:f32 @offset(0)
+}
+
+$B1: { # root
+ %sb:hlsl.byte_address_buffer<read_write> = var @binding_point(0, 0)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %3:ptr<function, u32, read_write> = var
+ %4:void = %sb.GetDimensions %3
+ %5:u32 = load %3
+ %6:u32 = div %5, 16u
+ %len:u32 = let %6
+ ret
+ }
+}
+)";
+ Run(DecomposeMemoryAccess);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriterDecomposeMemoryAccessTest, ArrayLengthMultiple) {
+ auto* sb = b.Var("sb", ty.ptr<storage, array<i32>>());
+ sb->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Let("b", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Let("c", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
+ b.Return(func);
+ });
+
+ auto* src = R"(
+$B1: { # root
+ %sb:ptr<storage, array<i32>, read_write> = var @binding_point(0, 0)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %3:u32 = arrayLength %sb
+ %a:u32 = let %3
+ %5:u32 = arrayLength %sb
+ %b:u32 = let %5
+ %7:u32 = arrayLength %sb
+ %c:u32 = let %7
+ ret
+ }
+}
+)";
+ ASSERT_EQ(src, str());
+
+ auto* expect = R"(
+$B1: { # root
+ %sb:hlsl.byte_address_buffer<read_write> = var @binding_point(0, 0)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %3:ptr<function, u32, read_write> = var
+ %4:void = %sb.GetDimensions %3
+ %5:u32 = load %3
+ %6:u32 = div %5, 4u
+ %a:u32 = let %6
+ %8:ptr<function, u32, read_write> = var
+ %9:void = %sb.GetDimensions %8
+ %10:u32 = load %8
+ %11:u32 = div %10, 4u
+ %b:u32 = let %11
+ %13:ptr<function, u32, read_write> = var
+ %14:void = %sb.GetDimensions %13
+ %15:u32 = load %13
+ %16:u32 = div %15, 4u
+ %c:u32 = let %16
+ ret
+ }
+}
+)";
+ Run(DecomposeMemoryAccess);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriterDecomposeMemoryAccessTest, ArrayLengthMultipleStorageBuffers) {
+ auto* SB1 =
+ ty.Struct(mod.symbols.New("SB1"), {
+ {mod.symbols.New("x"), ty.i32()},
+ {mod.symbols.New("arr1"), ty.runtime_array(ty.i32())},
+ });
+ auto* SB2 = ty.Struct(mod.symbols.New("SB2"),
+ {
+ {mod.symbols.New("x"), ty.i32()},
+ {mod.symbols.New("arr2"), ty.runtime_array(ty.vec4<f32>())},
+ });
+ auto* sb1 = b.Var("sb1", ty.ptr(storage, SB1));
+ sb1->SetBindingPoint(0, 0);
+ b.ir.root_block->Append(sb1);
+
+ auto* sb2 = b.Var("sb2", ty.ptr(storage, SB2));
+ sb2->SetBindingPoint(0, 1);
+ b.ir.root_block->Append(sb2);
+
+ auto* sb3 = b.Var("sb3", ty.ptr(storage, ty.runtime_array(ty.i32())));
+ sb3->SetBindingPoint(0, 2);
+ b.ir.root_block->Append(sb3);
+
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ b.Let("len1", b.Call(ty.u32(), core::BuiltinFn::kArrayLength,
+ b.Access(ty.ptr<storage, array<i32>>(), sb1, 1_u)));
+ b.Let("len2", b.Call(ty.u32(), core::BuiltinFn::kArrayLength,
+ b.Access(ty.ptr<storage, array<vec4<f32>>>(), sb2, 1_u)));
+ b.Let("len3", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb3));
+ b.Return(func);
+ });
+
+ auto* src = R"(
+SB1 = struct @align(4) {
+ x:i32 @offset(0)
+ arr1:array<i32> @offset(4)
+}
+
+SB2 = struct @align(16) {
+ x_1:i32 @offset(0)
+ arr2:array<vec4<f32>> @offset(16)
+}
+
+$B1: { # root
+ %sb1:ptr<storage, SB1, read_write> = var @binding_point(0, 0)
+ %sb2:ptr<storage, SB2, read_write> = var @binding_point(0, 1)
+ %sb3:ptr<storage, array<i32>, read_write> = var @binding_point(0, 2)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %5:ptr<storage, array<i32>, read_write> = access %sb1, 1u
+ %6:u32 = arrayLength %5
+ %len1:u32 = let %6
+ %8:ptr<storage, array<vec4<f32>>, read_write> = access %sb2, 1u
+ %9:u32 = arrayLength %8
+ %len2:u32 = let %9
+ %11:u32 = arrayLength %sb3
+ %len3:u32 = let %11
+ ret
+ }
+}
+)";
+ ASSERT_EQ(src, str());
+
+ auto* expect = R"(
+SB1 = struct @align(4) {
+ x:i32 @offset(0)
+ arr1:array<i32> @offset(4)
+}
+
+SB2 = struct @align(16) {
+ x_1:i32 @offset(0)
+ arr2:array<vec4<f32>> @offset(16)
+}
+
+$B1: { # root
+ %sb1:hlsl.byte_address_buffer<read_write> = var @binding_point(0, 0)
+ %sb2:hlsl.byte_address_buffer<read_write> = var @binding_point(0, 1)
+ %sb3:hlsl.byte_address_buffer<read_write> = var @binding_point(0, 2)
+}
+
+%foo = @fragment func():void {
+ $B2: {
+ %5:ptr<function, u32, read_write> = var
+ %6:void = %sb1.GetDimensions %5
+ %7:u32 = load %5
+ %8:u32 = sub %7, 4u
+ %9:u32 = div %8, 4u
+ %len1:u32 = let %9
+ %11:ptr<function, u32, read_write> = var
+ %12:void = %sb2.GetDimensions %11
+ %13:u32 = load %11
+ %14:u32 = sub %13, 16u
+ %15:u32 = div %14, 16u
+ %len2:u32 = let %15
+ %17:ptr<function, u32, read_write> = var
+ %18:void = %sb3.GetDimensions %17
+ %19:u32 = load %17
+ %20:u32 = div %19, 4u
+ %len3:u32 = let %20
+ ret
+ }
+}
+)";
+ Run(DecomposeMemoryAccess);
+ EXPECT_EQ(expect, str());
+}
+
} // namespace
} // namespace tint::hlsl::writer::raise