Import Tint changes from Dawn
Changes:
- d623182c336bad0be262a544d8b5865a1565c5da tint/PromoteInitializers: Do not hoist abstracts by James Price <jrprice@google.com>
- dee884c9257cc3b2c533c6b0ec338296d3839632 Convert most remaining usages to utils::StringStream. by dan sinclair <dsinclair@chromium.org>
- 7c21fe5d92c87e7defd37a367de0ab933dad1973 tint/uniformity: Fix struct member partial pointers by James Price <jrprice@google.com>
- b7c2aed189b5006628a6998d3d9aca783c89c864 tint: Skip short-circuited array init const eval by James Price <jrprice@google.com>
- 0723a3c7f8f193db9e557edae9833f86c226539e Convert WGSL reader to utils::StringStream. by dan sinclair <dsinclair@chromium.org>
- 0c184c285621f91969c199e6da54beaeac6560f0 Convert SPIR-V reader to utils::StringStream. by dan sinclair <dsinclair@chromium.org>
- b23cda4bc24f931f8be3d8999dbbf67838c407eb Convert the resolver over to utils::StringStream. by dan sinclair <dsinclair@chromium.org>
- b2ba57b15d6c935eaf8c2c4e6a6d6c6d5ab02566 Convert TextGenerator over to utils::StringStream. by dan sinclair <dsinclair@chromium.org>
- 88fea2a9c33436d42f284948cc8fab2d31295116 Convert the WGSL generator to utils::StringStream. by dan sinclair <dsinclair@chromium.org>
- ec24bb2f0ce2eed088d0d1fc9dcd2a087d51f5f9 Convert SPIR-V Writer over to utils::StringStream. by dan sinclair <dsinclair@chromium.org>
- 52fa68b1a748b90b3f646a46c98ce72607608c60 Convert MSL generator over to utils::StringStream. by dan sinclair <dsinclair@chromium.org>
- 2b9d5b338a28cf6d919bcb51c84561f77d2b2f16 Convert HLSL generator over to utils::StringStream. by dan sinclair <dsinclair@chromium.org>
- dba03d30fb141e94d7d823924fd9a7c3a642d095 Convert GLSL Generator over to utils::StringStream. by dan sinclair <dsinclair@chromium.org>
- a4637ad8a314c50138c03500dfe76c3ee5ffde3e Convert IR over to `utils::StringStream`. by dan sinclair <dsinclair@chromium.org>
- 7ca41fffb782f0f75203dbaf91a6594203894a0d Add a utils/string_stream class. by dan sinclair <dsinclair@chromium.org>
- 4d3af66bbdafda4284a0eefb0d384ccdb77a7080 tint/msl: Preserve trailing vec3 padding by James Price <jrprice@google.com>
- 43ffb09247e1e48f021abb63131bedd449e55209 tint: validate max number of case selectors in a switch s... by Antonio Maiorano <amaiorano@google.com>
- 1bb5be9789272206ea23ebe6454fa8afca579722 tint: improve error message about function paramter limit by Antonio Maiorano <amaiorano@google.com>
- 6b304e9ffd649602d8074d0362928479416c8d3e tint: validate max nesting depth of composite types by Antonio Maiorano <amaiorano@google.com>
- 0b3400c56e1ac2782f8bca1854cab1a1c282b141 tint: Add chromium_internal_relaxed_uniform_layout by James Price <jrprice@google.com>
- 806135658dbc91b5dd581cc11effca62455bd2ca tint: Pass constant::Values to ArrayOrStructCtor by James Price <jrprice@google.com>
- c5ec169b890ac8a16bffbb4f063cbede6f34294e classify template args: add cases used to debug Treesitte... by David Neto <dneto@google.com>
- 6176c85be83b08a7bf4f2e6ec6422d65a5ee5290 tint: Preserve padding in matrices with three rows by James Price <jrprice@google.com>
- fe19fee3ea3ddf7d0ef1995f7e89739870c20a94 tint/const-eval: Fix runtime semantics for (x % 0) by James Price <jrprice@google.com>
- 04529be9b74e20e515eb30ca14303063ae49df3f Dawn/Tint: Polyfill reflect vec2<f32> for D3D12 FXC on In... by Zhaoming Jiang <zhaoming.jiang@intel.com>
GitOrigin-RevId: d623182c336bad0be262a544d8b5865a1565c5da
Change-Id: Ie09db15507c3ff36b0e23aadb5ef1a70753dbe61
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/121680
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 662f90d..89eb6ee 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -221,6 +221,8 @@
"utils/slice.h",
"utils/string.cc",
"utils/string.h",
+ "utils/string_stream.cc",
+ "utils/string_stream.h",
"utils/unique_allocator.h",
"utils/unique_vector.h",
"utils/vector.h",
@@ -291,7 +293,10 @@
"demangler.cc",
"demangler.h",
]
- deps = [ ":libtint_program_src" ]
+ deps = [
+ ":libtint_base_src",
+ ":libtint_program_src",
+ ]
}
libtint_source_set("libtint_initializer_src") {
@@ -1559,6 +1564,7 @@
"utils/reverse_test.cc",
"utils/scoped_assignment_test.cc",
"utils/slice_test.cc",
+ "utils/string_stream_test.cc",
"utils/string_test.cc",
"utils/transform_test.cc",
"utils/unique_allocator_test.cc",
@@ -2051,6 +2057,12 @@
configs += [ "//build/config/compiler:no_chromium_code" ]
}
+ if (is_win && is_debug) {
+ # TODO(crbug.com/tint/1749): both msvc and clang builds stack overflow on debug builds.
+ # Increase the initial stack size to 4 MB (default is 1MB).
+ ldflags = [ "/STACK:4194304" ]
+ }
+
testonly = true
}
}
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 658d14f..1d31896 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -530,6 +530,8 @@
utils/slice.h
utils/string.cc
utils/string.h
+ utils/string_stream.cc
+ utils/string_stream.h
utils/unique_allocator.h
utils/unique_vector.h
utils/vector.h
@@ -985,6 +987,7 @@
utils/reverse_test.cc
utils/scoped_assignment_test.cc
utils/slice_test.cc
+ utils/string_stream_test.cc
utils/string_test.cc
utils/transform_test.cc
utils/unique_allocator_test.cc
diff --git a/src/tint/ast/float_literal_expression_test.cc b/src/tint/ast/float_literal_expression_test.cc
index 5ec5f0f..6374583 100644
--- a/src/tint/ast/float_literal_expression_test.cc
+++ b/src/tint/ast/float_literal_expression_test.cc
@@ -14,6 +14,8 @@
#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string_stream.h"
+
namespace tint::ast {
namespace {
@@ -42,7 +44,7 @@
TEST_F(FloatLiteralExpressionTest, SuffixStringStream) {
auto to_str = [](FloatLiteralExpression::Suffix suffix) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << suffix;
return ss.str();
};
diff --git a/src/tint/ast/int_literal_expression_test.cc b/src/tint/ast/int_literal_expression_test.cc
index 969e1b9..9481c30 100644
--- a/src/tint/ast/int_literal_expression_test.cc
+++ b/src/tint/ast/int_literal_expression_test.cc
@@ -14,6 +14,8 @@
#include "src/tint/ast/test_helper.h"
+#include "src/tint/utils/string_stream.h"
+
namespace tint::ast {
namespace {
@@ -42,7 +44,7 @@
TEST_F(IntLiteralExpressionTest, SuffixStringStream) {
auto to_str = [](IntLiteralExpression::Suffix suffix) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << suffix;
return ss.str();
};
diff --git a/src/tint/bench/benchmark.cc b/src/tint/bench/benchmark.cc
index c00e51f..6b072db 100644
--- a/src/tint/bench/benchmark.cc
+++ b/src/tint/bench/benchmark.cc
@@ -19,6 +19,8 @@
#include <utility>
#include <vector>
+#include "src/tint/utils/string_stream.h"
+
namespace tint::bench {
namespace {
@@ -44,7 +46,7 @@
fseek(file, 0, SEEK_END);
const auto file_size = static_cast<size_t>(ftell(file));
if (0 != (file_size % sizeof(T))) {
- std::stringstream err;
+ utils::StringStream err;
err << "File " << input_file
<< " does not contain an integral number of objects: " << file_size
<< " bytes in the file, require " << sizeof(T) << " bytes per object";
diff --git a/src/tint/builtin/builtin.cc b/src/tint/builtin/builtin.cc
index 60449b5..dc608d0 100644
--- a/src/tint/builtin/builtin.cc
+++ b/src/tint/builtin/builtin.cc
@@ -28,6 +28,9 @@
/// @param str the string to parse
/// @returns the parsed enum, or Builtin::kUndefined if the string could not be parsed.
Builtin ParseBuiltin(std::string_view str) {
+ if (str == "__packed_vec3") {
+ return Builtin::kPackedVec3;
+ }
if (str == "array") {
return Builtin::kArray;
}
@@ -242,6 +245,8 @@
switch (value) {
case Builtin::kUndefined:
return out << "undefined";
+ case Builtin::kPackedVec3:
+ return out << "__packed_vec3";
case Builtin::kArray:
return out << "array";
case Builtin::kAtomic:
diff --git a/src/tint/builtin/builtin.h b/src/tint/builtin/builtin.h
index f514109..25bac8b 100644
--- a/src/tint/builtin/builtin.h
+++ b/src/tint/builtin/builtin.h
@@ -30,6 +30,7 @@
/// An enumerator of builtin builtin.
enum class Builtin {
kUndefined,
+ kPackedVec3,
kArray,
kAtomic,
kBool,
@@ -112,6 +113,7 @@
Builtin ParseBuiltin(std::string_view str);
constexpr const char* kBuiltinStrings[] = {
+ "__packed_vec3",
"array",
"atomic",
"bool",
diff --git a/src/tint/builtin/builtin_bench.cc b/src/tint/builtin/builtin_bench.cc
index 3c3134d..1f309f5 100644
--- a/src/tint/builtin/builtin_bench.cc
+++ b/src/tint/builtin/builtin_bench.cc
@@ -31,489 +31,496 @@
void BuiltinParser(::benchmark::State& state) {
const char* kStrings[] = {
- "arccy",
- "3a",
- "aVray",
+ "__acked_veccc",
+ "_pac3ed_v3",
+ "__packeV_vec3",
+ "__packed_vec3",
+ "__pa1ked_vec3",
+ "_qqJcked_vec3",
+ "__pack77d_vllc3",
+ "arqHapp",
+ "vy",
+ "Grby",
"array",
- "arra1",
- "qqrJy",
- "arrll7y",
- "atppmHHc",
- "cto",
- "abGmi",
+ "arviay",
+ "ar8WWy",
+ "Mxxra",
+ "atXggi",
+ "Xoic",
+ "ato3ic",
"atomic",
- "atvmiii",
- "atWWm8c",
- "xxtomc",
- "bXgg",
- "Xu",
- "b3ol",
+ "aEomic",
+ "toTTiPP",
+ "ddtoxxi",
+ "44ool",
+ "VVSSol",
+ "RoRl",
"bool",
- "booE",
- "TTPol",
- "xxool",
- "4416",
- "fSVV6",
- "RR2",
+ "oFl",
+ "boo",
+ "ORVHl",
+ "y1",
+ "l77rrn6",
+ "4016",
"f16",
- "96",
- "f1",
- "VOR6",
- "y3",
- "l77rrn2",
- "4032",
- "f32",
"5",
- "u377",
- "kk2",
- "ii",
- "i3XX",
+ "u16",
+ "f",
+ "f3kk",
+ "fi",
+ "f3XX",
+ "f32",
"55399II",
- "i32",
- "irSSHHa",
+ "frSSHHa",
"U",
"jV3",
- "ax2",
- "t2SGG",
- "q2x2",
- "mat2x2",
- "at2",
- "majjx",
+ "",
+ "GG",
+ "i32",
+ "2",
+ "",
+ "jj",
"a2xrf",
- "mat2xjf",
- "mNNw2x28",
- "matx2f",
- "mat2x2f",
- "mrrt2x2f",
- "Gat2x2f",
+ "mat2j2",
+ "m82wNN2",
+ "mat2x2",
+ "mt2x2",
+ "rrat2x2",
+ "mGt2x2",
"mat2x2FF",
- "at2h",
- "marrx2h",
- "t2x2h",
- "mat2x2h",
- "Da2xJJh",
+ "at2f",
+ "marrx2f",
+ "mat2x2f",
+ "t2x2f",
+ "Da2xJJf",
"ma82",
"m11k2",
- "matx3",
- "maJx3",
- "cat2x3",
- "mat2x3",
- "mat2O3",
- "ttKavv2x__",
+ "matx2h",
+ "maJx2h",
+ "mat2x2h",
+ "mat2c2h",
+ "mat2x2O",
+ "KK_atvvtt2h",
"5txxx8",
- "__qatF3",
- "matqx3f",
- "33atOx3f",
- "mat2x3f",
- "mtt62x9oQQ",
- "ma2x66f",
+ "a__xqq",
+ "maqq2x",
+ "mat2x3",
+ "ma32x66",
+ "mttQQo2x3",
+ "mat66x",
"mtOxzz66",
- "mat2yy3h",
+ "mat2yy3f",
"ZaHH3Z",
- "4WWt2q3h",
- "mat2x3h",
- "mOO2x3h",
- "oatY3h",
+ "mat2x3f",
+ "4WWt2q3f",
+ "mOO2x3f",
+ "oatY3f",
"matx",
- "ma2x4",
- "matw4",
- "ma2Gf",
- "mat2x4",
- "qatKKx4",
- "mmmt2x4",
+ "ma2xFh",
+ "at2x3w",
+ "mat2x3h",
+ "fGtxKh",
+ "matqKx3h",
+ "matmmxFh",
"at2x4",
- "mt2x4q",
- "mat2xbb",
- "mi2x4f",
- "mat2x4f",
- "maOO2xq",
- "matTvvx4f",
+ "matxq",
+ "mb2bb4",
+ "mat2x4",
+ "it2x4",
+ "mOO2xq",
+ "mat2Tvv4",
"maFF2x4f",
- "Pa00xQh",
- "mPt2x4h",
+ "Pa00xQf",
+ "mPt2x4f",
+ "mat2x4f",
"ma772xss",
- "mat2x4h",
- "RRCbb2x4h",
- "mXXt2x4h",
+ "RRCbb2x4f",
+ "mXXt2x4f",
"qaCC2xOOh",
- "mtsuL",
- "mat3xX",
- "mat3x",
- "mat3x2",
- "qqt2",
- "mat3x22",
+ "ma2s4L",
+ "mXt2x4h",
+ "mat2x4h",
+ "mat24h",
+ "qa2O4",
+ "mat2x22h",
"mzzyt3x",
- "matVViP",
- "mannC2f",
- "atx2AHHq",
+ "atiVP2",
+ "mt3Cnn",
+ "mat3x2",
+ "AtqqHH2",
+ "at3x2",
+ "mafKK",
+ "ltgg2f",
+ "mat3xf",
+ "NTTtcx4f",
"mat3x2f",
- "may3x2",
- "aOOOZZf",
- "Vt12f",
- "mff__3x2h",
- "qaTMMl4h",
+ "ma7ppl2f",
"mNNt3xg",
- "mat3x2h",
- "uub3XX2h",
+ "uub3XX2f",
"matx2h",
"Qt882h",
- "maqx3",
- "mat3113",
- "Ft3xi22",
- "mat3x3",
- "m7t3x3",
+ "mt9q2h",
+ "mat3x2h",
+ "m11t3x2h",
+ "22at3iih",
+ "at3x277",
"NNa323",
"VVat3x3",
- "FaWW3w11f",
- "mawwx3f",
- "Dat3x3f",
- "mat3x3f",
- "mt3x3K",
+ "ma11F3w3",
+ "mat3x3",
+ "matww3",
+ "mat3D3",
+ "maKx3",
"mat31PPhf",
"mat33f",
- "mYYt3x3h",
+ "mYYt3x3f",
+ "mat3x3f",
"mttHH3kk",
- "mat3rr3h",
- "mat3x3h",
- "WWas3x3h",
+ "mat3rr3f",
+ "WWas3x3f",
"Yt3x3h",
"mt3qfh",
- "vvafu224",
- "mt34",
- "maY34",
- "mat3x4",
- "YYa7y3E4",
+ "mav223xuh",
+ "mat3x3h",
+ "t3x3h",
+ "YYat3h",
+ "may3x3EYY",
"Moatd4",
"mt3xMM",
- "mat3x55f",
- "maN34",
- "ma3Ox33",
+ "m55t3x4",
+ "mat3x4",
+ "maN4",
+ "ma33x4",
+ "mt3x3",
+ "mm66Issf",
+ "mat3x1f",
+ "Xt3x4",
"mat3x4f",
- "m3t3x4f",
- "mam3xI",
- "mnnt3r4K",
- "m3XX",
- "LatIx4h",
- "at3fh",
- "mat3x4h",
+ "LatIx4f",
+ "at3ff",
"mYtURD4",
"mah3x4h",
"uuIqt3x",
- "mat4xH",
- "at4Qvv",
- "66ate",
- "mat4x2",
- "mat7x",
+ "maH3x4h",
+ "mat3x4h",
+ "at3QQvv",
+ "at66eh",
+ "ma7O4h",
"m0t55DD2",
"IIaH4x2",
- "at4x2",
- "rat4x299",
- "mGtt41W2f",
- "mat4x2f",
- "yatx2",
+ "mat4x",
+ "mat4x2",
+ "mt4r2",
+ "mat4xl",
+ "mGttx2",
+ "mat4y2",
"mt4x2f",
"IIaBB4x2f",
+ "mat4x2f",
"TTat4x833",
- "ddUUnntYYx2h",
+ "ddUUnntYYx2f",
"m5CCxxdZ",
- "mat4x2h",
"matkkq2h",
"005itpxh",
"maIInnx2h",
- "ccaKx",
- "mtKK",
- "ma664x3",
- "mat4x3",
+ "mat4x2h",
+ "Ka4Wcc",
+ "m42KK",
+ "mat66x2h",
"mKKtPx",
"maxx43",
"matqx3",
- "MMayySrxf",
- "mat3f",
- "tx3f",
- "mat4x3f",
+ "mat4x3",
+ "rMtyyxSS",
+ "uat4",
+ "tx3",
"ma5F4x3f",
"rra444z3f",
"matWW",
- "CatZJXx3h",
- "maPPx3h",
- "mat4c3h",
- "mat4x3h",
+ "mat4x3f",
+ "CatZJXx3f",
+ "maPPx3f",
+ "mat4c3f",
"matPPll6h",
"mat993yy",
"mat4JKKh",
- "ma_x4",
- "a4K4",
- "kVt4xz",
- "mat4x4",
+ "mat4x3h",
+ "mat4_h",
+ "ayK3h",
+ "mzt4V3k",
"qaSKx4",
"mat44",
"ma4xVV",
- "AAatIxUf",
- "mbj4f",
- "YY444x",
- "mat4x4f",
+ "mat4x4",
+ "mAAt4xI",
+ "jb44",
+ "t4YYx",
"mao4x4",
"mtx114f",
"mtmxccf",
- "aJJ4x4h",
+ "mat4x4f",
+ "aJJ4x4f",
"fCCDD4x4U",
- "mgt4x4h",
- "mat4x4h",
+ "mgt4x4f",
"CCx4h",
"mat4x66",
"maN4M4h",
- "pt",
- "KW",
- "pzzee",
- "ptr",
+ "mat4x4h",
+ "mattth",
+ "maKWxh",
+ "mateezx4h",
"",
"w9",
"4tnn",
- "sllDler",
- "oamp4er",
- "wEaggler",
- "sampler",
+ "ptr",
+ "tll",
+ "4to",
+ "wEgg",
"gamler",
"spleS",
"aampl",
- "sampZcRTr_comparison",
- "sampler_88TmparisOn",
- "sampler_comparim00n",
- "sampler_comparison",
+ "sampler",
+ "TamplZRRr",
+ "sa8TplOr",
+ "m0ampler",
"sampler_Bmomparison",
"Mamper_ppomarison",
"samper_compOOrison",
- "teGtGre_1d",
- "tex11ureHH1d",
- "6exeeur_1FF",
- "texture_1d",
+ "sampler_comparison",
+ "sampler_compGrGGon",
+ "sHHm11ler_comparison",
+ "sa6ler_FFeemparison",
"texure_1",
"tKiilure_1d",
"exture_1d",
- "99etvIIre_2d",
+ "texture_1d",
+ "99etvIIre_1d",
"texture_d",
"texture_hd",
- "texture_2d",
"llxzzure_PPd",
"exue2d",
"tffqqtre_2d",
- "texJJre_2dd_arWay",
- "teXXzzre_2darray",
- "textu2_2d_array",
- "texture_2d_array",
+ "texture_2d",
+ "texturJdd_d",
+ "trXXtu_2zz",
+ "textu2e2d",
"tNyyture_2d_array",
"txture_2d_rOOa",
"textureErduaZPay",
- "22lxtredd3ee",
- "texVVe93d",
- "teture_I1d",
- "texture_3d",
+ "texture_2d_array",
+ "exl22re_2dd_areeay",
+ "mextureVV_ar9ay",
+ "teIItu1_2d_array",
"tebture_3d",
"ie7ure3d",
"teotiire_3d",
- "entre_cube",
- "texturScube",
- "tex22r_cube",
- "texture_cube",
+ "texture_3d",
+ "extre_35",
+ "textre_iS",
+ "t22xtur_3",
"teC711recuGe",
"texture8cffbe",
"textue_cue",
- "tJJxture_SSube_array",
- "texture_9ue_arry",
- "TbbJJxture_cube_array",
- "texture_cube_array",
+ "texture_cube",
+ "texture_SSJJbe",
+ "textrecu9e",
+ "TTeJJbture_cube",
"t66ture_cube_aray",
"textur66_cubu_arra",
"textureWubeyarray",
- "texture_deth_d",
- "texture_epth_2d",
- "texture_derth_2d",
- "texture_depth_2d",
+ "texture_cube_array",
+ "texture_cube_ara",
+ "texture_ube_array",
+ "rexture_cube_array",
"tex2ure_depth_2B",
"texture_dpBBh_2d",
"texture_dpth_RRd",
- "tLLxture_deptVV0darray",
- "textuOOe_dethKK2d_arra",
- "textuwe_ggepth_2d_rray",
- "texture_depth_2d_array",
+ "texture_depth_2d",
+ "tLL0Vure_deth_2d",
+ "tetKKredOOpth_2d",
+ "textgwre_dpth_2d",
"textue_depthLh2d_arpay",
"texture_depEh2diiKrray",
"texture_dept_2d_array",
- "textuUUe88dept_cbe",
- "texrrure_depvvh_cube",
- "texure_wepmmh_ube",
- "texture_depth_cube",
+ "texture_depth_2d_array",
+ "t88xtuUUe_deph_2d_rray",
+ "texrruvve_depth_2d_array",
+ "texture_depmm_2d_wray",
"tjture_d44pth_cube",
"texture_depth_cXbe",
"t8xture_depth_cube",
- "textre_depth_cubeEEarrvvy",
- "tzzture_d9pth_cuie_array",
- "teAture_depth_QQube_GGrrJJy",
- "texture_depth_cube_array",
+ "texture_depth_cube",
+ "textur_devvth_cubEE",
+ "tzxturi99epth_cube",
+ "teQQtuJJGe_nepth_cuAe",
"texture_depth_cusse_array",
"texture_Pepth_cKbe_array",
"texture_dppp_cube_attray",
- "texture_depth_multisample_2",
- "texture_depth_multisamplMMd_2d",
- "texJJure_de0th_multisampled_2d",
- "texture_depth_multisampled_2d",
+ "texture_depth_cube_array",
+ "exture_deth_cube_array",
+ "texture_depth_MMube_array",
+ "tJJxture_depth_cube_a0ray",
"textu8_dpth_mulisampled_2V",
"texture_dhhpth_mKltisggmpled_2d",
"texture_depth_multisampledf2d",
- "tex77ure_exQernal",
- "tYYxture_externa",
- "tektur_exterSal",
- "texture_external",
+ "texture_depth_multisampled_2d",
+ "te77ture_depth_multisamQled_2d",
+ "teture_depthYYmultisampled_2d",
+ "texture_deptk_multiampled_Sd",
"txturn_ext2rnal",
"txture_FFternal",
"texUPPIre_GGxuernal",
- "txtuEEe_mulaisFmpledv2d",
- "ddexBBure_mltDDeampled_2d",
- "teMture_EEulccisam55led_2",
- "texture_multisampled_2d",
+ "texture_external",
+ "taxtuvEE_externl",
+ "textureexBddernDDl",
+ "tEEMtur_e55tccrnal",
"texturemuKKtisample_d",
"texture_multisRmpled_2d",
"texturemulDisampl9d_2d",
- "texturestorage_1d",
- "textIre_storaa_1d",
- "texture_sto77age_1d",
- "texture_storage_1d",
+ "texture_multisampled_2d",
+ "teture_multisampled_2d",
+ "textuIa_multisampld_2d",
+ "texture_multisamp77ed_2d",
"texIure_storage_1d",
"texture_storagedd",
"texture_storae_1d",
+ "texture_storage_1d",
"texture_strate_d",
- "texture33stoXXcge_2d",
- "texturestorage_2E",
- "texture_storage_2d",
+ "texture33stoXXcge_1d",
+ "texturestorage_1E",
"textuXXestorage_2d",
"texture_stoBaxxe_2d",
"texte_storWge_2G",
- "texture_storage_2d_ar66ay",
- "t0xTTr_storave_2d_array",
- "kexure_orage_2d_rray",
- "texture_storage_2d_array",
+ "texture_storage_2d",
+ "texture_s66orage_2d",
+ "textvTr_so0age_2d",
+ "textureorgek2d",
"textppre_stoae_2d_array",
"textre_stora11e_d_array",
"textureystorBEgeJ2d_array",
- "textqreIImtxrage_3d",
- "texture_toFage_3d",
- "exture_Ytorage_3d",
- "texture_storage_3d",
+ "texture_storage_2d_array",
+ "texture_mtorage_2dxIqrray",
+ "teture_storageF2d_array",
+ "textur_Ytorage_2d_array",
"heDture_sHHorage_3d",
"texturstorage23H",
"teture_strage_3d",
- "u2",
- "u2",
- "dd32",
- "u32",
+ "texture_storage_3d",
+ "texture_storage_d",
+ "texturestorage_3d",
+ "ddexture_storage_3d",
"uPO",
"ba",
"u02",
- "veh2",
- "vgY2",
- "Oec2",
- "vec2",
+ "u32",
+ "h32",
+ "gYY",
+ "O32",
"eh",
"ppfe2",
"vev",
- "vc2zz",
- "vaac2",
- "Ouuicf",
- "vec2f",
+ "vec2",
+ "vzz2",
+ "vc2",
+ "OOii",
"vGc2f",
"22ecTTf",
"dlc2f",
- "vecbh",
+ "vec2f",
+ "vecbf",
"ec2BB",
"IIScXPP",
- "vec2h",
"jjec2h",
"cc_c2h",
"zz6xx2h",
+ "vec2h",
"c2",
"4xx2N",
- "p0AAei",
- "vec2i",
+ "p0AAeh",
"vey2",
"vbWW0i",
"meMMtti",
- "du",
+ "vec2i",
+ "di",
"vvc_",
- "VEEc2u",
- "vec2u",
+ "VEEc2i",
"vec24",
"VVeX2u",
"veVou",
- "vec",
- "KKc3",
- "G",
- "vec3",
+ "vec2u",
+ "ve2u",
+ "ecKKt",
+ "eG",
"ea3",
"OOc",
"G",
- "v5c3f",
- "99jcfff",
- "XXvYY3R",
- "vec3f",
+ "vec3",
+ "ve53",
+ "9fjec3",
+ "vvXcRY",
"ccf",
"v8XX5",
"ec3",
+ "vec3f",
"ppc3cc",
- "vecvh",
+ "vecvf",
"eEE3SS",
- "vec3h",
"vec",
"eh",
"ec3ww",
- "vecd99i",
+ "vec3h",
+ "vecd99h",
"ve99P",
"KKec3",
- "vec3i",
"ooMcDD",
"vei",
"vqi",
+ "vec3i",
"veL30",
"vncvv66",
"vrrn3",
- "vec3u",
"vxxce",
"NCCOc3u",
"vc3u",
- "veca",
- "veNNN",
- "vec",
- "vec4",
+ "vec3u",
+ "aec4u",
+ "NNc3NN",
+ "ve3u",
"vc",
"vAYS4",
"vec0",
- "vecaaf",
- "vmm4f",
- "ec4f",
- "vec4f",
+ "vec4",
+ "vecaa",
+ "mmcq",
+ "vc4",
"vE4U",
"veKD4",
"v0t4__",
+ "vec4f",
"cpA",
- "ec4h",
- "vBBc4h",
- "vec4h",
+ "ec4f",
+ "vBBc4f",
"vbnn99",
"EEcAAh",
"v5c66h",
- "vHc4i",
- "vecxi",
+ "vec4h",
+ "vHc4h",
+ "vecxh",
"vzyn40",
- "vec4i",
"ve4i",
"kH4i",
"veci",
+ "vec4i",
"oo4rr",
"JJc4",
"vcCC0",
- "vec4u",
"xAA99F",
"veccu",
"vec4S",
+ "vec4u",
+ "vocBB",
+ "ec4u",
+ "veemm",
};
for (auto _ : state) {
for (auto* str : kStrings) {
diff --git a/src/tint/builtin/builtin_test.cc b/src/tint/builtin/builtin_test.cc
index 2908bc2..9ff8d99 100644
--- a/src/tint/builtin/builtin_test.cc
+++ b/src/tint/builtin/builtin_test.cc
@@ -43,6 +43,7 @@
}
static constexpr Case kValidCases[] = {
+ {"__packed_vec3", Builtin::kPackedVec3},
{"array", Builtin::kArray},
{"atomic", Builtin::kAtomic},
{"bool", Builtin::kBool},
@@ -115,213 +116,216 @@
};
static constexpr Case kInvalidCases[] = {
- {"arccy", Builtin::kUndefined},
- {"3a", Builtin::kUndefined},
- {"aVray", Builtin::kUndefined},
- {"1tomic", Builtin::kUndefined},
- {"aoqqic", Builtin::kUndefined},
- {"atomll77", Builtin::kUndefined},
- {"ppqooH", Builtin::kUndefined},
- {"c", Builtin::kUndefined},
- {"bGo", Builtin::kUndefined},
- {"f1vi", Builtin::kUndefined},
- {"f8WW", Builtin::kUndefined},
- {"fxx", Builtin::kUndefined},
+ {"__acked_veccc", Builtin::kUndefined},
+ {"_pac3ed_v3", Builtin::kUndefined},
+ {"__packeV_vec3", Builtin::kUndefined},
+ {"arra1", Builtin::kUndefined},
+ {"qqrJy", Builtin::kUndefined},
+ {"arrll7y", Builtin::kUndefined},
+ {"atppmHHc", Builtin::kUndefined},
+ {"cto", Builtin::kUndefined},
+ {"abGmi", Builtin::kUndefined},
+ {"bovii", Builtin::kUndefined},
+ {"boWWl", Builtin::kUndefined},
+ {"Mxxl", Builtin::kUndefined},
{"fgg", Builtin::kUndefined},
{"X", Builtin::kUndefined},
- {"332", Builtin::kUndefined},
- {"iE2", Builtin::kUndefined},
- {"iPTT", Builtin::kUndefined},
+ {"316", Builtin::kUndefined},
+ {"fE2", Builtin::kUndefined},
+ {"fPTT", Builtin::kUndefined},
{"dxx2", Builtin::kUndefined},
- {"44at2x2", Builtin::kUndefined},
- {"mSSVV2x2", Builtin::kUndefined},
- {"mat2R2", Builtin::kUndefined},
- {"mF2x9f", Builtin::kUndefined},
- {"matx2f", Builtin::kUndefined},
- {"VOORRH2f", Builtin::kUndefined},
- {"ma2xyh", Builtin::kUndefined},
- {"llnarr2772h", Builtin::kUndefined},
+ {"4432", Builtin::kUndefined},
+ {"iSVV2", Builtin::kUndefined},
+ {"RR2", Builtin::kUndefined},
+ {"at292", Builtin::kUndefined},
+ {"mat2x", Builtin::kUndefined},
+ {"Vat2OR2", Builtin::kUndefined},
+ {"ma2xyf", Builtin::kUndefined},
+ {"llnarr2772f", Builtin::kUndefined},
{"mat24200", Builtin::kUndefined},
- {"m2oo", Builtin::kUndefined},
- {"atzz3", Builtin::kUndefined},
- {"1it2xpp", Builtin::kUndefined},
- {"mat2xXXf", Builtin::kUndefined},
- {"9II5ann2x3f", Builtin::kUndefined},
- {"mataSSrHHYf", Builtin::kUndefined},
- {"makkh", Builtin::kUndefined},
+ {"a2ooh", Builtin::kUndefined},
+ {"zz2x2h", Builtin::kUndefined},
+ {"miitppx1", Builtin::kUndefined},
+ {"maXX2x3", Builtin::kUndefined},
+ {"55IIt2nn99", Builtin::kUndefined},
+ {"aHHrrt2xSS", Builtin::kUndefined},
+ {"makkf", Builtin::kUndefined},
{"jatgRx", Builtin::kUndefined},
{"mb2x3", Builtin::kUndefined},
- {"mat2j4", Builtin::kUndefined},
- {"mt2x4", Builtin::kUndefined},
- {"m2q4", Builtin::kUndefined},
- {"matNN4f", Builtin::kUndefined},
- {"at24vv", Builtin::kUndefined},
- {"QQt2x4f", Builtin::kUndefined},
- {"maffxr", Builtin::kUndefined},
{"mat2xjh", Builtin::kUndefined},
+ {"at2x3h", Builtin::kUndefined},
+ {"q2x3h", Builtin::kUndefined},
+ {"mNN2x4", Builtin::kUndefined},
+ {"mavv4", Builtin::kUndefined},
+ {"maQQx4", Builtin::kUndefined},
+ {"maffxr", Builtin::kUndefined},
+ {"mat2xjf", Builtin::kUndefined},
{"mNNw2x48", Builtin::kUndefined},
- {"mt3x2", Builtin::kUndefined},
- {"rrat3x2", Builtin::kUndefined},
- {"mGt3x2", Builtin::kUndefined},
- {"mat3x2FF", Builtin::kUndefined},
- {"at3f", Builtin::kUndefined},
- {"marrx2f", Builtin::kUndefined},
- {"t3x2h", Builtin::kUndefined},
- {"Da3xJJh", Builtin::kUndefined},
+ {"matx4h", Builtin::kUndefined},
+ {"mrrt2x4h", Builtin::kUndefined},
+ {"Gat2x4h", Builtin::kUndefined},
+ {"matFFx2", Builtin::kUndefined},
+ {"mtx", Builtin::kUndefined},
+ {"mrrt3x", Builtin::kUndefined},
+ {"t3x2f", Builtin::kUndefined},
+ {"Da3xJJf", Builtin::kUndefined},
{"ma82", Builtin::kUndefined},
- {"1k33", Builtin::kUndefined},
- {"matx3", Builtin::kUndefined},
- {"maJx3", Builtin::kUndefined},
- {"mat3c3f", Builtin::kUndefined},
- {"mat3x3O", Builtin::kUndefined},
- {"KK_atvvtt3f", Builtin::kUndefined},
- {"xx83x3h", Builtin::kUndefined},
+ {"m11k2", Builtin::kUndefined},
+ {"matx2h", Builtin::kUndefined},
+ {"maJx2h", Builtin::kUndefined},
+ {"cat3x3", Builtin::kUndefined},
+ {"mat3O3", Builtin::kUndefined},
+ {"ttKavv3x__", Builtin::kUndefined},
+ {"xx83x3f", Builtin::kUndefined},
{"__qatF3", Builtin::kUndefined},
- {"matqx3h", Builtin::kUndefined},
- {"ma33x66", Builtin::kUndefined},
- {"mttQQo3x4", Builtin::kUndefined},
- {"mat66x", Builtin::kUndefined},
- {"mtOxzz66", Builtin::kUndefined},
- {"mat3yy4f", Builtin::kUndefined},
- {"ZaHH4Z", Builtin::kUndefined},
- {"4WWt3q4h", Builtin::kUndefined},
- {"mOO3x4h", Builtin::kUndefined},
- {"oatY4h", Builtin::kUndefined},
- {"ax2", Builtin::kUndefined},
- {"ma4x2", Builtin::kUndefined},
- {"matw2", Builtin::kUndefined},
- {"fGtxKf", Builtin::kUndefined},
- {"matqKx2f", Builtin::kUndefined},
- {"matmmxFf", Builtin::kUndefined},
- {"at4x2h", Builtin::kUndefined},
+ {"matqx3f", Builtin::kUndefined},
+ {"33atOx3h", Builtin::kUndefined},
+ {"mtt63x9oQQ", Builtin::kUndefined},
+ {"ma3x66h", Builtin::kUndefined},
+ {"66aOzx4", Builtin::kUndefined},
+ {"myyt3x4", Builtin::kUndefined},
+ {"HHZx4", Builtin::kUndefined},
+ {"4WWt3q4f", Builtin::kUndefined},
+ {"mOO3x4f", Builtin::kUndefined},
+ {"oatY4f", Builtin::kUndefined},
+ {"matx", Builtin::kUndefined},
+ {"ma3xFh", Builtin::kUndefined},
+ {"at3x4w", Builtin::kUndefined},
+ {"ma4Gf", Builtin::kUndefined},
+ {"qatKKx2", Builtin::kUndefined},
+ {"mmmt4x2", Builtin::kUndefined},
+ {"at4x2f", Builtin::kUndefined},
{"mt4x2q", Builtin::kUndefined},
{"mat4xbb", Builtin::kUndefined},
- {"it4x3", Builtin::kUndefined},
- {"mOO4xq", Builtin::kUndefined},
- {"mat4Tvv3", Builtin::kUndefined},
- {"maFF4x3f", Builtin::kUndefined},
- {"Pa00xQf", Builtin::kUndefined},
- {"mPt4x3f", Builtin::kUndefined},
+ {"mi4x2h", Builtin::kUndefined},
+ {"maOO4xq", Builtin::kUndefined},
+ {"matTvvx2h", Builtin::kUndefined},
+ {"mat4FF3", Builtin::kUndefined},
+ {"mtQ00P", Builtin::kUndefined},
+ {"maP4x3", Builtin::kUndefined},
{"ma774xss", Builtin::kUndefined},
- {"RRCbb4x3h", Builtin::kUndefined},
- {"mXXt4x3h", Builtin::kUndefined},
- {"CCt4OOOO", Builtin::kUndefined},
- {"mtsuL", Builtin::kUndefined},
- {"mat4xX", Builtin::kUndefined},
- {"mat44f", Builtin::kUndefined},
- {"qa4O4", Builtin::kUndefined},
- {"mat4x22f", Builtin::kUndefined},
+ {"RRCbb4x3f", Builtin::kUndefined},
+ {"mXXt4x3f", Builtin::kUndefined},
+ {"qaCC4xOOh", Builtin::kUndefined},
+ {"ma4s3L", Builtin::kUndefined},
+ {"mXt4x3h", Builtin::kUndefined},
+ {"mat4x", Builtin::kUndefined},
+ {"qqt4", Builtin::kUndefined},
+ {"mat4x22", Builtin::kUndefined},
{"myzz40XX", Builtin::kUndefined},
{"matVViP", Builtin::kUndefined},
- {"mannC4h", Builtin::kUndefined},
- {"pHAq", Builtin::kUndefined},
- {"tr", Builtin::kUndefined},
- {"Kf", Builtin::kUndefined},
- {"lmgger", Builtin::kUndefined},
- {"samplr", Builtin::kUndefined},
- {"NTTmcl4r", Builtin::kUndefined},
- {"sampler_clmppri77on", Builtin::kUndefined},
- {"samplg_czzmparNNso", Builtin::kUndefined},
- {"smpleuuXXomparibbon", Builtin::kUndefined},
- {"texture_1", Builtin::kUndefined},
- {"t88tueQ1K", Builtin::kUndefined},
- {"texturq9d", Builtin::kUndefined},
- {"text11re_2d", Builtin::kUndefined},
- {"teiiu22eF2d", Builtin::kUndefined},
- {"tex77ur_2d", Builtin::kUndefined},
- {"textNNr2_d_array", Builtin::kUndefined},
- {"textVVre_2d_array", Builtin::kUndefined},
- {"texwure_WWF_11rray", Builtin::kUndefined},
- {"txture_3ww", Builtin::kUndefined},
- {"texturD_3d", Builtin::kUndefined},
- {"teKture_d", Builtin::kUndefined},
- {"11exPPufe_cubh", Builtin::kUndefined},
- {"textue_cube", Builtin::kUndefined},
- {"texture_cubYY", Builtin::kUndefined},
- {"texttr_cube_HHkkVay", Builtin::kUndefined},
- {"texture_crrbe_array", Builtin::kUndefined},
- {"texturesscubeWWaray", Builtin::kUndefined},
- {"texture_deptY_d", Builtin::kUndefined},
- {"teLturq_defh_2d", Builtin::kUndefined},
- {"texvvre_duu22th_2d", Builtin::kUndefined},
- {"texure_deth_2d_array", Builtin::kUndefined},
- {"texturYY_depth_2daray", Builtin::kUndefined},
- {"texturE_77epth_2d_aryYay", Builtin::kUndefined},
- {"Mexdoore_depth_cue", Builtin::kUndefined},
- {"texturedepMMh_cube", Builtin::kUndefined},
- {"texture55depth_cube", Builtin::kUndefined},
- {"textue_depth_cbe_aNray", Builtin::kUndefined},
- {"texture_dpth_c33be_array", Builtin::kUndefined},
- {"texture_depth_cub3_array", Builtin::kUndefined},
- {"texIure_mepth_mulisampled_2d", Builtin::kUndefined},
- {"texture_depthrmKltisampled_2nn", Builtin::kUndefined},
- {"textur_depth_multismXld_2d", Builtin::kUndefined},
- {"texpure_exLLeIna", Builtin::kUndefined},
- {"txture_exfrnal", Builtin::kUndefined},
- {"teUture_extYRRDl", Builtin::kUndefined},
- {"texturehmultisampled_2d", Builtin::kUndefined},
- {"texturqmultsIImuuled_2d", Builtin::kUndefined},
- {"Hexture_multisampled_2d", Builtin::kUndefined},
- {"texQQur_storge_vvd", Builtin::kUndefined},
- {"texeure_66oage_1d", Builtin::kUndefined},
- {"texture_stoage71d", Builtin::kUndefined},
- {"texture_s55or0ge_2DD", Builtin::kUndefined},
- {"teHture_storIIge_2d", Builtin::kUndefined},
- {"textue_storage_2d", Builtin::kUndefined},
- {"texturestorage_2d_rrray", Builtin::kUndefined},
- {"textule_storage_2d_array", Builtin::kUndefined},
- {"tetture_JJtorage_Gd_arra", Builtin::kUndefined},
- {"yexture_storage3d", Builtin::kUndefined},
- {"texturestorage_3d", Builtin::kUndefined},
- {"texture_IItorBBge_3d", Builtin::kUndefined},
- {"TTK33", Builtin::kUndefined},
- {"nnUYdSS2", Builtin::kUndefined},
- {"x5dZ", Builtin::kUndefined},
- {"veckq", Builtin::kUndefined},
- {"ii500", Builtin::kUndefined},
- {"vecIIn", Builtin::kUndefined},
- {"cceW", Builtin::kUndefined},
- {"cKK", Builtin::kUndefined},
- {"vec66f", Builtin::kUndefined},
- {"vePPK", Builtin::kUndefined},
- {"vexxh", Builtin::kUndefined},
- {"qec2h", Builtin::kUndefined},
+ {"mannC4f", Builtin::kUndefined},
+ {"atx4AHHq", Builtin::kUndefined},
+ {"may4x4", Builtin::kUndefined},
+ {"aOOOZZh", Builtin::kUndefined},
+ {"V", Builtin::kUndefined},
+ {"ptf__", Builtin::kUndefined},
+ {"4lMT", Builtin::kUndefined},
+ {"sNNmplg", Builtin::kUndefined},
+ {"uubpXXer", Builtin::kUndefined},
+ {"samler", Builtin::kUndefined},
+ {"m88ler_cQmparisoK", Builtin::kUndefined},
+ {"qa9ler_comparison", Builtin::kUndefined},
+ {"sampler_comparis11n", Builtin::kUndefined},
+ {"teiiu22eF1d", Builtin::kUndefined},
+ {"tex77ur_1d", Builtin::kUndefined},
+ {"te2urNN_1d", Builtin::kUndefined},
+ {"texturVV_2d", Builtin::kUndefined},
+ {"WWFxtu11e_wd", Builtin::kUndefined},
+ {"txture_2ww", Builtin::kUndefined},
+ {"texture_2d_arrDy", Builtin::kUndefined},
+ {"teKtre_2d_array", Builtin::kUndefined},
+ {"texhure_2fra11raPP", Builtin::kUndefined},
+ {"texture3d", Builtin::kUndefined},
+ {"texture_3YY", Builtin::kUndefined},
+ {"HHtxtrkk_3d", Builtin::kUndefined},
+ {"texrrure_cube", Builtin::kUndefined},
+ {"tssxturWW_cue", Builtin::kUndefined},
+ {"teYure_cube", Builtin::kUndefined},
+ {"txture_Lufe_arraq", Builtin::kUndefined},
+ {"te22ture_uuubevvfray", Builtin::kUndefined},
+ {"texturecube_aray", Builtin::kUndefined},
+ {"texture_Yepth_2", Builtin::kUndefined},
+ {"teytYYEe_77epth_2d", Builtin::kUndefined},
+ {"teMture_deootd2d", Builtin::kUndefined},
+ {"texMMre_depth_2d_array", Builtin::kUndefined},
+ {"texture_depth_2d_arra55", Builtin::kUndefined},
+ {"texture_deh_2d_aNray", Builtin::kUndefined},
+ {"te3ture_dpth_cO3be", Builtin::kUndefined},
+ {"texture_depth_cub3", Builtin::kUndefined},
+ {"Iexturedepth_cume", Builtin::kUndefined},
+ {"texture_depthnncube_Krrry", Builtin::kUndefined},
+ {"texture_dth_XXube_rra", Builtin::kUndefined},
+ {"textIre_depph_ubeLLarray", Builtin::kUndefined},
+ {"txtfre_depthmultisampled_2d", Builtin::kUndefined},
+ {"texURuYe_Depthmultisampled_2d", Builtin::kUndefined},
+ {"texture_depth_multisamphed_2d", Builtin::kUndefined},
+ {"teqtureuIIextnal", Builtin::kUndefined},
+ {"texture_externaH", Builtin::kUndefined},
+ {"texre_externaQvv", Builtin::kUndefined},
+ {"textureemultismp66ed_d", Builtin::kUndefined},
+ {"tW7trO_multisampled_2d", Builtin::kUndefined},
+ {"texture_mult550ampled_2DD", Builtin::kUndefined},
+ {"teHture_storIIge_1d", Builtin::kUndefined},
+ {"textue_storage_1d", Builtin::kUndefined},
+ {"rexture_storae_1d", Builtin::kUndefined},
+ {"texture_stolage_2d", Builtin::kUndefined},
+ {"txture_JJtGrgtt_2d", Builtin::kUndefined},
+ {"yexture_storage2d", Builtin::kUndefined},
+ {"texture_storage_2d_rray", Builtin::kUndefined},
+ {"texture_IItorage_2d_BBrray", Builtin::kUndefined},
+ {"33exture_TTtorge_Kd_ar88ay", Builtin::kUndefined},
+ {"texSnnYUUure_storage_3d", Builtin::kUndefined},
+ {"textuxe_5torCCdZ_3d", Builtin::kUndefined},
+ {"tkkxture_storaqe_3d", Builtin::kUndefined},
+ {"5i00", Builtin::kUndefined},
+ {"unII2", Builtin::kUndefined},
+ {"cc", Builtin::kUndefined},
+ {"KK", Builtin::kUndefined},
+ {"66ec2", Builtin::kUndefined},
+ {"PPEK", Builtin::kUndefined},
+ {"vexxf", Builtin::kUndefined},
+ {"qec2f", Builtin::kUndefined},
{"veSyMMr", Builtin::kUndefined},
{"v2u", Builtin::kUndefined},
{"ec", Builtin::kUndefined},
- {"5eFF2u", Builtin::kUndefined},
+ {"5eFF2h", Builtin::kUndefined},
{"rrecz44", Builtin::kUndefined},
{"vWW", Builtin::kUndefined},
- {"ZJJCcX", Builtin::kUndefined},
- {"vcPP", Builtin::kUndefined},
- {"vec", Builtin::kUndefined},
- {"3Le003f", Builtin::kUndefined},
- {"MMec3RR", Builtin::kUndefined},
- {"vec39K", Builtin::kUndefined},
- {"yyecm", Builtin::kUndefined},
- {"v__cD", Builtin::kUndefined},
- {"vec3U", Builtin::kUndefined},
- {"ze333i", Builtin::kUndefined},
- {"eKti", Builtin::kUndefined},
- {"ve3V", Builtin::kUndefined},
- {"jbR3K", Builtin::kUndefined},
- {"e44344", Builtin::kUndefined},
- {"00u", Builtin::kUndefined},
- {"WK4", Builtin::kUndefined},
- {"m", Builtin::kUndefined},
- {"vJJ", Builtin::kUndefined},
- {"lDDcUfC", Builtin::kUndefined},
- {"vec4g", Builtin::kUndefined},
- {"CCe", Builtin::kUndefined},
- {"ec4h", Builtin::kUndefined},
- {"vIc__h", Builtin::kUndefined},
+ {"XJecCZZ", Builtin::kUndefined},
+ {"vePP2", Builtin::kUndefined},
+ {"vec2c", Builtin::kUndefined},
+ {"ve6ll2u", Builtin::kUndefined},
+ {"vey99", Builtin::kUndefined},
+ {"vKKc3", Builtin::kUndefined},
+ {"x_3", Builtin::kUndefined},
+ {"Ky3", Builtin::kUndefined},
+ {"zek3f", Builtin::kUndefined},
+ {"veKSf", Builtin::kUndefined},
+ {"vc3h", Builtin::kUndefined},
+ {"ec3VV", Builtin::kUndefined},
+ {"IAAc3h", Builtin::kUndefined},
+ {"jbR", Builtin::kUndefined},
+ {"veY4", Builtin::kUndefined},
+ {"ec3i", Builtin::kUndefined},
+ {"vc911", Builtin::kUndefined},
+ {"mmccu", Builtin::kUndefined},
+ {"vJJcu", Builtin::kUndefined},
+ {"lDCfcU", Builtin::kUndefined},
+ {"veg4", Builtin::kUndefined},
+ {"CC", Builtin::kUndefined},
+ {"ec4f", Builtin::kUndefined},
+ {"vIc__f", Builtin::kUndefined},
{"ePPtt", Builtin::kUndefined},
- {"v3dc4i", Builtin::kUndefined},
- {"vcyyi", Builtin::kUndefined},
+ {"v3dc4h", Builtin::kUndefined},
+ {"vcyyh", Builtin::kUndefined},
{"u4", Builtin::kUndefined},
- {"v03nnu", Builtin::kUndefined},
+ {"v03nni", Builtin::kUndefined},
{"Cuuecnv", Builtin::kUndefined},
{"vX4ll", Builtin::kUndefined},
+ {"vocppu", Builtin::kUndefined},
+ {"vwwc4", Builtin::kUndefined},
+ {"veuug", Builtin::kUndefined},
};
using BuiltinParseTest = testing::TestWithParam<Case>;
diff --git a/src/tint/builtin/extension.cc b/src/tint/builtin/extension.cc
index 3d57867..36171db 100644
--- a/src/tint/builtin/extension.cc
+++ b/src/tint/builtin/extension.cc
@@ -40,6 +40,9 @@
if (str == "chromium_experimental_push_constant") {
return Extension::kChromiumExperimentalPushConstant;
}
+ if (str == "chromium_internal_relaxed_uniform_layout") {
+ return Extension::kChromiumInternalRelaxedUniformLayout;
+ }
if (str == "f16") {
return Extension::kF16;
}
@@ -58,6 +61,8 @@
return out << "chromium_experimental_full_ptr_parameters";
case Extension::kChromiumExperimentalPushConstant:
return out << "chromium_experimental_push_constant";
+ case Extension::kChromiumInternalRelaxedUniformLayout:
+ return out << "chromium_internal_relaxed_uniform_layout";
case Extension::kF16:
return out << "f16";
}
diff --git a/src/tint/builtin/extension.h b/src/tint/builtin/extension.h
index f0ebeca..aace504 100644
--- a/src/tint/builtin/extension.h
+++ b/src/tint/builtin/extension.h
@@ -37,6 +37,7 @@
kChromiumExperimentalDp4A,
kChromiumExperimentalFullPtrParameters,
kChromiumExperimentalPushConstant,
+ kChromiumInternalRelaxedUniformLayout,
kF16,
};
@@ -51,11 +52,9 @@
Extension ParseExtension(std::string_view str);
constexpr const char* kExtensionStrings[] = {
- "chromium_disable_uniformity_analysis",
- "chromium_experimental_dp4a",
- "chromium_experimental_full_ptr_parameters",
- "chromium_experimental_push_constant",
- "f16",
+ "chromium_disable_uniformity_analysis", "chromium_experimental_dp4a",
+ "chromium_experimental_full_ptr_parameters", "chromium_experimental_push_constant",
+ "chromium_internal_relaxed_uniform_layout", "f16",
};
// A unique vector of extensions
diff --git a/src/tint/builtin/extension_bench.cc b/src/tint/builtin/extension_bench.cc
index 4619ce2..b3e410e 100644
--- a/src/tint/builtin/extension_bench.cc
+++ b/src/tint/builtin/extension_bench.cc
@@ -59,13 +59,20 @@
"chromium_exp9rimFntal_ush_constant",
"chrmium_experimental_push_constant",
"cOOromium_experiVeHtal_puh_conRRtant",
- "y1",
- "l77rrn6",
- "4016",
+ "chromium_internl_relaxyd_uniform_layout",
+ "chromnnum_internrr77_Gelaxell_uniform_layout",
+ "chromium_intern4l_relaxe00_uniform_layout",
+ "chromium_internal_relaxed_uniform_layout",
+ "chrmoom_internal_relaxed_uniform_lyout",
+ "chroium_internal_rlaxed_uniform_layzzut",
+ "chromium_internaii_r11axed_uppifor_layout",
+ "f1XX",
+ "55199II",
+ "frSSHHa",
"f16",
- "5",
- "u16",
- "f",
+ "U",
+ "jV3",
+ "",
};
for (auto _ : state) {
for (auto* str : kStrings) {
diff --git a/src/tint/builtin/extension_test.cc b/src/tint/builtin/extension_test.cc
index 01eb1ae..9ef8683 100644
--- a/src/tint/builtin/extension_test.cc
+++ b/src/tint/builtin/extension_test.cc
@@ -48,6 +48,7 @@
{"chromium_experimental_full_ptr_parameters",
Extension::kChromiumExperimentalFullPtrParameters},
{"chromium_experimental_push_constant", Extension::kChromiumExperimentalPushConstant},
+ {"chromium_internal_relaxed_uniform_layout", Extension::kChromiumInternalRelaxedUniformLayout},
{"f16", Extension::kF16},
};
@@ -64,9 +65,12 @@
{"chvomium_experimental_push_constiint", Extension::kUndefined},
{"chromiu8WWexperimental_push_constant", Extension::kUndefined},
{"chromium_experiMental_push_costanxx", Extension::kUndefined},
- {"fgg", Extension::kUndefined},
- {"X", Extension::kUndefined},
- {"316", Extension::kUndefined},
+ {"chromium_internal_relaxed_unXform_layugg", Extension::kUndefined},
+ {"chromiuu_iVterna_relxed_unifXrm_layout", Extension::kUndefined},
+ {"chromium_internal_relaxed_uni3orm_layout", Extension::kUndefined},
+ {"fE6", Extension::kUndefined},
+ {"fPTT", Extension::kUndefined},
+ {"dxx6", Extension::kUndefined},
};
using ExtensionParseTest = testing::TestWithParam<Case>;
diff --git a/src/tint/cmd/main.cc b/src/tint/cmd/main.cc
index cd46885..12d5b8c 100644
--- a/src/tint/cmd/main.cc
+++ b/src/tint/cmd/main.cc
@@ -37,6 +37,7 @@
#include "src/tint/cmd/helper.h"
#include "src/tint/utils/io/command.h"
#include "src/tint/utils/string.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/transform.h"
#include "src/tint/val/val.h"
#include "tint/tint.h"
@@ -245,7 +246,7 @@
std::vector<std::string> split_on_char(std::string list, char c) {
std::vector<std::string> res;
- std::stringstream str(list);
+ std::istringstream str(list);
while (str.good()) {
std::string substr;
getline(str, substr, c);
@@ -1034,7 +1035,7 @@
}},
};
auto transform_names = [&] {
- std::stringstream names;
+ tint::utils::StringStream names;
for (auto& t : transforms) {
names << " " << t.name << std::endl;
}
diff --git a/src/tint/debug.h b/src/tint/debug.h
index 43bc052..5caeb5d 100644
--- a/src/tint/debug.h
+++ b/src/tint/debug.h
@@ -21,6 +21,7 @@
#include "src/tint/diagnostic/formatter.h"
#include "src/tint/diagnostic/printer.h"
#include "src/tint/utils/compiler_macros.h"
+#include "src/tint/utils/string_stream.h"
namespace tint {
@@ -71,7 +72,7 @@
const size_t line_;
diag::System system_;
diag::List& diagnostics_;
- std::stringstream msg_;
+ utils::StringStream msg_;
};
} // namespace tint
diff --git a/src/tint/demangler.cc b/src/tint/demangler.cc
index d68a62a..146a31c 100644
--- a/src/tint/demangler.cc
+++ b/src/tint/demangler.cc
@@ -15,6 +15,7 @@
#include "src/tint/demangler.h"
#include "src/tint/program.h"
+#include "src/tint/utils/string_stream.h"
namespace tint {
namespace {
@@ -29,7 +30,7 @@
Demangler::~Demangler() = default;
std::string Demangler::Demangle(const SymbolTable& symbols, const std::string& str) const {
- std::stringstream out;
+ utils::StringStream out;
size_t pos = 0;
for (;;) {
diff --git a/src/tint/diagnostic/formatter.cc b/src/tint/diagnostic/formatter.cc
index db69397..18520fc 100644
--- a/src/tint/diagnostic/formatter.cc
+++ b/src/tint/diagnostic/formatter.cc
@@ -20,6 +20,7 @@
#include "src/tint/diagnostic/diagnostic.h"
#include "src/tint/diagnostic/printer.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::diag {
namespace {
@@ -41,7 +42,7 @@
}
std::string to_str(const Source::Location& location) {
- std::stringstream ss;
+ utils::StringStream ss;
if (location.line > 0) {
ss << location.line;
if (location.column > 0) {
@@ -75,7 +76,7 @@
auto str = stream.str();
if (str.length() > 0) {
printer->write(str, style);
- std::stringstream reset;
+ utils::StringStream reset;
stream.swap(reset);
}
}
@@ -95,12 +96,12 @@
/// repeat queues the character c to be written to the printer n times.
/// @param c the character to print `n` times
/// @param n the number of times to print character `c`
- void repeat(char c, size_t n) { std::fill_n(std::ostream_iterator<char>(stream), n, c); }
+ void repeat(char c, size_t n) { stream.repeat(c, n); }
private:
Printer* printer;
diag::Style style;
- std::stringstream stream;
+ utils::StringStream stream;
};
Formatter::Formatter() {}
diff --git a/src/tint/diagnostic/printer.h b/src/tint/diagnostic/printer.h
index b2ac105..9e4ce7c 100644
--- a/src/tint/diagnostic/printer.h
+++ b/src/tint/diagnostic/printer.h
@@ -19,6 +19,8 @@
#include <sstream>
#include <string>
+#include "src/tint/utils/string_stream.h"
+
namespace tint::diag {
class List;
@@ -73,7 +75,7 @@
void write(const std::string& str, const Style&) override;
private:
- std::stringstream stream;
+ utils::StringStream stream;
};
} // namespace tint::diag
diff --git a/src/tint/intrinsics.def b/src/tint/intrinsics.def
index 826a667..7a5334f 100644
--- a/src/tint/intrinsics.def
+++ b/src/tint/intrinsics.def
@@ -70,6 +70,8 @@
// A Chromium-specific extension that enables passing of uniform, storage and workgroup
// address-spaced pointers as parameters, as well as pointers into sub-objects.
chromium_experimental_full_ptr_parameters
+ // A Chromium-specific extension that relaxes memory layout requirements for uniform storage.
+ chromium_internal_relaxed_uniform_layout
}
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
@@ -209,6 +211,9 @@
texture_storage_3d
// https://www.w3.org/TR/WGSL/#external-texture-type
texture_external
+
+ // Internal types.
+ __packed_vec3
}
// https://gpuweb.github.io/gpuweb/wgsl/#attributes
@@ -287,6 +292,7 @@
type texture_storage_2d_array<F: texel_format, A: access>
type texture_storage_3d<F: texel_format, A: access>
type texture_external
+type packedVec3<T>
@display("__modf_result_{T}") type __modf_result<T>
@display("__modf_result_vec{N}_{T}") type __modf_result_vec<N: num, T>
@@ -999,6 +1005,9 @@
@must_use @const conv mat4x4<T: f16>(mat4x4<f32>) -> mat4x4<f16>
@must_use @const conv mat4x4<T: f32>(mat4x4<f16>) -> mat4x4<f32>
+// Conversion from vec3 to internal __packed_vec3 type.
+@must_use @const conv packedVec3<T: concrete_scalar>(vec3<T>) -> packedVec3<T>
+
////////////////////////////////////////////////////////////////////////////////
// Operators //
// //
diff --git a/src/tint/ir/binary.cc b/src/tint/ir/binary.cc
index e48ca86..cdec94d 100644
--- a/src/tint/ir/binary.cc
+++ b/src/tint/ir/binary.cc
@@ -29,7 +29,7 @@
Binary::~Binary() = default;
-std::ostream& Binary::ToString(std::ostream& out, const SymbolTable& st) const {
+utils::StringStream& Binary::ToString(utils::StringStream& out, const SymbolTable& st) const {
Result()->ToString(out, st) << " = ";
lhs_->ToString(out, st) << " ";
diff --git a/src/tint/ir/binary.h b/src/tint/ir/binary.h
index 85ad9dc..be5d243 100644
--- a/src/tint/ir/binary.h
+++ b/src/tint/ir/binary.h
@@ -21,6 +21,7 @@
#include "src/tint/ir/instruction.h"
#include "src/tint/symbol_table.h"
#include "src/tint/type/type.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::ir {
@@ -79,7 +80,7 @@
/// @param out the stream to write to
/// @param st the symbol table
/// @returns the stream
- std::ostream& ToString(std::ostream& out, const SymbolTable& st) const override;
+ utils::StringStream& ToString(utils::StringStream& out, const SymbolTable& st) const override;
private:
Kind kind_;
@@ -87,8 +88,6 @@
Value* rhs_ = nullptr;
};
-std::ostream& operator<<(std::ostream& out, const Binary&);
-
} // namespace tint::ir
#endif // SRC_TINT_IR_BINARY_H_
diff --git a/src/tint/ir/binary_test.cc b/src/tint/ir/binary_test.cc
index b5fba93..103719c 100644
--- a/src/tint/ir/binary_test.cc
+++ b/src/tint/ir/binary_test.cc
@@ -16,6 +16,7 @@
#include "src/tint/ir/instruction.h"
#include "src/tint/ir/test_helper.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::ir {
namespace {
@@ -47,7 +48,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (i32) = 4 & 2");
}
@@ -74,7 +75,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (i32) = 4 | 2");
}
@@ -101,7 +102,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (i32) = 4 ^ 2");
}
@@ -128,7 +129,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (bool) = 4 && 2");
}
@@ -155,7 +156,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (bool) = 4 || 2");
}
@@ -182,7 +183,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (bool) = 4 == 2");
}
@@ -209,7 +210,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (bool) = 4 != 2");
}
@@ -236,7 +237,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (bool) = 4 < 2");
}
@@ -263,7 +264,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (bool) = 4 > 2");
}
@@ -290,7 +291,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (bool) = 4 <= 2");
}
@@ -317,7 +318,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (bool) = 4 >= 2");
}
@@ -344,7 +345,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (i32) = 4 << 2");
}
@@ -371,7 +372,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (i32) = 4 >> 2");
}
@@ -398,7 +399,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (i32) = 4 + 2");
}
@@ -425,7 +426,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (i32) = 4 - 2");
}
@@ -452,7 +453,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (i32) = 4 * 2");
}
@@ -479,7 +480,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (i32) = 4 / 2");
}
@@ -506,7 +507,7 @@
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (i32) = 4 % 2");
}
diff --git a/src/tint/ir/bitcast.cc b/src/tint/ir/bitcast.cc
index 512d93a..3cf0c97 100644
--- a/src/tint/ir/bitcast.cc
+++ b/src/tint/ir/bitcast.cc
@@ -26,7 +26,7 @@
Bitcast::~Bitcast() = default;
-std::ostream& Bitcast::ToString(std::ostream& out, const SymbolTable& st) const {
+utils::StringStream& Bitcast::ToString(utils::StringStream& out, const SymbolTable& st) const {
Result()->ToString(out, st);
out << " = bitcast(";
val_->ToString(out, st);
diff --git a/src/tint/ir/bitcast.h b/src/tint/ir/bitcast.h
index df8a05e..16d62f8 100644
--- a/src/tint/ir/bitcast.h
+++ b/src/tint/ir/bitcast.h
@@ -21,6 +21,7 @@
#include "src/tint/ir/instruction.h"
#include "src/tint/symbol_table.h"
#include "src/tint/type/type.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::ir {
@@ -45,14 +46,12 @@
/// @param out the stream to write to
/// @param st the symbol table
/// @returns the stream
- std::ostream& ToString(std::ostream& out, const SymbolTable& st) const override;
+ utils::StringStream& ToString(utils::StringStream& out, const SymbolTable& st) const override;
private:
Value* val_ = nullptr;
};
-std::ostream& operator<<(std::ostream& out, const Bitcast&);
-
} // namespace tint::ir
#endif // SRC_TINT_IR_BITCAST_H_
diff --git a/src/tint/ir/bitcast_test.cc b/src/tint/ir/bitcast_test.cc
index ee7bd3d..d190abb 100644
--- a/src/tint/ir/bitcast_test.cc
+++ b/src/tint/ir/bitcast_test.cc
@@ -16,6 +16,7 @@
#include "src/tint/ir/instruction.h"
#include "src/tint/ir/test_helper.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::ir {
namespace {
@@ -40,7 +41,7 @@
ASSERT_TRUE(val->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, val->As<constant::Scalar<i32>>()->ValueAs<i32>());
- std::stringstream str;
+ utils::StringStream str;
instr->ToString(str, b.builder.ir.symbols);
EXPECT_EQ(str.str(), "%42 (i32) = bitcast(4)");
}
diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc
index ccf0ccf..b70c059 100644
--- a/src/tint/ir/builder_impl_test.cc
+++ b/src/tint/ir/builder_impl_test.cc
@@ -1836,8 +1836,8 @@
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 >> 4
%2 (u32) = %1 (u32) + 9
%3 (bool) = 1 < %2 (u32)
-%4 (f32) = 2.3 * 5.5
-%5 (f32) = 6.7 / %4 (f32)
+%4 (f32) = 2.299999952 * 5.5
+%5 (f32) = 6.699999809 / %4 (f32)
%6 (bool) = 2.5 > %5 (f32)
%7 (bool) = %3 (bool) && %6 (bool)
)");
diff --git a/src/tint/ir/constant.cc b/src/tint/ir/constant.cc
index 98a5d3d..da4cb36 100644
--- a/src/tint/ir/constant.cc
+++ b/src/tint/ir/constant.cc
@@ -28,7 +28,7 @@
Constant::~Constant() = default;
-std::ostream& Constant::ToString(std::ostream& out, const SymbolTable& st) const {
+utils::StringStream& Constant::ToString(utils::StringStream& out, const SymbolTable& st) const {
std::function<void(const constant::Value*)> emit = [&](const constant::Value* c) {
Switch(
c,
diff --git a/src/tint/ir/constant.h b/src/tint/ir/constant.h
index 10b41d3..e7d66a4 100644
--- a/src/tint/ir/constant.h
+++ b/src/tint/ir/constant.h
@@ -20,6 +20,7 @@
#include "src/tint/constant/value.h"
#include "src/tint/ir/value.h"
#include "src/tint/symbol_table.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::ir {
@@ -38,7 +39,7 @@
/// @param out the stream to write to
/// @param st the symbol table
/// @returns the stream
- std::ostream& ToString(std::ostream& out, const SymbolTable& st) const override;
+ utils::StringStream& ToString(utils::StringStream& out, const SymbolTable& st) const override;
/// The constants value
const constant::Value* const value;
diff --git a/src/tint/ir/constant_test.cc b/src/tint/ir/constant_test.cc
index c6fe2e4..745ec54 100644
--- a/src/tint/ir/constant_test.cc
+++ b/src/tint/ir/constant_test.cc
@@ -16,6 +16,7 @@
#include "src/tint/ir/test_helper.h"
#include "src/tint/ir/value.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::ir {
namespace {
@@ -27,13 +28,13 @@
TEST_F(IR_ConstantTest, f32) {
auto& b = CreateEmptyBuilder();
- std::stringstream str;
+ utils::StringStream str;
auto* c = b.builder.Constant(1.2_f);
EXPECT_EQ(1.2_f, c->value->As<constant::Scalar<f32>>()->ValueAs<f32>());
c->ToString(str, b.builder.ir.symbols);
- EXPECT_EQ("1.2", str.str());
+ EXPECT_EQ("1.200000048", str.str());
EXPECT_TRUE(c->value->Is<constant::Scalar<f32>>());
EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
@@ -45,13 +46,13 @@
TEST_F(IR_ConstantTest, f16) {
auto& b = CreateEmptyBuilder();
- std::stringstream str;
+ utils::StringStream str;
auto* c = b.builder.Constant(1.1_h);
EXPECT_EQ(1.1_h, c->value->As<constant::Scalar<f16>>()->ValueAs<f16>());
c->ToString(str, b.builder.ir.symbols);
- EXPECT_EQ("1.09961", str.str());
+ EXPECT_EQ("1.099609375", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
EXPECT_TRUE(c->value->Is<constant::Scalar<f16>>());
@@ -63,7 +64,7 @@
TEST_F(IR_ConstantTest, i32) {
auto& b = CreateEmptyBuilder();
- std::stringstream str;
+ utils::StringStream str;
auto* c = b.builder.Constant(1_i);
EXPECT_EQ(1_i, c->value->As<constant::Scalar<i32>>()->ValueAs<i32>());
@@ -81,7 +82,7 @@
TEST_F(IR_ConstantTest, u32) {
auto& b = CreateEmptyBuilder();
- std::stringstream str;
+ utils::StringStream str;
auto* c = b.builder.Constant(2_u);
EXPECT_EQ(2_u, c->value->As<constant::Scalar<u32>>()->ValueAs<u32>());
@@ -99,26 +100,30 @@
TEST_F(IR_ConstantTest, bool) {
auto& b = CreateEmptyBuilder();
- std::stringstream str;
+ {
+ utils::StringStream str;
- auto* c = b.builder.Constant(false);
- EXPECT_FALSE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
+ auto* c = b.builder.Constant(false);
+ EXPECT_FALSE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
- c->ToString(str, b.builder.ir.symbols);
- EXPECT_EQ("false", str.str());
+ c->ToString(str, b.builder.ir.symbols);
+ EXPECT_EQ("false", str.str());
+ }
- str.str("");
- c = b.builder.Constant(true);
- EXPECT_TRUE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
+ {
+ utils::StringStream str;
+ auto c = b.builder.Constant(true);
+ EXPECT_TRUE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
- c->ToString(str, b.builder.ir.symbols);
- EXPECT_EQ("true", str.str());
+ c->ToString(str, b.builder.ir.symbols);
+ EXPECT_EQ("true", str.str());
- EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
- EXPECT_TRUE(c->value->Is<constant::Scalar<bool>>());
+ EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
+ EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
+ EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
+ EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
+ EXPECT_TRUE(c->value->Is<constant::Scalar<bool>>());
+ }
}
} // namespace
diff --git a/src/tint/ir/debug.cc b/src/tint/ir/debug.cc
index 617b207..b541236 100644
--- a/src/tint/ir/debug.cc
+++ b/src/tint/ir/debug.cc
@@ -23,6 +23,7 @@
#include "src/tint/ir/loop.h"
#include "src/tint/ir/switch.h"
#include "src/tint/ir/terminator.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::ir {
@@ -33,7 +34,7 @@
std::unordered_set<const FlowNode*> visited;
std::unordered_set<const FlowNode*> merge_nodes;
std::unordered_map<const FlowNode*, std::string> node_to_name;
- std::stringstream out;
+ utils::StringStream out;
auto name_for = [&](const FlowNode* node) -> std::string {
if (node_to_name.count(node) > 0) {
diff --git a/src/tint/ir/disassembler.cc b/src/tint/ir/disassembler.cc
index 4665c80..1bac411 100644
--- a/src/tint/ir/disassembler.cc
+++ b/src/tint/ir/disassembler.cc
@@ -53,7 +53,7 @@
Disassembler::~Disassembler() = default;
-std::ostream& Disassembler::Indent() {
+utils::StringStream& Disassembler::Indent() {
for (uint32_t i = 0; i < indent_size_; i++) {
out_ << " ";
}
diff --git a/src/tint/ir/disassembler.h b/src/tint/ir/disassembler.h
index 03cbea1..1ed822c 100644
--- a/src/tint/ir/disassembler.h
+++ b/src/tint/ir/disassembler.h
@@ -22,6 +22,7 @@
#include "src/tint/ir/flow_node.h"
#include "src/tint/ir/module.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::ir {
@@ -45,12 +46,12 @@
std::string AsString() const { return out_.str(); }
private:
- std::ostream& Indent();
+ utils::StringStream& Indent();
void Walk(const FlowNode* node);
size_t GetIdForNode(const FlowNode* node);
const Module& mod_;
- std::stringstream out_;
+ utils::StringStream out_;
std::unordered_set<const FlowNode*> visited_;
std::unordered_set<const FlowNode*> stop_nodes_;
std::unordered_map<const FlowNode*, size_t> flow_node_to_id_;
diff --git a/src/tint/ir/instruction.h b/src/tint/ir/instruction.h
index 8cd9ba8..abd5179 100644
--- a/src/tint/ir/instruction.h
+++ b/src/tint/ir/instruction.h
@@ -20,6 +20,7 @@
#include "src/tint/castable.h"
#include "src/tint/ir/value.h"
#include "src/tint/symbol_table.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::ir {
@@ -41,7 +42,8 @@
/// @param out the stream to write to
/// @param st the symbol table
/// @returns the stream
- virtual std::ostream& ToString(std::ostream& out, const SymbolTable& st) const = 0;
+ virtual utils::StringStream& ToString(utils::StringStream& out,
+ const SymbolTable& st) const = 0;
protected:
/// Constructor
diff --git a/src/tint/ir/temp.cc b/src/tint/ir/temp.cc
index e925561..3efae03 100644
--- a/src/tint/ir/temp.cc
+++ b/src/tint/ir/temp.cc
@@ -24,7 +24,7 @@
Temp::~Temp() = default;
-std::ostream& Temp::ToString(std::ostream& out, const SymbolTable& st) const {
+utils::StringStream& Temp::ToString(utils::StringStream& out, const SymbolTable& st) const {
out << "%" << std::to_string(AsId()) << " (" << type_->FriendlyName(st) << ")";
return out;
}
diff --git a/src/tint/ir/temp.h b/src/tint/ir/temp.h
index 1a4a38d..989e416 100644
--- a/src/tint/ir/temp.h
+++ b/src/tint/ir/temp.h
@@ -19,6 +19,7 @@
#include "src/tint/ir/value.h"
#include "src/tint/symbol_table.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::ir {
@@ -52,7 +53,7 @@
/// @param out the stream to write to
/// @param st the symbol table
/// @returns the stream
- std::ostream& ToString(std::ostream& out, const SymbolTable& st) const override;
+ utils::StringStream& ToString(utils::StringStream& out, const SymbolTable& st) const override;
private:
const type::Type* type_ = nullptr;
diff --git a/src/tint/ir/temp_test.cc b/src/tint/ir/temp_test.cc
index ddb0124..1a33769 100644
--- a/src/tint/ir/temp_test.cc
+++ b/src/tint/ir/temp_test.cc
@@ -16,6 +16,7 @@
#include "src/tint/ir/temp.h"
#include "src/tint/ir/test_helper.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::ir {
namespace {
@@ -27,7 +28,7 @@
TEST_F(IR_TempTest, id) {
auto& b = CreateEmptyBuilder();
- std::stringstream str;
+ utils::StringStream str;
b.builder.next_temp_id = Temp::Id(4);
auto* val = b.builder.Temp(b.builder.ir.types.Get<type::I32>());
diff --git a/src/tint/ir/value.h b/src/tint/ir/value.h
index 1f9619f..983eae0 100644
--- a/src/tint/ir/value.h
+++ b/src/tint/ir/value.h
@@ -20,6 +20,7 @@
#include "src/tint/castable.h"
#include "src/tint/symbol_table.h"
#include "src/tint/type/type.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/unique_vector.h"
// Forward declarations
@@ -56,7 +57,8 @@
/// @param out the stream to write to
/// @param st the symbol table
/// @returns the stream
- virtual std::ostream& ToString(std::ostream& out, const SymbolTable& st) const = 0;
+ virtual utils::StringStream& ToString(utils::StringStream& out,
+ const SymbolTable& st) const = 0;
protected:
/// Constructor
diff --git a/src/tint/number_test.cc b/src/tint/number_test.cc
index fe03663..7ae5e37 100644
--- a/src/tint/number_test.cc
+++ b/src/tint/number_test.cc
@@ -19,6 +19,7 @@
#include "src/tint/program_builder.h"
#include "src/tint/utils/compiler_macros.h"
+#include "src/tint/utils/string_stream.h"
#include "gtest/gtest.h"
@@ -254,7 +255,7 @@
float input_value = GetParam().input_value;
float quantized_value = GetParam().quantized_value;
- std::stringstream ss;
+ utils::StringStream ss;
ss << "input value = " << input_value << ", expected quantized value = " << quantized_value;
SCOPED_TRACE(ss.str());
@@ -269,7 +270,7 @@
float input_value = GetParam().input_value;
uint16_t representation = GetParam().f16_bit_pattern;
- std::stringstream ss;
+ utils::StringStream ss;
ss << "input value = " << input_value
<< ", expected binary16 bits representation = " << std::hex << std::showbase
<< representation;
@@ -282,7 +283,7 @@
float input_value = GetParam().quantized_value;
uint16_t representation = GetParam().f16_bit_pattern;
- std::stringstream ss;
+ utils::StringStream ss;
ss << "binary16 bits representation = " << std::hex << std::showbase << representation
<< " expected value = " << input_value;
SCOPED_TRACE(ss.str());
diff --git a/src/tint/reader/spirv/construct.h b/src/tint/reader/spirv/construct.h
index cd0804a..06ae450 100644
--- a/src/tint/reader/spirv/construct.h
+++ b/src/tint/reader/spirv/construct.h
@@ -19,6 +19,7 @@
#include <sstream>
#include <string>
+#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/vector.h"
namespace tint::reader::spirv {
@@ -173,7 +174,7 @@
/// @returns a short summary string
inline std::string ToStringBrief(const Construct* c) {
if (c) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << ToString(c->kind) << "@" << c->begin_id;
return ss.str();
}
@@ -184,7 +185,7 @@
/// @param o the stream
/// @param c the structured construct
/// @returns the stream
-inline std::ostream& operator<<(std::ostream& o, const Construct& c) {
+inline utils::StringStream& operator<<(utils::StringStream& o, const Construct& c) {
o << "Construct{ " << ToString(c.kind) << " [" << c.begin_pos << "," << c.end_pos << ")"
<< " begin_id:" << c.begin_id << " end_id:" << c.end_id << " depth:" << c.depth;
@@ -215,7 +216,8 @@
/// @param o the stream
/// @param c the structured construct
/// @returns the stream
-inline std::ostream& operator<<(std::ostream& o, const std::unique_ptr<Construct>& c) {
+inline utils::StringStream& operator<<(utils::StringStream& o,
+ const std::unique_ptr<Construct>& c) {
return o << *(c.get());
}
@@ -223,7 +225,7 @@
/// @param c the construct
/// @returns the string representation
inline std::string ToString(const Construct& c) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << c;
return ss.str();
}
@@ -246,7 +248,7 @@
/// @param o the stream
/// @param cl the construct list
/// @returns the stream
-inline std::ostream& operator<<(std::ostream& o, const ConstructList& cl) {
+inline utils::StringStream& operator<<(utils::StringStream& o, const ConstructList& cl) {
o << "ConstructList{\n";
for (const auto& c : cl) {
o << " " << c << "\n";
@@ -259,7 +261,7 @@
/// @param cl the construct list
/// @returns the string representation
inline std::string ToString(const ConstructList& cl) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << cl;
return ss.str();
}
diff --git a/src/tint/reader/spirv/enum_converter_test.cc b/src/tint/reader/spirv/enum_converter_test.cc
index 407b121..854504d 100644
--- a/src/tint/reader/spirv/enum_converter_test.cc
+++ b/src/tint/reader/spirv/enum_converter_test.cc
@@ -18,6 +18,7 @@
#include "gmock/gmock.h"
#include "src/tint/type/texture_dimension.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -45,7 +46,7 @@
protected:
bool success_ = true;
- std::stringstream errors_;
+ utils::StringStream errors_;
FailStream fail_stream_;
EnumConverter converter_;
};
@@ -103,7 +104,7 @@
protected:
bool success_ = true;
- std::stringstream errors_;
+ utils::StringStream errors_;
FailStream fail_stream_;
EnumConverter converter_;
};
@@ -164,7 +165,7 @@
protected:
bool success_ = true;
- std::stringstream errors_;
+ utils::StringStream errors_;
FailStream fail_stream_;
EnumConverter converter_;
};
@@ -239,7 +240,7 @@
protected:
bool success_ = true;
- std::stringstream errors_;
+ utils::StringStream errors_;
FailStream fail_stream_;
EnumConverter converter_;
};
@@ -311,7 +312,7 @@
protected:
bool success_ = true;
- std::stringstream errors_;
+ utils::StringStream errors_;
FailStream fail_stream_;
EnumConverter converter_;
};
diff --git a/src/tint/reader/spirv/fail_stream.h b/src/tint/reader/spirv/fail_stream.h
index 382fe5f..6530eae 100644
--- a/src/tint/reader/spirv/fail_stream.h
+++ b/src/tint/reader/spirv/fail_stream.h
@@ -15,7 +15,7 @@
#ifndef SRC_TINT_READER_SPIRV_FAIL_STREAM_H_
#define SRC_TINT_READER_SPIRV_FAIL_STREAM_H_
-#include <ostream>
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
@@ -29,7 +29,7 @@
/// to be a valid pointer to bool.
/// @param out output stream where a message should be written to explain
/// the failure
- FailStream(bool* status_ptr, std::ostream* out) : status_ptr_(status_ptr), out_(out) {}
+ FailStream(bool* status_ptr, utils::StringStream* out) : status_ptr_(status_ptr), out_(out) {}
/// Copy constructor
/// @param other the fail stream to clone
FailStream(const FailStream& other) = default;
@@ -61,7 +61,7 @@
private:
bool* status_ptr_;
- std::ostream* out_;
+ utils::StringStream* out_;
};
} // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/fail_stream_test.cc b/src/tint/reader/spirv/fail_stream_test.cc
index 5b8701d..02eb822 100644
--- a/src/tint/reader/spirv/fail_stream_test.cc
+++ b/src/tint/reader/spirv/fail_stream_test.cc
@@ -15,6 +15,7 @@
#include "src/tint/reader/spirv/fail_stream.h"
#include "gmock/gmock.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -56,7 +57,7 @@
TEST_F(FailStreamTest, ShiftOperatorAccumulatesValues) {
bool flag = true;
- std::stringstream ss;
+ utils::StringStream ss;
FailStream fs(&flag, &ss);
ss << "prefix ";
diff --git a/src/tint/reader/spirv/function_arithmetic_test.cc b/src/tint/reader/spirv/function_arithmetic_test.cc
index 0597916..8f29a91 100644
--- a/src/tint/reader/spirv/function_arithmetic_test.cc
+++ b/src/tint/reader/spirv/function_arithmetic_test.cc
@@ -16,6 +16,7 @@
#include "src/tint/reader/spirv/function.h"
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
#include "src/tint/reader/spirv/spirv_tools_helpers_test.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -307,7 +308,7 @@
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "let x_1 : " << GetParam().ast_type << " = (" << GetParam().ast_lhs << " "
<< GetParam().ast_op << " " << GetParam().ast_rhs << ");";
auto ast_body = fe.ast_body();
@@ -346,7 +347,7 @@
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "let x_1 : " << GetParam().wgsl_type << " = " << GetParam().expected << ";";
auto ast_body = fe.ast_body();
auto got = test::ToString(p->program(), ast_body);
diff --git a/src/tint/reader/spirv/function_bit_test.cc b/src/tint/reader/spirv/function_bit_test.cc
index a8e97b3..40f9162 100644
--- a/src/tint/reader/spirv/function_bit_test.cc
+++ b/src/tint/reader/spirv/function_bit_test.cc
@@ -15,6 +15,7 @@
#include "src/tint/reader/spirv/function.h"
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
#include "src/tint/reader/spirv/spirv_tools_helpers_test.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -125,7 +126,7 @@
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "let x_1 : " << GetParam().ast_type << " = (" << GetParam().ast_lhs << " "
<< GetParam().ast_op << " " << GetParam().ast_rhs << ");";
auto ast_body = fe.ast_body();
@@ -163,7 +164,7 @@
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error() << assembly;
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "let x_1 : " << GetParam().wgsl_type << " = " << GetParam().expected << ";\nreturn;\n";
auto ast_body = fe.ast_body();
auto got = test::ToString(p->program(), ast_body);
diff --git a/src/tint/reader/spirv/function_cfg_test.cc b/src/tint/reader/spirv/function_cfg_test.cc
index c5800fb..f4f1ce5 100644
--- a/src/tint/reader/spirv/function_cfg_test.cc
+++ b/src/tint/reader/spirv/function_cfg_test.cc
@@ -16,6 +16,7 @@
#include "src/tint/reader/spirv/function.h"
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
#include "src/tint/reader/spirv/spirv_tools_helpers_test.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -27,7 +28,7 @@
using SpvParserCFGTest = SpvParserTest;
std::string Dump(const std::vector<uint32_t>& v) {
- std::ostringstream o;
+ utils::StringStream o;
o << "{";
for (auto a : v) {
o << a << " ";
diff --git a/src/tint/reader/spirv/function_decl_test.cc b/src/tint/reader/spirv/function_decl_test.cc
index 0c4834b..0eceba2 100644
--- a/src/tint/reader/spirv/function_decl_test.cc
+++ b/src/tint/reader/spirv/function_decl_test.cc
@@ -16,6 +16,7 @@
#include "src/tint/reader/spirv/function.h"
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
#include "src/tint/reader/spirv/spirv_tools_helpers_test.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -34,7 +35,7 @@
/// @returns a SPIR-V assembly segment which assigns debug names
/// to particular IDs.
std::string Names(std::vector<std::string> ids) {
- std::ostringstream outs;
+ utils::StringStream outs;
for (auto& id : ids) {
outs << " OpName %" << id << " \"" << id << "\"\n";
}
diff --git a/src/tint/reader/spirv/function_logical_test.cc b/src/tint/reader/spirv/function_logical_test.cc
index 474af2e..a9ccf7d 100644
--- a/src/tint/reader/spirv/function_logical_test.cc
+++ b/src/tint/reader/spirv/function_logical_test.cc
@@ -16,6 +16,7 @@
#include "src/tint/reader/spirv/function.h"
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
#include "src/tint/reader/spirv/spirv_tools_helpers_test.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -188,7 +189,7 @@
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "let x_1 : " << GetParam().ast_type << " = (" << GetParam().ast_lhs << " "
<< GetParam().ast_op << " " << GetParam().ast_rhs << ");";
auto ast_body = fe.ast_body();
diff --git a/src/tint/reader/spirv/function_var_test.cc b/src/tint/reader/spirv/function_var_test.cc
index 1119667..681572b 100644
--- a/src/tint/reader/spirv/function_var_test.cc
+++ b/src/tint/reader/spirv/function_var_test.cc
@@ -16,6 +16,7 @@
#include "src/tint/reader/spirv/function.h"
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
#include "src/tint/reader/spirv/spirv_tools_helpers_test.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -26,7 +27,7 @@
/// @returns a SPIR-V assembly segment which assigns debug names
/// to particular IDs.
std::string Names(std::vector<std::string> ids) {
- std::ostringstream outs;
+ utils::StringStream outs;
for (auto& id : ids) {
outs << " OpName %" << id << " \"" << id << "\"\n";
}
diff --git a/src/tint/reader/spirv/namer.cc b/src/tint/reader/spirv/namer.cc
index 3e1f880..378e133 100644
--- a/src/tint/reader/spirv/namer.cc
+++ b/src/tint/reader/spirv/namer.cc
@@ -19,6 +19,7 @@
#include <unordered_set>
#include "src/tint/debug.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
@@ -219,7 +220,7 @@
std::string derived_name;
uint32_t& i = next_unusued_derived_name_id_[base_name];
while (i != 0xffffffff) {
- std::stringstream new_name_stream;
+ utils::StringStream new_name_stream;
new_name_stream << base_name;
if (i > 0) {
new_name_stream << "_" << i;
@@ -305,7 +306,7 @@
uint32_t i = 1;
std::string new_name;
do {
- std::stringstream new_name_stream;
+ utils::StringStream new_name_stream;
new_name_stream << suggestion << "_" << i;
new_name = new_name_stream.str();
++i;
@@ -331,7 +332,7 @@
uint32_t index = 0;
for (auto& name : name_vector) {
if (name.empty()) {
- std::stringstream suggestion;
+ utils::StringStream suggestion;
suggestion << "field" << index;
// Again, modify the name-vector in-place.
name = disambiguate_name(suggestion.str());
diff --git a/src/tint/reader/spirv/namer_test.cc b/src/tint/reader/spirv/namer_test.cc
index a24e03c..65a19bf 100644
--- a/src/tint/reader/spirv/namer_test.cc
+++ b/src/tint/reader/spirv/namer_test.cc
@@ -15,6 +15,7 @@
#include "src/tint/reader/spirv/namer.h"
#include "gmock/gmock.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -29,7 +30,7 @@
std::string error() { return errors_.str(); }
protected:
- std::stringstream errors_;
+ utils::StringStream errors_;
bool success_ = true;
FailStream fail_stream_;
};
@@ -351,7 +352,7 @@
TEST_P(SpvNamerReservedWordTest, ReservedWordsAreUsed) {
bool success;
- std::stringstream errors;
+ utils::StringStream errors;
FailStream fail_stream(&success, &errors);
Namer namer(fail_stream);
const std::string reserved = GetParam();
diff --git a/src/tint/reader/spirv/parser_impl.h b/src/tint/reader/spirv/parser_impl.h
index 36c24de..141df61 100644
--- a/src/tint/reader/spirv/parser_impl.h
+++ b/src/tint/reader/spirv/parser_impl.h
@@ -24,6 +24,7 @@
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/hashmap.h"
+#include "src/tint/utils/string_stream.h"
TINT_BEGIN_DISABLE_WARNING(NEWLINE_EOF);
TINT_BEGIN_DISABLE_WARNING(OLD_STYLE_CAST);
@@ -819,7 +820,7 @@
// Is the parse successful?
bool success_ = true;
// Collector for diagnostic messages.
- std::stringstream errors_;
+ utils::StringStream errors_;
FailStream fail_stream_;
spvtools::MessageConsumer message_consumer_;
diff --git a/src/tint/reader/spirv/parser_impl_function_decl_test.cc b/src/tint/reader/spirv/parser_impl_function_decl_test.cc
index 459460d..1c29649 100644
--- a/src/tint/reader/spirv/parser_impl_function_decl_test.cc
+++ b/src/tint/reader/spirv/parser_impl_function_decl_test.cc
@@ -15,6 +15,7 @@
#include "gmock/gmock.h"
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
#include "src/tint/reader/spirv/spirv_tools_helpers_test.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -47,7 +48,7 @@
/// @returns a SPIR-V assembly segment which assigns debug names
/// to particular IDs.
std::string Names(std::vector<std::string> ids) {
- std::ostringstream outs;
+ utils::StringStream outs;
for (auto& id : ids) {
outs << " OpName %" << id << " \"" << id << "\"\n";
}
diff --git a/src/tint/reader/spirv/parser_impl_handle_test.cc b/src/tint/reader/spirv/parser_impl_handle_test.cc
index 2413386..17e6ed6 100644
--- a/src/tint/reader/spirv/parser_impl_handle_test.cc
+++ b/src/tint/reader/spirv/parser_impl_handle_test.cc
@@ -18,6 +18,7 @@
#include "src/tint/reader/spirv/function.h"
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
#include "src/tint/reader/spirv/spirv_tools_helpers_test.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -235,7 +236,7 @@
}
std::string Bindings(std::vector<uint32_t> ids) {
- std::ostringstream os;
+ utils::StringStream os;
int binding = 0;
for (auto id : ids) {
os << " OpDecorate %" << id << " DescriptorSet 0\n"
diff --git a/src/tint/reader/spirv/parser_impl_test_helper.cc b/src/tint/reader/spirv/parser_impl_test_helper.cc
index d0b6ef7..754922c 100644
--- a/src/tint/reader/spirv/parser_impl_test_helper.cc
+++ b/src/tint/reader/spirv/parser_impl_test_helper.cc
@@ -13,6 +13,7 @@
// limitations under the License.
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/generator_impl.h"
namespace tint::reader::spirv::test {
@@ -54,7 +55,7 @@
return Switch(
node,
[&](const ast::Expression* expr) {
- std::stringstream out;
+ utils::StringStream out;
if (!writer.EmitExpression(out, expr)) {
return "WGSL writer error: " + writer.error();
}
diff --git a/src/tint/reader/spirv/parser_type.cc b/src/tint/reader/spirv/parser_type.cc
index 0d4c58a..71482ff 100644
--- a/src/tint/reader/spirv/parser_type.cc
+++ b/src/tint/reader/spirv/parser_type.cc
@@ -23,6 +23,7 @@
#include "src/tint/utils/hash.h"
#include "src/tint/utils/map.h"
#include "src/tint/utils/string.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/unique_allocator.h"
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Type);
@@ -557,31 +558,31 @@
}
std::string Pointer::String() const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "ptr<" << utils::ToString(address_space) << ", " << type->String() + ">";
return ss.str();
}
std::string Reference::String() const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "ref<" + utils::ToString(address_space) << ", " << type->String() << ">";
return ss.str();
}
std::string Vector::String() const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "vec" << size << "<" << type->String() << ">";
return ss.str();
}
std::string Matrix::String() const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "mat" << columns << "x" << rows << "<" << type->String() << ">";
return ss.str();
}
std::string Array::String() const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "array<" << type->String() << ", " << size << ", " << stride << ">";
return ss.str();
}
@@ -597,31 +598,31 @@
}
std::string DepthTexture::String() const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "depth_" << dims;
return ss.str();
}
std::string DepthMultisampledTexture::String() const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "depth_multisampled_" << dims;
return ss.str();
}
std::string MultisampledTexture::String() const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "texture_multisampled_" << dims << "<" << type << ">";
return ss.str();
}
std::string SampledTexture::String() const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "texture_" << dims << "<" << type << ">";
return ss.str();
}
std::string StorageTexture::String() const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "texture_storage_" << dims << "<" << format << ", " << access << ">";
return ss.str();
}
diff --git a/src/tint/reader/spirv/spirv_tools_helpers_test.cc b/src/tint/reader/spirv/spirv_tools_helpers_test.cc
index 21a5be2..ff3db87 100644
--- a/src/tint/reader/spirv/spirv_tools_helpers_test.cc
+++ b/src/tint/reader/spirv/spirv_tools_helpers_test.cc
@@ -16,6 +16,7 @@
#include "gtest/gtest.h"
#include "spirv-tools/libspirv.hpp"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv::test {
@@ -24,7 +25,7 @@
// (The target environment doesn't affect assembly.
spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
- std::stringstream errors;
+ utils::StringStream errors;
std::vector<uint32_t> result;
tools.SetMessageConsumer([&errors](spv_message_level_t, const char*,
const spv_position_t& position, const char* message) {
@@ -40,7 +41,7 @@
std::string Disassemble(const std::vector<uint32_t>& spirv_module) {
spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
- std::stringstream errors;
+ utils::StringStream errors;
tools.SetMessageConsumer([&errors](spv_message_level_t, const char*,
const spv_position_t& position, const char* message) {
errors << "disassmbly error:" << position.line << ":" << position.column << ": " << message;
diff --git a/src/tint/reader/spirv/usage.cc b/src/tint/reader/spirv/usage.cc
index c120b2c..5256d4f 100644
--- a/src/tint/reader/spirv/usage.cc
+++ b/src/tint/reader/spirv/usage.cc
@@ -16,6 +16,8 @@
#include <sstream>
+#include "src/tint/utils/string_stream.h"
+
namespace tint::reader::spirv {
Usage::Usage() {}
@@ -179,7 +181,7 @@
}
std::string Usage::to_str() const {
- std::ostringstream ss;
+ utils::StringStream ss;
ss << *this;
return ss.str();
}
diff --git a/src/tint/reader/spirv/usage_test.cc b/src/tint/reader/spirv/usage_test.cc
index bb64bb3..eb5eb5d 100644
--- a/src/tint/reader/spirv/usage_test.cc
+++ b/src/tint/reader/spirv/usage_test.cc
@@ -17,6 +17,7 @@
#include "gmock/gmock.h"
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::spirv {
namespace {
@@ -38,7 +39,7 @@
}
TEST_F(SpvParserTest, Usage_Trivial_Output) {
- std::ostringstream ss;
+ utils::StringStream ss;
Usage u;
ss << u;
EXPECT_THAT(ss.str(), Eq("Usage()"));
@@ -89,13 +90,13 @@
EXPECT_TRUE(a.IsStorageReadTexture());
EXPECT_FALSE(a.IsStorageWriteTexture());
- std::ostringstream ss;
+ utils::StringStream ss;
ss << a;
EXPECT_THAT(ss.str(), Eq("Usage(Sampler( comparison )Texture( read ))"));
}
TEST_F(SpvParserTest, Usage_AddSampler) {
- std::ostringstream ss;
+ utils::StringStream ss;
Usage u;
u.AddSampler();
@@ -120,7 +121,7 @@
}
TEST_F(SpvParserTest, Usage_AddComparisonSampler) {
- std::ostringstream ss;
+ utils::StringStream ss;
Usage u;
u.AddComparisonSampler();
@@ -144,7 +145,7 @@
}
TEST_F(SpvParserTest, Usage_AddTexture) {
- std::ostringstream ss;
+ utils::StringStream ss;
Usage u;
u.AddTexture();
@@ -168,7 +169,7 @@
}
TEST_F(SpvParserTest, Usage_AddSampledTexture) {
- std::ostringstream ss;
+ utils::StringStream ss;
Usage u;
u.AddSampledTexture();
@@ -192,7 +193,7 @@
}
TEST_F(SpvParserTest, Usage_AddMultisampledTexture) {
- std::ostringstream ss;
+ utils::StringStream ss;
Usage u;
u.AddMultisampledTexture();
@@ -216,7 +217,7 @@
}
TEST_F(SpvParserTest, Usage_AddDepthTexture) {
- std::ostringstream ss;
+ utils::StringStream ss;
Usage u;
u.AddDepthTexture();
@@ -240,7 +241,7 @@
}
TEST_F(SpvParserTest, Usage_AddStorageReadTexture) {
- std::ostringstream ss;
+ utils::StringStream ss;
Usage u;
u.AddStorageReadTexture();
@@ -264,7 +265,7 @@
}
TEST_F(SpvParserTest, Usage_AddStorageWriteTexture) {
- std::ostringstream ss;
+ utils::StringStream ss;
Usage u;
u.AddStorageWriteTexture();
diff --git a/src/tint/reader/wgsl/classify_template_args_test.cc b/src/tint/reader/wgsl/classify_template_args_test.cc
index 9cf2c8f..e2833ee 100644
--- a/src/tint/reader/wgsl/classify_template_args_test.cc
+++ b/src/tint/reader/wgsl/classify_template_args_test.cc
@@ -479,5 +479,198 @@
},
}));
+INSTANTIATE_TEST_SUITE_P(TreesitterScannerSeparatingCases,
+ ClassifyTemplateArgsTest,
+ testing::ValuesIn(std::vector<Case>{
+ // Treesitter had trouble missing '=' in its lookahead
+ {
+ "a<b>=c",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kIdentifier, // b
+ T::kTemplateArgsRight, // >
+ T::kEqual, // =
+ T::kIdentifier, // c
+ T::kEOF,
+ },
+ },
+ {
+ "a<b>>=c",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kIdentifier, // b
+ T::kTemplateArgsRight, // >
+ T::kGreaterThanEqual, // >=
+ T::kPlaceholder, // <placeholder>
+ T::kIdentifier, // c
+ T::kEOF,
+ },
+ },
+ {
+ "a<b==c>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kIdentifier, // b
+ T::kEqualEqual, // ==
+ T::kIdentifier, // c
+ T::kTemplateArgsRight, // >
+ T::kEOF,
+ },
+ },
+ {
+ "a<(b==c)>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kParenLeft, // (
+ T::kIdentifier, // b
+ T::kEqualEqual, // ==
+ T::kIdentifier, // c
+ T::kParenRight, // )
+ T::kTemplateArgsRight, // >
+ T::kEOF,
+ },
+ },
+ {
+ "a<b<=c>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kIdentifier, // b
+ T::kLessThanEqual, // <=
+ T::kIdentifier, // c
+ T::kTemplateArgsRight, // >
+ T::kEOF,
+ },
+ },
+ {
+ "a<(b<=c)>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kParenLeft, // (
+ T::kIdentifier, // b
+ T::kLessThanEqual, // <=
+ T::kIdentifier, // c
+ T::kParenRight, // )
+ T::kTemplateArgsRight, // >
+ T::kEOF,
+ },
+ },
+ {
+ "a<b>=c>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kIdentifier, // b
+ T::kTemplateArgsRight, // >
+ T::kEqual, // =
+ T::kIdentifier, // c
+ T::kGreaterThan, // >
+ T::kEOF,
+ },
+ },
+ {
+ "a<(b<=c)>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kParenLeft, // (
+ T::kIdentifier, // b
+ T::kLessThanEqual, // <=
+ T::kIdentifier, // c
+ T::kParenRight, // )
+ T::kTemplateArgsRight, // >
+ T::kEOF,
+ },
+ },
+ {
+ "a<b>>c>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kIdentifier, // b
+ T::kTemplateArgsRight, // >
+ T::kGreaterThan, // >
+ T::kIdentifier, // c
+ T::kGreaterThan, // >
+ T::kEOF,
+ },
+ },
+ {
+ "a<b<<c>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kIdentifier, // b
+ T::kShiftLeft, // <<
+ T::kIdentifier, // c
+ T::kTemplateArgsRight, // >
+ T::kEOF,
+ },
+ },
+ {
+ "a<(b<<c)>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kParenLeft, // (
+ T::kIdentifier, // b
+ T::kShiftLeft, // <<
+ T::kIdentifier, // c
+ T::kParenRight, // )
+ T::kTemplateArgsRight, // >
+ T::kEOF,
+ },
+ },
+ {
+ "a<(b>>c)>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kParenLeft, // (
+ T::kIdentifier, // b
+ T::kShiftRight, // >>
+ T::kPlaceholder, // <placeholder>
+ T::kIdentifier, // c
+ T::kParenRight, // )
+ T::kTemplateArgsRight, // >
+ T::kEOF,
+ },
+ },
+ {
+ "a<1<<c>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kIntLiteral, // 1
+ T::kShiftLeft, // <<
+ T::kIdentifier, // c
+ T::kTemplateArgsRight, // >
+ T::kEOF,
+ },
+ },
+ {
+ "a<1<<c<d>()>",
+ {
+ T::kIdentifier, // a
+ T::kTemplateArgsLeft, // <
+ T::kIntLiteral, // 1
+ T::kShiftLeft, // <<
+ T::kIdentifier, // c
+ T::kTemplateArgsLeft, // <
+ T::kIdentifier, // d
+ T::kTemplateArgsRight, // >
+ T::kParenLeft, // (
+ T::kParenRight, // )
+ T::kTemplateArgsRight, // >
+ T::kEOF,
+ },
+ },
+ }));
+
} // namespace
} // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index 53d29f1..e4eab29 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -44,6 +44,7 @@
#include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/reverse.h"
#include "src/tint/utils/string.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::reader::wgsl {
namespace {
@@ -213,7 +214,7 @@
ParserImpl::Failure::Errored ParserImpl::add_error(const Source& source,
std::string_view err,
std::string_view use) {
- std::stringstream msg;
+ utils::StringStream msg;
msg << err;
if (!use.empty()) {
msg << " for " << use;
@@ -911,7 +912,7 @@
}
/// Create a sensible error message
- std::ostringstream err;
+ utils::StringStream err;
err << "expected " << name;
if (!use.empty()) {
@@ -3164,7 +3165,7 @@
return false;
}
- std::stringstream err;
+ utils::StringStream err;
if (tok == Token::Type::kTemplateArgsLeft && t.type() == Token::Type::kLessThan) {
err << "missing closing '>'";
} else {
diff --git a/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc b/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc
index fea7c2d..7ad39c2 100644
--- a/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc
@@ -62,7 +62,7 @@
// Error when unknown extension found
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
+Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'chromium_internal_relaxed_uniform_layout', 'f16')");
auto program = p->program();
auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u);
@@ -76,7 +76,7 @@
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension
Did you mean 'f16'?
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
+Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'chromium_internal_relaxed_uniform_layout', 'f16')");
auto program = p->program();
auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u);
@@ -124,7 +124,7 @@
p->translation_unit();
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
+Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'chromium_internal_relaxed_uniform_layout', 'f16')");
auto program = p->program();
auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u);
@@ -135,7 +135,7 @@
p->translation_unit();
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
+Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'chromium_internal_relaxed_uniform_layout', 'f16')");
auto program = p->program();
auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u);
@@ -147,7 +147,7 @@
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension
Did you mean 'f16'?
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
+Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'chromium_internal_relaxed_uniform_layout', 'f16')");
auto program = p->program();
auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u);
diff --git a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
index 85e55cb..af50894 100644
--- a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
@@ -14,6 +14,8 @@
#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+#include "src/tint/utils/string_stream.h"
+
namespace tint::reader::wgsl {
namespace {
@@ -513,8 +515,8 @@
TEST_F(ParserImplErrorTest, GlobalDeclConstExprMaxDepth) {
uint32_t kMaxDepth = 128;
- std::stringstream src;
- std::stringstream mkr;
+ utils::StringStream src;
+ utils::StringStream mkr;
src << "const i : i32 = ";
mkr << " ";
for (size_t i = 0; i < kMaxDepth + 8; i++) {
@@ -530,7 +532,7 @@
src << ")";
}
src << ";";
- std::stringstream err;
+ utils::StringStream err;
err << "test.wgsl:1:529 error: maximum parser recursive depth reached\n"
<< src.str() << "\n"
<< mkr.str() << "\n";
diff --git a/src/tint/reader/wgsl/parser_impl_expression_test.cc b/src/tint/reader/wgsl/parser_impl_expression_test.cc
index 0de3dea..9a6c917 100644
--- a/src/tint/reader/wgsl/parser_impl_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_expression_test.cc
@@ -14,6 +14,8 @@
#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+#include "src/tint/utils/string_stream.h"
+
namespace tint::reader::wgsl {
namespace {
@@ -486,7 +488,7 @@
using ParserImplMixedBinaryOpTest = ParserImplTestWithParam<Case>;
TEST_P(ParserImplMixedBinaryOpTest, Test) {
- std::stringstream wgsl;
+ utils::StringStream wgsl;
wgsl << GetParam();
auto p = parser(wgsl.str());
auto e = p->expression();
@@ -498,7 +500,7 @@
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
- std::stringstream expected;
+ utils::StringStream expected;
expected << "1:3: mixing '" << GetParam().lhs_op.symbol << "' and '"
<< GetParam().rhs_op.symbol << "' requires parenthesis";
EXPECT_EQ(p->error(), expected.str());
diff --git a/src/tint/resolver/address_space_layout_validation_test.cc b/src/tint/resolver/address_space_layout_validation_test.cc
index 79e2781..9a621e3 100644
--- a/src/tint/resolver/address_space_layout_validation_test.cc
+++ b/src/tint/resolver/address_space_layout_validation_test.cc
@@ -603,5 +603,150 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
+TEST_F(ResolverAddressSpaceLayoutValidationTest, RelaxedUniformLayout_StructMemberOffset_Struct) {
+ // enable chromium_internal_relaxed_uniform_layout;
+ //
+ // struct Inner {
+ // scalar : i32;
+ // };
+ //
+ // struct Outer {
+ // scalar : f32;
+ // inner : Inner;
+ // };
+ //
+ // @group(0) @binding(0)
+ // var<uniform> a : Outer;
+
+ Enable(builtin::Extension::kChromiumInternalRelaxedUniformLayout);
+
+ Structure(Source{{12, 34}}, "Inner",
+ utils::Vector{
+ Member("scalar", ty.i32()),
+ });
+
+ Structure(Source{{34, 56}}, "Outer",
+ utils::Vector{
+ Member("scalar", ty.f32()),
+ Member(Source{{56, 78}}, "inner", ty("Inner")),
+ });
+
+ GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
+ Binding(0_a));
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverAddressSpaceLayoutValidationTest, RelaxedUniformLayout_StructMemberOffset_Array) {
+ // enable chromium_internal_relaxed_uniform_layout;
+ //
+ // type Inner = @stride(16) array<f32, 10u>;
+ //
+ // struct Outer {
+ // scalar : f32;
+ // inner : Inner;
+ // };
+ //
+ // @group(0) @binding(0)
+ // var<uniform> a : Outer;
+
+ Enable(builtin::Extension::kChromiumInternalRelaxedUniformLayout);
+
+ Alias("Inner", ty.array<f32, 10>(utils::Vector{Stride(16)}));
+
+ Structure(Source{{12, 34}}, "Outer",
+ utils::Vector{
+ Member("scalar", ty.f32()),
+ Member(Source{{56, 78}}, "inner", ty("Inner")),
+ });
+
+ GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
+ Binding(0_a));
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverAddressSpaceLayoutValidationTest, RelaxedUniformLayout_MemberOffsetNotMutipleOf16) {
+ // enable chromium_internal_relaxed_uniform_layout;
+ //
+ // struct Inner {
+ // @align(1) @size(5) scalar : i32;
+ // };
+ //
+ // struct Outer {
+ // inner : Inner;
+ // scalar : i32;
+ // };
+ //
+ // @group(0) @binding(0)
+ // var<uniform> a : Outer;
+
+ Enable(builtin::Extension::kChromiumInternalRelaxedUniformLayout);
+
+ Structure(Source{{12, 34}}, "Inner",
+ utils::Vector{
+ Member("scalar", ty.i32(), utils::Vector{MemberAlign(1_i), MemberSize(5_a)}),
+ });
+
+ Structure(Source{{34, 56}}, "Outer",
+ utils::Vector{
+ Member(Source{{56, 78}}, "inner", ty("Inner")),
+ Member(Source{{78, 90}}, "scalar", ty.i32()),
+ });
+
+ GlobalVar(Source{{22, 24}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
+ Binding(0_a));
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverAddressSpaceLayoutValidationTest, RelaxedUniformLayout_ArrayStride_Scalar) {
+ // enable chromium_internal_relaxed_uniform_layout;
+ //
+ // struct Outer {
+ // arr : array<f32, 10u>;
+ // };
+ //
+ // @group(0) @binding(0)
+ // var<uniform> a : Outer;
+
+ Enable(builtin::Extension::kChromiumInternalRelaxedUniformLayout);
+
+ Structure(Source{{12, 34}}, "Outer",
+ utils::Vector{
+ Member("arr", ty.array<f32, 10>()),
+ });
+
+ GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
+ Binding(0_a));
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverAddressSpaceLayoutValidationTest, RelaxedUniformLayout_ArrayStride_Vech) {
+ // enable f16;
+ // enable chromium_internal_relaxed_uniform_layout;
+ //
+ // struct Outer {
+ // arr : array<vec3<f16>, 10u>;
+ // };
+ //
+ // @group(0) @binding(0)
+ // var<uniform> a : Outer;
+
+ Enable(builtin::Extension::kF16);
+ Enable(builtin::Extension::kChromiumInternalRelaxedUniformLayout);
+
+ Structure(Source{{12, 34}}, "Outer",
+ utils::Vector{
+ Member("arr", ty.array(ty.vec3<f16>(), 10_u)),
+ });
+
+ GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
+ Binding(0_a));
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
} // namespace
} // namespace tint::resolver
diff --git a/src/tint/resolver/alias_analysis_test.cc b/src/tint/resolver/alias_analysis_test.cc
index fa70a7f..895ed88 100644
--- a/src/tint/resolver/alias_analysis_test.cc
+++ b/src/tint/resolver/alias_analysis_test.cc
@@ -14,6 +14,7 @@
#include "src/tint/resolver/resolver.h"
#include "src/tint/resolver/resolver_test_helper.h"
+#include "src/tint/utils/string_stream.h"
#include "gmock/gmock.h"
@@ -196,7 +197,7 @@
TwoPointerConfig{builtin::AddressSpace::kPrivate, false},
TwoPointerConfig{builtin::AddressSpace::kPrivate, true}),
[](const ::testing::TestParamInfo<TwoPointers::ParamType>& p) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << (p.param.aliased ? "Aliased" : "Unaliased") << "_"
<< p.param.address_space;
return ss.str();
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index 43e9929..b0a863d 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -18,6 +18,7 @@
#include "src/tint/resolver/resolver_test_helper.h"
#include "src/tint/transform/add_block_attribute.h"
#include "src/tint/type/texture_dimension.h"
+#include "src/tint/utils/string_stream.h"
#include "gmock/gmock.h"
@@ -1164,7 +1165,7 @@
auto& params = GetParam();
ast::Type el_ty = params.create_el_type(*this);
- std::stringstream ss;
+ utils::StringStream ss;
ss << "el_ty: " << FriendlyName(el_ty) << ", stride: " << params.stride
<< ", should_pass: " << params.should_pass;
SCOPED_TRACE(ss.str());
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index 6a9e5a3..0108e89 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -38,6 +38,7 @@
#include "src/tint/type/test_helper.h"
#include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/string.h"
+#include "src/tint/utils/string_stream.h"
using ::testing::ElementsAre;
using ::testing::HasSubstr;
@@ -2185,7 +2186,7 @@
static std::string to_str(const std::string& function,
utils::VectorRef<const sem::Parameter*> params) {
- std::stringstream out;
+ utils::StringStream out;
out << function << "(";
bool first = true;
for (auto* param : params) {
diff --git a/src/tint/resolver/builtin_validation_test.cc b/src/tint/resolver/builtin_validation_test.cc
index 967335d..d074703 100644
--- a/src/tint/resolver/builtin_validation_test.cc
+++ b/src/tint/resolver/builtin_validation_test.cc
@@ -17,6 +17,7 @@
#include "src/tint/ast/builtin_texture_helper_test.h"
#include "src/tint/resolver/resolver_test_helper.h"
#include "src/tint/sem/value_constructor.h"
+#include "src/tint/utils/string_stream.h"
using namespace tint::number_suffixes; // NOLINT
@@ -335,7 +336,7 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- std::stringstream err;
+ utils::StringStream err;
if (is_vector) {
err << "12:34 error: each component of the " << param.name
<< " argument must be at least " << param.min << " and at most " << param.max
@@ -392,7 +393,7 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- std::stringstream err;
+ utils::StringStream err;
if (is_vector) {
err << "12:34 error: each component of the " << param.name
<< " argument must be at least " << param.min << " and at most " << param.max
@@ -442,7 +443,7 @@
});
EXPECT_FALSE(r()->Resolve());
- std::stringstream err;
+ utils::StringStream err;
err << "12:34 error: the " << param.name << " argument must be a const-expression";
EXPECT_EQ(r()->error(), err.str());
}
diff --git a/src/tint/resolver/builtins_validation_test.cc b/src/tint/resolver/builtins_validation_test.cc
index 63e5abf..a985a1d 100644
--- a/src/tint/resolver/builtins_validation_test.cc
+++ b/src/tint/resolver/builtins_validation_test.cc
@@ -15,6 +15,7 @@
#include "src/tint/ast/call_statement.h"
#include "src/tint/builtin/builtin_value.h"
#include "src/tint/resolver/resolver_test_helper.h"
+#include "src/tint/utils/string_stream.h"
using namespace tint::number_suffixes; // NOLINT
@@ -145,7 +146,7 @@
if (params.is_valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
- std::stringstream err;
+ utils::StringStream err;
err << "12:34 error: @builtin(" << params.builtin << ")";
err << " cannot be used in input of " << params.stage << " pipeline stage";
EXPECT_FALSE(r()->Resolve());
diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc
index dc59ccd..325ccb0 100644
--- a/src/tint/resolver/const_eval.cc
+++ b/src/tint/resolver/const_eval.cc
@@ -44,6 +44,7 @@
#include "src/tint/utils/bitcast.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/map.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/transform.h"
using namespace tint::number_suffixes; // NOLINT
@@ -184,8 +185,7 @@
template <typename NumberT>
std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs) {
- std::stringstream ss;
- ss << std::setprecision(20);
+ utils::StringStream ss;
ss << "'" << lhs.value << " " << op << " " << rhs.value << "' cannot be represented as '"
<< FriendlyName<NumberT>() << "'";
return ss.str();
@@ -193,8 +193,7 @@
template <typename VALUE_TY>
std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) {
- std::stringstream ss;
- ss << std::setprecision(20);
+ utils::StringStream ss;
ss << "value " << value << " cannot be represented as "
<< "'" << target_ty << "'";
return ss.str();
@@ -202,8 +201,7 @@
template <typename NumberT>
std::string OverflowExpErrorMessage(std::string_view base, NumberT exp) {
- std::stringstream ss;
- ss << std::setprecision(20);
+ utils::StringStream ss;
ss << base << "^" << exp << " cannot be represented as "
<< "'" << FriendlyName<NumberT>() << "'";
return ss.str();
@@ -714,7 +712,7 @@
} else {
AddError(OverflowErrorMessage(a, "%", b), source);
if (use_runtime_semantics_) {
- return a;
+ return NumberT{0};
} else {
return utils::Failure;
}
@@ -727,7 +725,7 @@
// lhs % 0 is an error
AddError(OverflowErrorMessage(a, "%", b), source);
if (use_runtime_semantics_) {
- return a;
+ return NumberT{0};
} else {
return utils::Failure;
}
@@ -738,7 +736,7 @@
if (rhs == -1 && lhs == std::numeric_limits<T>::min()) {
AddError(OverflowErrorMessage(a, "%", b), source);
if (use_runtime_semantics_) {
- return a;
+ return NumberT{0};
} else {
return utils::Failure;
}
@@ -1229,23 +1227,18 @@
}
ConstEval::Result ConstEval::ArrayOrStructCtor(const type::Type* ty,
- utils::VectorRef<const sem::ValueExpression*> args) {
+ utils::VectorRef<const constant::Value*> args) {
if (args.IsEmpty()) {
return ZeroValue(ty);
}
if (args.Length() == 1 && args[0]->Type() == ty) {
// Identity constructor.
- return args[0]->ConstantValue();
+ return args[0];
}
// Multiple arguments. Must be a value constructor.
- utils::Vector<const constant::Value*, 4> els;
- els.Reserve(args.Length());
- for (auto* arg : args) {
- els.Push(arg->ConstantValue());
- }
- return builder.create<constant::Composite>(ty, std::move(els));
+ return builder.create<constant::Composite>(ty, std::move(args));
}
ConstEval::Result ConstEval::Conv(const type::Type* ty,
diff --git a/src/tint/resolver/const_eval.h b/src/tint/resolver/const_eval.h
index 969cfe7..9303656 100644
--- a/src/tint/resolver/const_eval.h
+++ b/src/tint/resolver/const_eval.h
@@ -77,11 +77,10 @@
// Constant value evaluation methods, to be called directly from Resolver
////////////////////////////////////////////////////////////////////////////////////////////////
- /// @param ty the target type - must be an array or initializer
+ /// @param ty the target type - must be an array or struct
/// @param args the input arguments
/// @return the constructed value, or null if the value cannot be calculated
- Result ArrayOrStructCtor(const type::Type* ty,
- utils::VectorRef<const sem::ValueExpression*> args);
+ Result ArrayOrStructCtor(const type::Type* ty, utils::VectorRef<const constant::Value*> args);
/// @param ty the target type
/// @param value the value being converted
diff --git a/src/tint/resolver/const_eval_binary_op_test.cc b/src/tint/resolver/const_eval_binary_op_test.cc
index e2dec19..ff50a24 100644
--- a/src/tint/resolver/const_eval_binary_op_test.cc
+++ b/src/tint/resolver/const_eval_binary_op_test.cc
@@ -1077,7 +1077,15 @@
GlobalConst("c", Add(Source{{1, 1}}, Expr(AFloat::Highest()), AFloat::Highest()));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "1:1 error: '1.7976931348623157081e+308 + 1.7976931348623157081e+308' cannot be "
+ "1:1 error: "
+ "'17976931348623157081452742373170435679807056752584499659891747680315726078002853876"
+ "058955863276687817154045895351438246423432132688946418276846754670353751698604991057"
+ "655128207624549009038932894407586850845513394230458323690322294816580855933212334827"
+ "4797826204144723168738177180919299881250404026184124858368.0 + "
+ "179769313486231570814527423731704356798070567525844996598917476803157260780028538760"
+ "589558632766878171540458953514382464234321326889464182768467546703537516986049910576"
+ "551282076245490090389328944075868508455133942304583236903222948165808559332123348274"
+ "797826204144723168738177180919299881250404026184124858368.0' cannot be "
"represented as 'abstract-float'");
}
@@ -1085,7 +1093,16 @@
GlobalConst("c", Add(Source{{1, 1}}, Expr(AFloat::Lowest()), AFloat::Lowest()));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "1:1 error: '-1.7976931348623157081e+308 + -1.7976931348623157081e+308' cannot be "
+ "1:1 error: "
+ "'-"
+ "179769313486231570814527423731704356798070567525844996598917476803157260780028538760"
+ "589558632766878171540458953514382464234321326889464182768467546703537516986049910576"
+ "551282076245490090389328944075868508455133942304583236903222948165808559332123348274"
+ "797826204144723168738177180919299881250404026184124858368.0 + "
+ "-17976931348623157081452742373170435679807056752584499659891747680315726078002853876"
+ "058955863276687817154045895351438246423432132688946418276846754670353751698604991057"
+ "655128207624549009038932894407586850845513394230458323690322294816580855933212334827"
+ "4797826204144723168738177180919299881250404026184124858368.0' cannot be "
"represented as 'abstract-float'");
}
@@ -1584,8 +1601,13 @@
GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: value 1.7976931348623157081e+308 cannot be represented as 'f32'");
+ EXPECT_EQ(
+ r()->error(),
+ "12:34 error: value "
+ "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558"
+ "632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245"
+ "490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168"
+ "738177180919299881250404026184124858368.000000000 cannot be represented as 'f32'");
}
TEST_F(ResolverConstEvalTest, ShortCircuit_And_Error_Materialize) {
@@ -1630,8 +1652,13 @@
GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "12:34 error: value 1.7976931348623157081e+308 cannot be represented as 'f32'");
+ EXPECT_EQ(
+ r()->error(),
+ "12:34 error: value "
+ "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558"
+ "632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245"
+ "490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168"
+ "738177180919299881250404026184124858368.000000000 cannot be represented as 'f32'");
}
TEST_F(ResolverConstEvalTest, ShortCircuit_Or_Error_Materialize) {
@@ -1981,6 +2008,42 @@
"expected 'f32', found 'bool'");
}
+TEST_F(ResolverConstEvalTest, ShortCircuit_And_Error_ArrayInit) {
+ // const one = 1;
+ // const result = (one == 0) && array(4) == 0;
+ GlobalConst("one", Expr(1_a));
+ auto* lhs = Equal("one", 0_a);
+ auto* rhs = Equal(Call("array", Expr(4_a)), 0_a);
+ GlobalConst("result", LogicalAnd(lhs, rhs));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(error: no matching overload for operator == (array<abstract-int, 1>, abstract-int)
+
+2 candidate operators:
+ operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+)");
+}
+
+TEST_F(ResolverConstEvalTest, ShortCircuit_Or_Error_ArrayInit) {
+ // const one = 1;
+ // const result = (one == 1) || array(4) == 0;
+ GlobalConst("one", Expr(1_a));
+ auto* lhs = Equal("one", 1_a);
+ auto* rhs = Equal(Call("array", Expr(4_a)), 0_a);
+ GlobalConst("result", LogicalOr(lhs, rhs));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ R"(error: no matching overload for operator == (array<abstract-int, 1>, abstract-int)
+
+2 candidate operators:
+ operator == (T, T) -> bool where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+ operator == (vecN<T>, vecN<T>) -> vecN<bool> where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool
+)");
+}
+
////////////////////////////////////////////////
// Short-Circuit Builtin Call
////////////////////////////////////////////////
diff --git a/src/tint/resolver/const_eval_builtin_test.cc b/src/tint/resolver/const_eval_builtin_test.cc
index 4e3cb5a..6f53af1 100644
--- a/src/tint/resolver/const_eval_builtin_test.cc
+++ b/src/tint/resolver/const_eval_builtin_test.cc
@@ -2025,9 +2025,11 @@
C({Vec(f32(10), f32(-10.5))}, Val(u32(0xc940'4900))),
E({Vec(f32(0), f32::Highest())},
- "12:34 error: value 3.4028234663852885981e+38 cannot be represented as 'f16'"),
+ "12:34 error: value 340282346638528859811704183484516925440.000000000 cannot be "
+ "represented as 'f16'"),
E({Vec(f32::Lowest(), f32(0))},
- "12:34 error: value -3.4028234663852885981e+38 cannot be represented as 'f16'"),
+ "12:34 error: value -340282346638528859811704183484516925440.000000000 cannot be "
+ "represented as 'f16'"),
};
}
INSTANTIATE_TEST_SUITE_P( //
@@ -2848,15 +2850,16 @@
Vec(0x0.034p-14_f, -0x0.034p-14_f, 0x0.068p-14_f, -0x0.068p-14_f)),
// Value out of f16 range
- E({65504.003_f}, "12:34 error: value 65504.00390625 cannot be represented as 'f16'"),
- E({-65504.003_f}, "12:34 error: value -65504.00390625 cannot be represented as 'f16'"),
- E({0x1.234p56_f}, "12:34 error: value 81979586966978560 cannot be represented as 'f16'"),
+ E({65504.003_f}, "12:34 error: value 65504.003906250 cannot be represented as 'f16'"),
+ E({-65504.003_f}, "12:34 error: value -65504.003906250 cannot be represented as 'f16'"),
+ E({0x1.234p56_f},
+ "12:34 error: value 81979586966978560.000000000 cannot be represented as 'f16'"),
E({0x4.321p65_f},
- "12:34 error: value 1.5478871919272394752e+20 cannot be represented as 'f16'"),
+ "12:34 error: value 154788719192723947520.000000000 cannot be represented as 'f16'"),
E({Vec(65504.003_f, 0_f)},
- "12:34 error: value 65504.00390625 cannot be represented as 'f16'"),
+ "12:34 error: value 65504.003906250 cannot be represented as 'f16'"),
E({Vec(0_f, -0x4.321p65_f)},
- "12:34 error: value -1.5478871919272394752e+20 cannot be represented as 'f16'"),
+ "12:34 error: value -154788719192723947520.000000000 cannot be represented as 'f16'"),
};
}
INSTANTIATE_TEST_SUITE_P( //
diff --git a/src/tint/resolver/const_eval_conversion_test.cc b/src/tint/resolver/const_eval_conversion_test.cc
index bcad648..b6bcc56 100644
--- a/src/tint/resolver/const_eval_conversion_test.cc
+++ b/src/tint/resolver/const_eval_conversion_test.cc
@@ -431,7 +431,8 @@
WrapInFunction(expr);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: value 10000000000 cannot be represented as 'f16'");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: value 10000000000.000000000 cannot be represented as 'f16'");
}
TEST_F(ResolverConstEvalTest, Vec3_Convert_Small_f32_to_f16) {
diff --git a/src/tint/resolver/const_eval_runtime_semantics_test.cc b/src/tint/resolver/const_eval_runtime_semantics_test.cc
index 9de1866..347e41d 100644
--- a/src/tint/resolver/const_eval_runtime_semantics_test.cc
+++ b/src/tint/resolver/const_eval_runtime_semantics_test.cc
@@ -75,7 +75,7 @@
EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f);
EXPECT_EQ(
error(),
- R"(warning: '1.7976931348623157081e+308 + 1.7976931348623157081e+308' cannot be represented as 'abstract-float')");
+ R"(warning: '179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 + 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0' cannot be represented as 'abstract-float')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Add_F32_Overflow) {
@@ -86,7 +86,7 @@
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
EXPECT_EQ(
error(),
- R"(warning: '3.4028234663852885981e+38 + 3.4028234663852885981e+38' cannot be represented as 'f32')");
+ R"(warning: '340282346638528859811704183484516925440.0 + 340282346638528859811704183484516925440.0' cannot be represented as 'f32')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_AInt_Overflow) {
@@ -107,7 +107,7 @@
EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f);
EXPECT_EQ(
error(),
- R"(warning: '-1.7976931348623157081e+308 - 1.7976931348623157081e+308' cannot be represented as 'abstract-float')");
+ R"(warning: '-179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 - 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0' cannot be represented as 'abstract-float')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_F32_Overflow) {
@@ -118,7 +118,7 @@
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
EXPECT_EQ(
error(),
- R"(warning: '-3.4028234663852885981e+38 - 3.4028234663852885981e+38' cannot be represented as 'f32')");
+ R"(warning: '-340282346638528859811704183484516925440.0 - 340282346638528859811704183484516925440.0' cannot be represented as 'f32')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_AInt_Overflow) {
@@ -139,7 +139,7 @@
EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f);
EXPECT_EQ(
error(),
- R"(warning: '1.7976931348623157081e+308 * 1.7976931348623157081e+308' cannot be represented as 'abstract-float')");
+ R"(warning: '179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 * 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0' cannot be represented as 'abstract-float')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_F32_Overflow) {
@@ -150,7 +150,7 @@
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
EXPECT_EQ(
error(),
- R"(warning: '3.4028234663852885981e+38 * 3.4028234663852885981e+38' cannot be represented as 'f32')");
+ R"(warning: '340282346638528859811704183484516925440.0 * 340282346638528859811704183484516925440.0' cannot be represented as 'f32')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_AInt_ZeroDenominator) {
@@ -186,7 +186,7 @@
auto result = const_eval.OpDivide(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 42.f);
- EXPECT_EQ(error(), R"(warning: '42 / 0' cannot be represented as 'abstract-float')");
+ EXPECT_EQ(error(), R"(warning: '42.0 / 0.0' cannot be represented as 'abstract-float')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_F32_ZeroDenominator) {
@@ -195,7 +195,7 @@
auto result = const_eval.OpDivide(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), 42.f);
- EXPECT_EQ(error(), R"(warning: '42 / 0' cannot be represented as 'f32')");
+ EXPECT_EQ(error(), R"(warning: '42.0 / 0.0' cannot be represented as 'f32')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_I32_MostNegativeByMinInt) {
@@ -212,7 +212,7 @@
auto* b = Scalar(AInt(0));
auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result);
- EXPECT_EQ(result.Get()->ValueAs<AInt>(), 42);
+ EXPECT_EQ(result.Get()->ValueAs<AInt>(), 0);
EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'abstract-int')");
}
@@ -221,7 +221,7 @@
auto* b = Scalar(i32(0));
auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result);
- EXPECT_EQ(result.Get()->ValueAs<i32>(), 42);
+ EXPECT_EQ(result.Get()->ValueAs<i32>(), 0);
EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'i32')");
}
@@ -230,7 +230,7 @@
auto* b = Scalar(u32(0));
auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result);
- EXPECT_EQ(result.Get()->ValueAs<u32>(), 42);
+ EXPECT_EQ(result.Get()->ValueAs<u32>(), 0);
EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'u32')");
}
@@ -239,8 +239,8 @@
auto* b = Scalar(AFloat(0));
auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result);
- EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 42.f);
- EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'abstract-float')");
+ EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f);
+ EXPECT_EQ(error(), R"(warning: '42.0 % 0.0' cannot be represented as 'abstract-float')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_F32_ZeroDenominator) {
@@ -248,8 +248,8 @@
auto* b = Scalar(f32(0));
auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result);
- EXPECT_EQ(result.Get()->ValueAs<f32>(), 42.f);
- EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'f32')");
+ EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
+ EXPECT_EQ(error(), R"(warning: '42.0 % 0.0' cannot be represented as 'f32')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_I32_MostNegativeByMinInt) {
@@ -257,7 +257,7 @@
auto* b = Scalar(i32(-1));
auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result);
- EXPECT_EQ(result.Get()->ValueAs<i32>(), i32::Lowest());
+ EXPECT_EQ(result.Get()->ValueAs<i32>(), 0);
EXPECT_EQ(error(), R"(warning: '-2147483648 % -1' cannot be represented as 'i32')");
}
@@ -363,7 +363,7 @@
auto result = const_eval.exp(a->Type(), utils::Vector{a}, {});
ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
- EXPECT_EQ(error(), R"(warning: e^1000 cannot be represented as 'f32')");
+ EXPECT_EQ(error(), R"(warning: e^1000.000000000 cannot be represented as 'f32')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Exp2_F32_Overflow) {
@@ -371,7 +371,7 @@
auto result = const_eval.exp2(a->Type(), utils::Vector{a}, {});
ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
- EXPECT_EQ(error(), R"(warning: 2^1000 cannot be represented as 'f32')");
+ EXPECT_EQ(error(), R"(warning: 2^1000.000000000 cannot be represented as 'f32')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, ExtractBits_I32_TooManyBits) {
@@ -476,7 +476,7 @@
auto result = const_eval.pack2x16float(create<type::U32>(), utils::Vector{vec}, {});
ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<u32>(), 0x51430000);
- EXPECT_EQ(error(), R"(warning: value 75250 cannot be represented as 'f16')");
+ EXPECT_EQ(error(), R"(warning: value 75250.000000000 cannot be represented as 'f16')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Pow_F32_Overflow) {
@@ -485,7 +485,7 @@
auto result = const_eval.pow(a->Type(), utils::Vector{a, b}, {});
ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
- EXPECT_EQ(error(), R"(warning: '2 ^ 1000' cannot be represented as 'f32')");
+ EXPECT_EQ(error(), R"(warning: '2.0 ^ 1000.0' cannot be represented as 'f32')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Unpack2x16Float_OutOfRange) {
@@ -502,7 +502,7 @@
auto result = const_eval.quantizeToF16(create<type::U32>(), utils::Vector{a}, {});
ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<u32>(), 0);
- EXPECT_EQ(error(), R"(warning: value 75250 cannot be represented as 'f16')");
+ EXPECT_EQ(error(), R"(warning: value 75250.000000000 cannot be represented as 'f16')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sqrt_F32_OutOfRange) {
@@ -534,8 +534,9 @@
auto result = const_eval.Convert(create<type::F32>(), a, {});
ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), f32::kHighestValue);
- EXPECT_EQ(error(),
- R"(warning: value 1.7976931348623157081e+308 cannot be represented as 'f32')");
+ EXPECT_EQ(
+ error(),
+ R"(warning: value 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000000 cannot be represented as 'f32')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F32_TooLow) {
@@ -543,8 +544,9 @@
auto result = const_eval.Convert(create<type::F32>(), a, {});
ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), f32::kLowestValue);
- EXPECT_EQ(error(),
- R"(warning: value -1.7976931348623157081e+308 cannot be represented as 'f32')");
+ EXPECT_EQ(
+ error(),
+ R"(warning: value -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000000 cannot be represented as 'f32')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooHigh) {
@@ -552,7 +554,7 @@
auto result = const_eval.Convert(create<type::F16>(), a, {});
ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), f16::kHighestValue);
- EXPECT_EQ(error(), R"(warning: value 1000000 cannot be represented as 'f16')");
+ EXPECT_EQ(error(), R"(warning: value 1000000.000000000 cannot be represented as 'f16')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooLow) {
@@ -560,7 +562,7 @@
auto result = const_eval.Convert(create<type::F16>(), a, {});
ASSERT_TRUE(result);
EXPECT_EQ(result.Get()->ValueAs<f32>(), f16::kLowestValue);
- EXPECT_EQ(error(), R"(warning: value -1000000 cannot be represented as 'f16')");
+ EXPECT_EQ(error(), R"(warning: value -1000000.000000000 cannot be represented as 'f16')");
}
TEST_F(ResolverConstEvalRuntimeSemanticsTest, Vec_Overflow_SingleComponent) {
diff --git a/src/tint/resolver/const_eval_test.h b/src/tint/resolver/const_eval_test.h
index 001d3d1..de25b20 100644
--- a/src/tint/resolver/const_eval_test.h
+++ b/src/tint/resolver/const_eval_test.h
@@ -24,6 +24,7 @@
#include "gtest/gtest.h"
#include "src/tint/resolver/resolver_test_helper.h"
#include "src/tint/type/test_helper.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::resolver {
@@ -218,8 +219,7 @@
/// Returns the overflow error message for binary ops
template <typename NumberT>
inline std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs) {
- std::stringstream ss;
- ss << std::setprecision(20);
+ utils::StringStream ss;
ss << "'" << lhs.value << " " << op << " " << rhs.value << "' cannot be represented as '"
<< FriendlyName<NumberT>() << "'";
return ss.str();
@@ -228,8 +228,7 @@
/// Returns the overflow error message for conversions
template <typename VALUE_TY>
std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) {
- std::stringstream ss;
- ss << std::setprecision(20);
+ utils::StringStream ss;
ss << "value " << value << " cannot be represented as "
<< "'" << target_ty << "'";
return ss.str();
@@ -238,8 +237,7 @@
/// Returns the overflow error message for exponentiation
template <typename NumberT>
std::string OverflowExpErrorMessage(std::string_view base, NumberT exp) {
- std::stringstream ss;
- ss << std::setprecision(20);
+ utils::StringStream ss;
ss << base << "^" << exp << " cannot be represented as "
<< "'" << FriendlyName<NumberT>() << "'";
return ss.str();
diff --git a/src/tint/resolver/control_block_validation_test.cc b/src/tint/resolver/control_block_validation_test.cc
index 2104321..ba7aa53 100644
--- a/src/tint/resolver/control_block_validation_test.cc
+++ b/src/tint/resolver/control_block_validation_test.cc
@@ -561,5 +561,36 @@
EXPECT_EQ(r()->error(), "12:34 error: case selector must be a constant expression");
}
+constexpr size_t kMaxSwitchCaseSelectors = 16383;
+
+TEST_F(ResolverControlBlockValidationTest, Switch_MaxSelectors_Valid) {
+ utils::Vector<const ast::CaseStatement*, 0> cases;
+ for (size_t i = 0; i < kMaxSwitchCaseSelectors - 1; ++i) {
+ cases.Push(Case(CaseSelector(Expr(i32(i)))));
+ }
+ cases.Push(DefaultCase());
+
+ auto* var = Var("a", ty.i32());
+ auto* s = Switch("a", std::move(cases));
+ WrapInFunction(var, s);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverControlBlockValidationTest, Switch_MaxSelectors_Invalid) {
+ utils::Vector<const ast::CaseStatement*, 0> cases;
+ for (size_t i = 0; i < kMaxSwitchCaseSelectors; ++i) {
+ cases.Push(Case(CaseSelector(Expr(i32(i)))));
+ }
+ cases.Push(DefaultCase());
+
+ auto* var = Var("a", ty.i32());
+ auto* s = Switch(Source{{12, 34}}, "a", std::move(cases));
+ WrapInFunction(var, s);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: switch statement has 16384 case selectors, max is 16383");
+}
+
} // namespace
} // namespace tint::resolver
diff --git a/src/tint/resolver/ctor_conv_intrinsic.cc b/src/tint/resolver/ctor_conv_intrinsic.cc
index 3ac3a67..1609e49 100644
--- a/src/tint/resolver/ctor_conv_intrinsic.cc
+++ b/src/tint/resolver/ctor_conv_intrinsic.cc
@@ -62,6 +62,8 @@
return "mat4x3";
case CtorConvIntrinsic::kMat4x4:
return "mat4x4";
+ case CtorConvIntrinsic::kPackedVec3:
+ return "packedVec3";
}
return "<unknown>";
}
diff --git a/src/tint/resolver/ctor_conv_intrinsic.h b/src/tint/resolver/ctor_conv_intrinsic.h
index 4ee1c79..f294394 100644
--- a/src/tint/resolver/ctor_conv_intrinsic.h
+++ b/src/tint/resolver/ctor_conv_intrinsic.h
@@ -48,6 +48,7 @@
kMat4x2,
kMat4x3,
kMat4x4,
+ kPackedVec3,
};
/// @returns the name of the type.
diff --git a/src/tint/resolver/dependency_graph.cc b/src/tint/resolver/dependency_graph.cc
index 0b8f728..9b6d471 100644
--- a/src/tint/resolver/dependency_graph.cc
+++ b/src/tint/resolver/dependency_graph.cc
@@ -65,6 +65,7 @@
#include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h"
#include "src/tint/utils/scoped_assignment.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/unique_vector.h"
#define TINT_DUMP_DEPENDENCY_GRAPH 0
@@ -711,7 +712,7 @@
/// found in `stack`.
/// @param stack is the global dependency stack that contains a loop.
void CyclicDependencyFound(const Global* root, utils::VectorRef<const Global*> stack) {
- std::stringstream msg;
+ utils::StringStream msg;
msg << "cyclic dependency found: ";
constexpr size_t kLoopNotStarted = ~0u;
size_t loop_start = kLoopNotStarted;
diff --git a/src/tint/resolver/function_validation_test.cc b/src/tint/resolver/function_validation_test.cc
index 3a0275f..6654c43 100644
--- a/src/tint/resolver/function_validation_test.cc
+++ b/src/tint/resolver/function_validation_test.cc
@@ -18,6 +18,7 @@
#include "src/tint/builtin/builtin_value.h"
#include "src/tint/resolver/resolver.h"
#include "src/tint/resolver/resolver_test_helper.h"
+#include "src/tint/utils/string_stream.h"
#include "gmock/gmock.h"
@@ -979,7 +980,7 @@
EXPECT_EQ(r()->error(), "12:34 error: type of function parameter must be constructible");
}
-TEST_F(ResolverFunctionValidationTest, ParameterSotreType_AtomicFree) {
+TEST_F(ResolverFunctionValidationTest, ParameterStoreType_AtomicFree) {
Structure("S", utils::Vector{
Member("m", ty.i32()),
});
@@ -1008,7 +1009,7 @@
Func(Source{{12, 34}}, "f", params, ty.void_(), utils::Empty);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: functions may declare at most 255 parameters");
+ EXPECT_EQ(r()->error(), "12:34 error: function declares 256 parameters, maximum is 255");
}
TEST_F(ResolverFunctionValidationTest, ParameterVectorNoType) {
@@ -1054,7 +1055,7 @@
if (param.expectation == Expectation::kAlwaysPass) {
ASSERT_TRUE(r()->Resolve()) << r()->error();
} else {
- std::stringstream ss;
+ utils::StringStream ss;
ss << param.address_space;
EXPECT_FALSE(r()->Resolve());
if (param.expectation == Expectation::kInvalid) {
diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc
index 17927db..0d2cc10 100644
--- a/src/tint/resolver/intrinsic_table.cc
+++ b/src/tint/resolver/intrinsic_table.cc
@@ -39,6 +39,7 @@
#include "src/tint/utils/hashmap.h"
#include "src/tint/utils/math.h"
#include "src/tint/utils/scoped_assignment.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::resolver {
namespace {
@@ -456,6 +457,25 @@
constexpr auto build_vec3 = build_vec<3>;
constexpr auto build_vec4 = build_vec<4>;
+bool match_packedVec3(MatchState&, const type::Type* ty, const type::Type*& T) {
+ if (ty->Is<Any>()) {
+ T = ty;
+ return true;
+ }
+
+ if (auto* v = ty->As<type::Vector>()) {
+ if (v->Packed()) {
+ T = v->type();
+ return true;
+ }
+ }
+ return false;
+}
+
+const type::Vector* build_packedVec3(MatchState& state, const type::Type* el) {
+ return state.builder.create<type::Vector>(el, 3u, /* packed */ true);
+}
+
bool match_mat(MatchState&, const type::Type* ty, Number& M, Number& N, const type::Type*& T) {
if (ty->Is<Any>()) {
M = Number::any;
@@ -1183,12 +1203,12 @@
sem::EvaluationStage earliest_eval_stage) const;
// Prints the overload for emitting diagnostics
- void PrintOverload(std::ostream& ss,
+ void PrintOverload(utils::StringStream& ss,
const OverloadInfo* overload,
const char* intrinsic_name) const;
// Prints the list of candidates for emitting diagnostics
- void PrintCandidates(std::ostream& ss,
+ void PrintCandidates(utils::StringStream& ss,
utils::VectorRef<Candidate> candidates,
const char* intrinsic_name) const;
@@ -1213,7 +1233,7 @@
const char* intrinsic_name,
utils::VectorRef<const type::Type*> args,
const type::Type* template_arg = nullptr) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << intrinsic_name;
if (template_arg) {
ss << "<" << template_arg->FriendlyName(builder.Symbols()) << ">";
@@ -1252,7 +1272,7 @@
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&](utils::VectorRef<Candidate> candidates) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "no matching call to " << CallSignature(builder, intrinsic_name, args) << std::endl;
if (!candidates.IsEmpty()) {
ss << std::endl
@@ -1321,7 +1341,7 @@
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&, name = intrinsic_name](utils::VectorRef<Candidate> candidates) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "no matching overload for " << CallSignature(builder, name, args) << std::endl;
if (!candidates.IsEmpty()) {
ss << std::endl
@@ -1399,7 +1419,7 @@
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&, name = intrinsic_name](utils::VectorRef<Candidate> candidates) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "no matching overload for " << CallSignature(builder, name, args) << std::endl;
if (!candidates.IsEmpty()) {
ss << std::endl
@@ -1434,7 +1454,7 @@
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&](utils::VectorRef<Candidate> candidates) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "no matching constructor for " << CallSignature(builder, name, args, template_arg)
<< std::endl;
Candidates ctor, conv;
@@ -1736,7 +1756,7 @@
return MatchState(builder, templates, matchers, overload, matcher_indices, earliest_eval_stage);
}
-void Impl::PrintOverload(std::ostream& ss,
+void Impl::PrintOverload(utils::StringStream& ss,
const OverloadInfo* overload,
const char* intrinsic_name) const {
TemplateState templates;
@@ -1808,7 +1828,7 @@
}
}
-void Impl::PrintCandidates(std::ostream& ss,
+void Impl::PrintCandidates(utils::StringStream& ss,
utils::VectorRef<Candidate> candidates,
const char* intrinsic_name) const {
for (auto& candidate : candidates) {
@@ -1846,7 +1866,7 @@
utils::VectorRef<const type::Type*> args,
TemplateState templates,
utils::VectorRef<Candidate> candidates) const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "ambiguous overload while attempting to match " << intrinsic_name;
for (size_t i = 0; i < std::numeric_limits<size_t>::max(); i++) {
if (auto* ty = templates.Type(i)) {
diff --git a/src/tint/resolver/intrinsic_table.inl b/src/tint/resolver/intrinsic_table.inl
index a4b5e14..9aa0b76 100644
--- a/src/tint/resolver/intrinsic_table.inl
+++ b/src/tint/resolver/intrinsic_table.inl
@@ -71,7 +71,7 @@
}
std::string Ia::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "abstract-int";
return ss.str();
}
@@ -99,7 +99,7 @@
}
std::string Fa::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "abstract-float";
return ss.str();
}
@@ -627,7 +627,7 @@
std::string Vec::String(MatchState* state) const {
const std::string N = state->NumName();
const std::string T = state->TypeName();
- std::stringstream ss;
+ utils::StringStream ss;
ss << "vec" << N << "<" << T << ">";
return ss.str();
}
@@ -673,7 +673,7 @@
const std::string N = state->NumName();
const std::string M = state->NumName();
const std::string T = state->TypeName();
- std::stringstream ss;
+ utils::StringStream ss;
ss << "mat" << N << "x" << M << "<" << T << ">";
return ss.str();
}
@@ -1370,6 +1370,38 @@
return "texture_external";
}
+/// TypeMatcher for 'type packedVec3'
+class PackedVec3 : public TypeMatcher {
+ public:
+ /// Checks whether the given type matches the matcher rules.
+ /// Match may define and refine the template types and numbers in state.
+ /// @param state the MatchState
+ /// @param type the type to match
+ /// @returns the canonicalized type on match, otherwise nullptr
+ const type::Type* Match(MatchState& state,
+ const type::Type* type) const override;
+ /// @param state the MatchState
+ /// @return a string representation of the matcher.
+ std::string String(MatchState* state) const override;
+};
+
+const type::Type* PackedVec3::Match(MatchState& state, const type::Type* ty) const {
+ const type::Type* T = nullptr;
+ if (!match_packedVec3(state, ty, T)) {
+ return nullptr;
+ }
+ T = state.Type(T);
+ if (T == nullptr) {
+ return nullptr;
+ }
+ return build_packedVec3(state, T);
+}
+
+std::string PackedVec3::String(MatchState* state) const {
+ const std::string T = state->TypeName();
+ return "packedVec3<" + T + ">";
+}
+
/// TypeMatcher for 'type __modf_result'
class ModfResult : public TypeMatcher {
public:
@@ -1399,7 +1431,7 @@
std::string ModfResult::String(MatchState* state) const {
const std::string T = state->TypeName();
- std::stringstream ss;
+ utils::StringStream ss;
ss << "__modf_result_" << T;
return ss.str();
}
@@ -1439,7 +1471,7 @@
std::string ModfResultVec::String(MatchState* state) const {
const std::string N = state->NumName();
const std::string T = state->TypeName();
- std::stringstream ss;
+ utils::StringStream ss;
ss << "__modf_result_vec" << N << "_" << T;
return ss.str();
}
@@ -1473,7 +1505,7 @@
std::string FrexpResult::String(MatchState* state) const {
const std::string T = state->TypeName();
- std::stringstream ss;
+ utils::StringStream ss;
ss << "__frexp_result_" << T;
return ss.str();
}
@@ -1513,7 +1545,7 @@
std::string FrexpResultVec::String(MatchState* state) const {
const std::string N = state->NumName();
const std::string T = state->TypeName();
- std::stringstream ss;
+ utils::StringStream ss;
ss << "__frexp_result_vec" << N << "_" << T;
return ss.str();
}
@@ -1592,7 +1624,7 @@
}
std::string Scalar::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
@@ -1635,7 +1667,7 @@
}
std::string ConcreteScalar::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
@@ -1681,7 +1713,7 @@
}
std::string ScalarNoF32::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << I32().String(nullptr) << ", " << F16().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
@@ -1727,7 +1759,7 @@
}
std::string ScalarNoF16::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
@@ -1773,7 +1805,7 @@
}
std::string ScalarNoI32::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr);
@@ -1819,7 +1851,7 @@
}
std::string ScalarNoU32::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << " or " << Bool().String(nullptr);
@@ -1865,7 +1897,7 @@
}
std::string ScalarNoBool::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
@@ -1911,7 +1943,7 @@
}
std::string FiaFiu32F16::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << F16().String(nullptr);
@@ -1954,7 +1986,7 @@
}
std::string FiaFi32F16::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << F16().String(nullptr);
@@ -1997,7 +2029,7 @@
}
std::string FiaFiu32::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
@@ -2031,7 +2063,7 @@
}
std::string FaF32::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Fa().String(nullptr) << " or " << F32().String(nullptr);
@@ -2068,7 +2100,7 @@
}
std::string FaF32F16::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Fa().String(nullptr) << ", " << F32().String(nullptr) << " or " << F16().String(nullptr);
@@ -2105,7 +2137,7 @@
}
std::string IaIu32::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
@@ -2139,7 +2171,7 @@
}
std::string IaI32::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << Ia().String(nullptr) << " or " << I32().String(nullptr);
@@ -2179,7 +2211,7 @@
}
std::string Fiu32F16::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << F16().String(nullptr);
@@ -2216,7 +2248,7 @@
}
std::string Fiu32::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr);
@@ -2253,7 +2285,7 @@
}
std::string Fi32F16::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << F16().String(nullptr);
@@ -2287,7 +2319,7 @@
}
std::string Fi32::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << " or " << I32().String(nullptr);
@@ -2321,7 +2353,7 @@
}
std::string F32F16::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << F32().String(nullptr) << " or " << F16().String(nullptr);
@@ -2355,7 +2387,7 @@
}
std::string Iu32::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss << I32().String(nullptr) << " or " << U32().String(nullptr);
@@ -2667,6 +2699,7 @@
TextureStorage2DArray TextureStorage2DArray_;
TextureStorage3D TextureStorage3D_;
TextureExternal TextureExternal_;
+ PackedVec3 PackedVec3_;
ModfResult ModfResult_;
ModfResultVec ModfResultVec_;
FrexpResult FrexpResult_;
@@ -2709,7 +2742,7 @@
~Matchers();
/// The template types, types, and type matchers
- TypeMatcher const* const type[72] = {
+ TypeMatcher const* const type[73] = {
/* [0] */ &template_type_0_,
/* [1] */ &template_type_1_,
/* [2] */ &template_type_2_,
@@ -2757,31 +2790,32 @@
/* [44] */ &TextureStorage2DArray_,
/* [45] */ &TextureStorage3D_,
/* [46] */ &TextureExternal_,
- /* [47] */ &ModfResult_,
- /* [48] */ &ModfResultVec_,
- /* [49] */ &FrexpResult_,
- /* [50] */ &FrexpResultVec_,
- /* [51] */ &AtomicCompareExchangeResult_,
- /* [52] */ &Scalar_,
- /* [53] */ &ConcreteScalar_,
- /* [54] */ &ScalarNoF32_,
- /* [55] */ &ScalarNoF16_,
- /* [56] */ &ScalarNoI32_,
- /* [57] */ &ScalarNoU32_,
- /* [58] */ &ScalarNoBool_,
- /* [59] */ &FiaFiu32F16_,
- /* [60] */ &FiaFi32F16_,
- /* [61] */ &FiaFiu32_,
- /* [62] */ &FaF32_,
- /* [63] */ &FaF32F16_,
- /* [64] */ &IaIu32_,
- /* [65] */ &IaI32_,
- /* [66] */ &Fiu32F16_,
- /* [67] */ &Fiu32_,
- /* [68] */ &Fi32F16_,
- /* [69] */ &Fi32_,
- /* [70] */ &F32F16_,
- /* [71] */ &Iu32_,
+ /* [47] */ &PackedVec3_,
+ /* [48] */ &ModfResult_,
+ /* [49] */ &ModfResultVec_,
+ /* [50] */ &FrexpResult_,
+ /* [51] */ &FrexpResultVec_,
+ /* [52] */ &AtomicCompareExchangeResult_,
+ /* [53] */ &Scalar_,
+ /* [54] */ &ConcreteScalar_,
+ /* [55] */ &ScalarNoF32_,
+ /* [56] */ &ScalarNoF16_,
+ /* [57] */ &ScalarNoI32_,
+ /* [58] */ &ScalarNoU32_,
+ /* [59] */ &ScalarNoBool_,
+ /* [60] */ &FiaFiu32F16_,
+ /* [61] */ &FiaFi32F16_,
+ /* [62] */ &FiaFiu32_,
+ /* [63] */ &FaF32_,
+ /* [64] */ &FaF32F16_,
+ /* [65] */ &IaIu32_,
+ /* [66] */ &IaI32_,
+ /* [67] */ &Fiu32F16_,
+ /* [68] */ &Fiu32_,
+ /* [69] */ &Fi32F16_,
+ /* [70] */ &Fi32_,
+ /* [71] */ &F32F16_,
+ /* [72] */ &Iu32_,
};
/// The template numbers, and number matchers
@@ -2848,13 +2882,13 @@
/* [40] */ 23,
/* [41] */ 0,
/* [42] */ 9,
- /* [43] */ 50,
+ /* [43] */ 51,
/* [44] */ 0,
/* [45] */ 0,
/* [46] */ 23,
/* [47] */ 0,
/* [48] */ 1,
- /* [49] */ 48,
+ /* [49] */ 49,
/* [50] */ 0,
/* [51] */ 0,
/* [52] */ 42,
@@ -2913,9 +2947,9 @@
/* [105] */ 8,
/* [106] */ 12,
/* [107] */ 0,
- /* [108] */ 49,
+ /* [108] */ 50,
/* [109] */ 0,
- /* [110] */ 47,
+ /* [110] */ 48,
/* [111] */ 0,
/* [112] */ 11,
/* [113] */ 9,
@@ -2967,7 +3001,7 @@
/* [159] */ 1,
/* [160] */ 12,
/* [161] */ 1,
- /* [162] */ 51,
+ /* [162] */ 52,
/* [163] */ 0,
/* [164] */ 11,
/* [165] */ 10,
@@ -3037,14 +3071,16 @@
/* [229] */ 9,
/* [230] */ 22,
/* [231] */ 10,
- /* [232] */ 37,
- /* [233] */ 38,
- /* [234] */ 39,
- /* [235] */ 40,
- /* [236] */ 41,
- /* [237] */ 46,
- /* [238] */ 28,
- /* [239] */ 29,
+ /* [232] */ 47,
+ /* [233] */ 0,
+ /* [234] */ 37,
+ /* [235] */ 38,
+ /* [236] */ 39,
+ /* [237] */ 40,
+ /* [238] */ 41,
+ /* [239] */ 46,
+ /* [240] */ 28,
+ /* [241] */ 29,
};
// Assert that the MatcherIndex is big enough to index all the matchers, plus
@@ -3387,7 +3423,7 @@
{
/* [66] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [67] */
@@ -3427,7 +3463,7 @@
{
/* [74] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [75] */
@@ -3447,12 +3483,12 @@
{
/* [78] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [79] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [80] */
@@ -3482,7 +3518,7 @@
{
/* [85] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [86] */
@@ -3507,12 +3543,12 @@
{
/* [90] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [91] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [92] */
@@ -3537,12 +3573,12 @@
{
/* [96] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [97] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [98] */
@@ -3572,7 +3608,7 @@
{
/* [103] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [104] */
@@ -3602,7 +3638,7 @@
{
/* [109] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [110] */
@@ -3632,7 +3668,7 @@
{
/* [115] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [116] */
@@ -3662,7 +3698,7 @@
{
/* [121] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [122] */
@@ -3692,7 +3728,7 @@
{
/* [127] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [128] */
@@ -3717,12 +3753,12 @@
{
/* [132] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [133] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [134] */
@@ -3817,7 +3853,7 @@
{
/* [152] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [153] */
@@ -3842,7 +3878,7 @@
{
/* [157] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [158] */
@@ -3867,7 +3903,7 @@
{
/* [162] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [163] */
@@ -3882,12 +3918,12 @@
{
/* [165] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [166] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [167] */
@@ -3907,12 +3943,12 @@
{
/* [170] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [171] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [172] */
@@ -3932,12 +3968,12 @@
{
/* [175] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [176] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [177] */
@@ -3957,12 +3993,12 @@
{
/* [180] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[235],
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [181] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [182] */
@@ -3987,7 +4023,7 @@
{
/* [186] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [187] */
@@ -4007,12 +4043,12 @@
{
/* [190] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [191] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [192] */
@@ -4037,7 +4073,7 @@
{
/* [196] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [197] */
@@ -4062,7 +4098,7 @@
{
/* [201] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [202] */
@@ -4087,7 +4123,7 @@
{
/* [206] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [207] */
@@ -4112,7 +4148,7 @@
{
/* [211] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [212] */
@@ -4132,12 +4168,12 @@
{
/* [215] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [216] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [217] */
@@ -4157,12 +4193,12 @@
{
/* [220] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [221] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [222] */
@@ -4182,12 +4218,12 @@
{
/* [225] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[235],
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [226] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [227] */
@@ -4207,12 +4243,12 @@
{
/* [230] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [231] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [232] */
@@ -4232,12 +4268,12 @@
{
/* [235] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [236] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [237] */
@@ -4257,12 +4293,12 @@
{
/* [240] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[235],
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [241] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [242] */
@@ -4287,7 +4323,7 @@
{
/* [246] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [247] */
@@ -4312,7 +4348,7 @@
{
/* [251] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [252] */
@@ -4337,7 +4373,7 @@
{
/* [256] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [257] */
@@ -4362,7 +4398,7 @@
{
/* [261] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [262] */
@@ -4387,7 +4423,7 @@
{
/* [266] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [267] */
@@ -4412,7 +4448,7 @@
{
/* [271] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [272] */
@@ -4437,7 +4473,7 @@
{
/* [276] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [277] */
@@ -4457,12 +4493,12 @@
{
/* [280] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [281] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [282] */
@@ -4482,12 +4518,12 @@
{
/* [285] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [286] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [287] */
@@ -4507,12 +4543,12 @@
{
/* [290] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[235],
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [291] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [292] */
@@ -4582,7 +4618,7 @@
{
/* [305] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [306] */
@@ -4602,7 +4638,7 @@
{
/* [309] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [310] */
@@ -4612,12 +4648,12 @@
{
/* [311] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [312] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [313] */
@@ -4632,12 +4668,12 @@
{
/* [315] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [316] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [317] */
@@ -4652,12 +4688,12 @@
{
/* [319] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[235],
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [320] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [321] */
@@ -4672,12 +4708,12 @@
{
/* [323] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [324] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [325] */
@@ -4692,12 +4728,12 @@
{
/* [327] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[234],
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [328] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [329] */
@@ -4717,7 +4753,7 @@
{
/* [332] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [333] */
@@ -4737,7 +4773,7 @@
{
/* [336] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [337] */
@@ -4757,7 +4793,7 @@
{
/* [340] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [341] */
@@ -4777,7 +4813,7 @@
{
/* [344] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [345] */
@@ -4792,12 +4828,12 @@
{
/* [347] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [348] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [349] */
@@ -4812,12 +4848,12 @@
{
/* [351] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [352] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [353] */
@@ -4832,12 +4868,12 @@
{
/* [355] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[235],
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [356] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [357] */
@@ -4857,7 +4893,7 @@
{
/* [360] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [361] */
@@ -4877,7 +4913,7 @@
{
/* [364] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [365] */
@@ -4897,7 +4933,7 @@
{
/* [368] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [369] */
@@ -4912,12 +4948,12 @@
{
/* [371] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [372] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [373] */
@@ -4932,12 +4968,12 @@
{
/* [375] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[234],
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [376] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [377] */
@@ -4952,12 +4988,12 @@
{
/* [379] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [380] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [381] */
@@ -4972,12 +5008,12 @@
{
/* [383] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[234],
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [384] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[239],
+ /* matcher indices */ &kMatcherIndices[241],
},
{
/* [385] */
@@ -4997,7 +5033,7 @@
{
/* [388] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [389] */
@@ -5017,7 +5053,7 @@
{
/* [392] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [393] */
@@ -5037,7 +5073,7 @@
{
/* [396] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [397] */
@@ -5052,12 +5088,12 @@
{
/* [399] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [400] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [401] */
@@ -5072,12 +5108,12 @@
{
/* [403] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[234],
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [404] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [405] */
@@ -5172,7 +5208,7 @@
{
/* [423] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [424] */
@@ -5532,12 +5568,12 @@
{
/* [495] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [496] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [497] */
@@ -5547,12 +5583,12 @@
{
/* [498] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[234],
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [499] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [500] */
@@ -5567,7 +5603,7 @@
{
/* [502] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [503] */
@@ -5582,7 +5618,7 @@
{
/* [505] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [506] */
@@ -5597,7 +5633,7 @@
{
/* [508] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [509] */
@@ -5612,7 +5648,7 @@
{
/* [511] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [512] */
@@ -5622,12 +5658,12 @@
{
/* [513] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [514] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [515] */
@@ -5637,12 +5673,12 @@
{
/* [516] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[234],
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [517] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [518] */
@@ -5657,7 +5693,7 @@
{
/* [520] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [521] */
@@ -5667,12 +5703,12 @@
{
/* [522] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[237],
+ /* matcher indices */ &kMatcherIndices[239],
},
{
/* [523] */
/* usage */ ParameterUsage::kSampler,
- /* matcher indices */ &kMatcherIndices[238],
+ /* matcher indices */ &kMatcherIndices[240],
},
{
/* [524] */
@@ -5877,7 +5913,7 @@
{
/* [564] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [565] */
@@ -5892,7 +5928,7 @@
{
/* [567] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[236],
+ /* matcher indices */ &kMatcherIndices[238],
},
{
/* [568] */
@@ -6277,7 +6313,7 @@
{
/* [644] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [645] */
@@ -6287,7 +6323,7 @@
{
/* [646] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [647] */
@@ -6297,7 +6333,7 @@
{
/* [648] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[234],
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [649] */
@@ -6307,7 +6343,7 @@
{
/* [650] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[235],
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [651] */
@@ -6317,7 +6353,7 @@
{
/* [652] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[237],
+ /* matcher indices */ &kMatcherIndices[239],
},
{
/* [653] */
@@ -7657,27 +7693,27 @@
{
/* [920] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [921] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [922] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[234],
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [923] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[235],
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [924] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[236],
+ /* matcher indices */ &kMatcherIndices[238],
},
{
/* [925] */
@@ -7702,7 +7738,7 @@
{
/* [929] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[237],
+ /* matcher indices */ &kMatcherIndices[239],
},
{
/* [930] */
@@ -7717,12 +7753,12 @@
{
/* [932] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [933] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[235],
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [934] */
@@ -7762,22 +7798,22 @@
{
/* [941] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[232],
+ /* matcher indices */ &kMatcherIndices[234],
},
{
/* [942] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[233],
+ /* matcher indices */ &kMatcherIndices[235],
},
{
/* [943] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[234],
+ /* matcher indices */ &kMatcherIndices[236],
},
{
/* [944] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[235],
+ /* matcher indices */ &kMatcherIndices[237],
},
{
/* [945] */
@@ -7787,7 +7823,7 @@
{
/* [946] */
/* usage */ ParameterUsage::kTexture,
- /* matcher indices */ &kMatcherIndices[236],
+ /* matcher indices */ &kMatcherIndices[238],
},
{
/* [947] */
@@ -8119,78 +8155,83 @@
/* usage */ ParameterUsage::kNone,
/* matcher indices */ &kMatcherIndices[230],
},
+ {
+ /* [1013] */
+ /* usage */ ParameterUsage::kNone,
+ /* matcher indices */ &kMatcherIndices[106],
+ },
};
constexpr TemplateTypeInfo kTemplateTypes[] = {
{
/* [0] */
/* name */ "T",
- /* matcher index */ 67,
+ /* matcher index */ 68,
},
{
/* [1] */
/* name */ "C",
- /* matcher index */ 71,
+ /* matcher index */ 72,
},
{
/* [2] */
/* name */ "A",
- /* matcher index */ 71,
+ /* matcher index */ 72,
},
{
/* [3] */
/* name */ "L",
- /* matcher index */ 71,
+ /* matcher index */ 72,
},
{
/* [4] */
/* name */ "T",
- /* matcher index */ 67,
+ /* matcher index */ 68,
},
{
/* [5] */
/* name */ "C",
- /* matcher index */ 71,
+ /* matcher index */ 72,
},
{
/* [6] */
/* name */ "L",
- /* matcher index */ 71,
+ /* matcher index */ 72,
},
{
/* [7] */
/* name */ "T",
- /* matcher index */ 67,
+ /* matcher index */ 68,
},
{
/* [8] */
/* name */ "C",
- /* matcher index */ 71,
+ /* matcher index */ 72,
},
{
/* [9] */
/* name */ "S",
- /* matcher index */ 71,
+ /* matcher index */ 72,
},
{
/* [10] */
/* name */ "T",
- /* matcher index */ 63,
+ /* matcher index */ 64,
},
{
/* [11] */
/* name */ "U",
- /* matcher index */ 65,
+ /* matcher index */ 66,
},
{
/* [12] */
/* name */ "T",
- /* matcher index */ 67,
+ /* matcher index */ 68,
},
{
/* [13] */
/* name */ "L",
- /* matcher index */ 71,
+ /* matcher index */ 72,
},
{
/* [14] */
@@ -8200,7 +8241,7 @@
{
/* [15] */
/* name */ "U",
- /* matcher index */ 54,
+ /* matcher index */ 55,
},
{
/* [16] */
@@ -8210,7 +8251,7 @@
{
/* [17] */
/* name */ "U",
- /* matcher index */ 55,
+ /* matcher index */ 56,
},
{
/* [18] */
@@ -8220,7 +8261,7 @@
{
/* [19] */
/* name */ "U",
- /* matcher index */ 56,
+ /* matcher index */ 57,
},
{
/* [20] */
@@ -8230,7 +8271,7 @@
{
/* [21] */
/* name */ "U",
- /* matcher index */ 57,
+ /* matcher index */ 58,
},
{
/* [22] */
@@ -8240,12 +8281,12 @@
{
/* [23] */
/* name */ "U",
- /* matcher index */ 58,
+ /* matcher index */ 59,
},
{
/* [24] */
/* name */ "T",
- /* matcher index */ 59,
+ /* matcher index */ 60,
},
{
/* [25] */
@@ -8255,62 +8296,62 @@
{
/* [26] */
/* name */ "T",
- /* matcher index */ 71,
+ /* matcher index */ 72,
},
{
/* [27] */
/* name */ "T",
- /* matcher index */ 52,
+ /* matcher index */ 53,
},
{
/* [28] */
/* name */ "T",
- /* matcher index */ 60,
+ /* matcher index */ 61,
},
{
/* [29] */
/* name */ "T",
- /* matcher index */ 64,
+ /* matcher index */ 65,
},
{
/* [30] */
/* name */ "T",
- /* matcher index */ 66,
+ /* matcher index */ 67,
},
{
/* [31] */
/* name */ "T",
- /* matcher index */ 56,
+ /* matcher index */ 57,
},
{
/* [32] */
/* name */ "T",
- /* matcher index */ 57,
+ /* matcher index */ 58,
},
{
/* [33] */
/* name */ "T",
- /* matcher index */ 54,
+ /* matcher index */ 55,
},
{
/* [34] */
/* name */ "T",
- /* matcher index */ 55,
+ /* matcher index */ 56,
},
{
/* [35] */
/* name */ "T",
- /* matcher index */ 58,
+ /* matcher index */ 59,
},
{
/* [36] */
/* name */ "T",
- /* matcher index */ 53,
+ /* matcher index */ 54,
},
{
/* [37] */
/* name */ "T",
- /* matcher index */ 70,
+ /* matcher index */ 71,
},
};
@@ -8879,7 +8920,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[36],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[134],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -9515,7 +9556,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[36],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[106],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -9983,7 +10024,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[36],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[23],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -10499,7 +10540,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[37],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[178],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -10571,7 +10612,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[37],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[184],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -10643,7 +10684,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[37],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[190],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -10715,7 +10756,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[37],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[196],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -10787,7 +10828,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[37],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[202],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -10859,7 +10900,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[37],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[208],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -10931,7 +10972,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[37],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[214],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -11003,7 +11044,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[37],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[220],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -11075,7 +11116,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[37],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[226],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -11591,7 +11632,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[38],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[9],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -11627,7 +11668,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[38],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[105],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -11663,7 +11704,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[38],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[42],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -11699,7 +11740,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[38],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[1],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -11735,7 +11776,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[38],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ &kMatcherIndices[39],
/* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::Zero,
@@ -13751,7 +13792,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[38],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
@@ -13835,7 +13876,7 @@
/* num template numbers */ 0,
/* template types */ &kTemplateTypes[38],
/* template numbers */ &kTemplateNumbers[10],
- /* parameters */ &kParameters[1013],
+ /* parameters */ &kParameters[1014],
/* return matcher indices */ nullptr,
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline),
/* const eval */ nullptr,
@@ -14020,6 +14061,18 @@
/* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
/* const eval */ &ConstEval::OpLogicalOr,
},
+ {
+ /* [471] */
+ /* num parameters */ 1,
+ /* num template types */ 1,
+ /* num template numbers */ 0,
+ /* template types */ &kTemplateTypes[36],
+ /* template numbers */ &kTemplateNumbers[10],
+ /* parameters */ &kParameters[1013],
+ /* return matcher indices */ &kMatcherIndices[232],
+ /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+ /* const eval */ &ConstEval::Conv,
+ },
};
constexpr IntrinsicInfo kBuiltins[] = {
@@ -15284,6 +15337,12 @@
/* num overloads */ 6,
/* overloads */ &kOverloads[225],
},
+ {
+ /* [17] */
+ /* conv packedVec3<T : concrete_scalar>(vec3<T>) -> packedVec3<T> */
+ /* num overloads */ 1,
+ /* overloads */ &kOverloads[471],
+ },
};
// clang-format on
diff --git a/src/tint/resolver/intrinsic_table.inl.tmpl b/src/tint/resolver/intrinsic_table.inl.tmpl
index 92e7e31..4769a3c 100644
--- a/src/tint/resolver/intrinsic_table.inl.tmpl
+++ b/src/tint/resolver/intrinsic_table.inl.tmpl
@@ -221,7 +221,7 @@
{{- end }}
{{- if .DisplayName }}
- std::stringstream ss;
+ utils::StringStream ss;
ss{{range SplitDisplayName .DisplayName}} << {{.}}{{end}};
return ss.str();
{{- else if .TemplateParams }}
@@ -264,7 +264,7 @@
}
std::string {{$class}}::String(MatchState*) const {
- std::stringstream ss;
+ utils::StringStream ss;
// Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
// template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
ss
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 4292438..cd426f7 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -84,6 +84,7 @@
#include "src/tint/utils/reverse.h"
#include "src/tint/utils/scoped_assignment.h"
#include "src/tint/utils/string.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/transform.h"
#include "src/tint/utils/vector.h"
@@ -99,6 +100,7 @@
constexpr int64_t kMaxArrayElementCount = 65536;
constexpr uint32_t kMaxStatementDepth = 127;
+constexpr size_t kMaxNestDepthOfCompositeType = 255;
} // namespace
@@ -1697,7 +1699,7 @@
target_el_ty = target_arr_ty->ElemType();
}
if (auto* el_ty = ConcreteType(a->ElemType(), target_el_ty, source)) {
- return Array(source, source, el_ty, a->Count(), /* explicit_stride */ 0);
+ return Array(source, source, source, el_ty, a->Count(), /* explicit_stride */ 0);
}
return nullptr;
},
@@ -2010,8 +2012,12 @@
auto stage = args_stage; // The evaluation stage of the call
const constant::Value* value = nullptr; // The constant value for the call
+ if (stage == sem::EvaluationStage::kConstant && skip_const_eval_.Contains(expr)) {
+ stage = sem::EvaluationStage::kNotEvaluated;
+ }
if (stage == sem::EvaluationStage::kConstant) {
- if (auto r = const_eval_.ArrayOrStructCtor(ty, args)) {
+ auto els = utils::Transform(args, [&](auto* arg) { return arg->ConstantValue(); });
+ if (auto r = const_eval_.ArrayOrStructCtor(ty, std::move(els))) {
value = r.Get();
} else {
return nullptr;
@@ -2043,6 +2049,10 @@
[&](const type::F32*) { return ctor_or_conv(CtorConvIntrinsic::kF32, nullptr); },
[&](const type::Bool*) { return ctor_or_conv(CtorConvIntrinsic::kBool, nullptr); },
[&](const type::Vector* v) {
+ if (v->Packed()) {
+ TINT_ASSERT(Resolver, v->Width() == 3u);
+ return ctor_or_conv(CtorConvIntrinsic::kPackedVec3, v->type());
+ }
return ctor_or_conv(VectorCtorConvIntrinsic(v->Width()), v->type());
},
[&](const type::Matrix* m) {
@@ -2128,7 +2138,8 @@
}
return nullptr;
}
- auto* arr = Array(expr->source, expr->source, el_ty, el_count, /* explicit_stride */ 0);
+ auto* arr = Array(expr->source, expr->source, expr->source, el_ty, el_count,
+ /* explicit_stride */ 0);
if (!arr) {
return nullptr;
}
@@ -2445,7 +2456,8 @@
return nullptr;
}
- auto* out = Array(ast_el_ty->source, //
+ auto* out = Array(tmpl_ident->source, //
+ ast_el_ty->source, //
ast_count ? ast_count->source : ident->source, //
el_ty, el_count, explicit_stride);
if (!out) {
@@ -2570,6 +2582,24 @@
}
return tex;
};
+ auto packed_vec3_t = [&]() -> type::Vector* {
+ auto* tmpl_ident = templated_identifier(1);
+ if (TINT_UNLIKELY(!tmpl_ident)) {
+ return nullptr;
+ }
+ auto* el_ty = Type(tmpl_ident->arguments[0]);
+ if (TINT_UNLIKELY(!el_ty)) {
+ return nullptr;
+ }
+
+ if (TINT_UNLIKELY(!el_ty)) {
+ return nullptr;
+ }
+ if (TINT_UNLIKELY(!validator_.Vector(el_ty, ident->source))) {
+ return nullptr;
+ }
+ return b.create<type::Vector>(el_ty, 3u, true);
+ };
switch (builtin_ty) {
case builtin::Builtin::kBool:
@@ -2716,6 +2746,9 @@
return storage_texture(type::TextureDimension::k2dArray);
case builtin::Builtin::kTextureStorage3D:
return storage_texture(type::TextureDimension::k3d);
+ case builtin::Builtin::kPackedVec3: {
+ return packed_vec3_t();
+ }
case builtin::Builtin::kUndefined:
break;
}
@@ -2725,6 +2758,19 @@
return nullptr;
}
+size_t Resolver::NestDepth(const type::Type* ty) const {
+ return Switch(
+ ty, //
+ [](const type::Vector*) { return size_t{1}; },
+ [](const type::Matrix*) { return size_t{2}; },
+ [&](Default) {
+ if (auto d = nest_depth_.Get(ty)) {
+ return *d;
+ }
+ return size_t{0};
+ });
+}
+
void Resolver::CollectTextureSamplerPairs(
const sem::Builtin* builtin,
utils::VectorRef<const sem::ValueExpression*> args) const {
@@ -3057,7 +3103,7 @@
filtered.Push(str);
}
}
- std::ostringstream msg;
+ utils::StringStream msg;
utils::SuggestAlternatives(unresolved->name,
filtered.Slice().Reinterpret<char const* const>(), msg);
AddNote(msg.str(), expr->source);
@@ -3422,7 +3468,7 @@
if (rule != builtin::DiagnosticRule::kUndefined) {
validator_.DiagnosticFilters().Set(rule, control.severity);
} else {
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "unrecognized diagnostic rule '" << rule_name << "'\n";
utils::SuggestAlternatives(rule_name, builtin::kDiagnosticRuleStrings, ss);
AddWarning(ss.str(), control.rule_name->source);
@@ -3527,7 +3573,8 @@
return true;
}
-type::Array* Resolver::Array(const Source& el_source,
+type::Array* Resolver::Array(const Source& array_source,
+ const Source& el_source,
const Source& count_source,
const type::Type* el_ty,
const type::ArrayCount* el_count,
@@ -3541,7 +3588,7 @@
if (auto const_count = el_count->As<type::ConstantArrayCount>()) {
size = const_count->value * stride;
if (size > std::numeric_limits<uint32_t>::max()) {
- std::stringstream msg;
+ utils::StringStream msg;
msg << "array byte size (0x" << std::hex << size
<< ") must not exceed 0xffffffff bytes";
AddError(msg.str(), count_source);
@@ -3554,6 +3601,17 @@
el_ty, el_count, el_align, static_cast<uint32_t>(size), static_cast<uint32_t>(stride),
static_cast<uint32_t>(implicit_stride));
+ // Maximum nesting depth of composite types
+ // https://gpuweb.github.io/gpuweb/wgsl/#limits
+ const size_t nest_depth = 1 + NestDepth(el_ty);
+ if (nest_depth > kMaxNestDepthOfCompositeType) {
+ AddError("array has nesting depth of " + std::to_string(nest_depth) + ", maximum is " +
+ std::to_string(kMaxNestDepthOfCompositeType),
+ array_source);
+ return nullptr;
+ }
+ nest_depth_.Add(out, nest_depth);
+
if (!validator_.Array(out, el_source)) {
return nullptr;
}
@@ -3573,15 +3631,18 @@
}
sem::Struct* Resolver::Structure(const ast::Struct* str) {
+ auto struct_name = [&] { //
+ return builder_->Symbols().NameFor(str->name->symbol);
+ };
+
if (validator_.IsValidationEnabled(str->attributes,
ast::DisabledValidation::kIgnoreStructMemberLimit)) {
// Maximum number of members in a structure type
// https://gpuweb.github.io/gpuweb/wgsl/#limits
const size_t kMaxNumStructMembers = 16383;
if (str->members.Length() > kMaxNumStructMembers) {
- AddError("struct '" + builder_->Symbols().NameFor(str->name->symbol) + "' has " +
- std::to_string(str->members.Length()) + " members, maximum is " +
- std::to_string(kMaxNumStructMembers),
+ AddError("struct '" + struct_name() + "' has " + std::to_string(str->members.Length()) +
+ " members, maximum is " + std::to_string(kMaxNumStructMembers),
str->source);
return nullptr;
}
@@ -3607,6 +3668,7 @@
uint64_t struct_align = 1;
utils::Hashmap<Symbol, const ast::StructMember*, 8> member_map;
+ size_t members_nest_depth = 0;
for (auto* member : str->members) {
Mark(member);
Mark(member->name);
@@ -3623,6 +3685,8 @@
return nullptr;
}
+ members_nest_depth = std::max(members_nest_depth, NestDepth(type));
+
// validator_.Validate member type
if (!validator_.IsPlain(type)) {
AddError(sem_.TypeNameOf(type) + " cannot be used as the type of a structure member",
@@ -3762,7 +3826,7 @@
offset = utils::RoundUp(align, offset);
if (offset > std::numeric_limits<uint32_t>::max()) {
- std::stringstream msg;
+ utils::StringStream msg;
msg << "struct member offset (0x" << std::hex << offset << ") must not exceed 0x"
<< std::hex << std::numeric_limits<uint32_t>::max() << " bytes";
AddError(msg.str(), member->source);
@@ -3784,7 +3848,7 @@
struct_size = utils::RoundUp(struct_align, struct_size);
if (struct_size > std::numeric_limits<uint32_t>::max()) {
- std::stringstream msg;
+ utils::StringStream msg;
msg << "struct size (0x" << std::hex << struct_size << ") must not exceed 0xffffffff bytes";
AddError(msg.str(), str->source);
return nullptr;
@@ -3820,6 +3884,18 @@
return nullptr;
}
+ // Maximum nesting depth of composite types
+ // https://gpuweb.github.io/gpuweb/wgsl/#limits
+ const size_t nest_depth = 1 + members_nest_depth;
+ if (nest_depth > kMaxNestDepthOfCompositeType) {
+ AddError("struct '" + struct_name() + "' has nesting depth of " +
+ std::to_string(nest_depth) + ", maximum is " +
+ std::to_string(kMaxNestDepthOfCompositeType),
+ str->source);
+ return nullptr;
+ }
+ nest_depth_.Add(out, nest_depth);
+
return out;
}
@@ -4120,7 +4196,7 @@
if (decl &&
!ApplyAddressSpaceUsageToType(
address_space, const_cast<type::Type*>(member->Type()), decl->type->source)) {
- std::stringstream err;
+ utils::StringStream err;
err << "while analyzing structure member " << sem_.TypeNameOf(str) << "."
<< builder_->Symbols().NameFor(member->Name());
AddNote(err.str(), member->Source());
@@ -4151,7 +4227,7 @@
}
if (builtin::IsHostShareable(address_space) && !validator_.IsHostShareable(ty)) {
- std::stringstream err;
+ utils::StringStream err;
err << "Type '" << sem_.TypeNameOf(ty) << "' cannot be used in address space '"
<< address_space << "' as it is non-host-shareable";
AddError(err.str(), usage);
@@ -4176,7 +4252,7 @@
return false;
}
} else {
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "attribute is not valid for " << use;
AddError(ss.str(), attr->source);
return false;
diff --git a/src/tint/resolver/resolver.h b/src/tint/resolver/resolver.h
index 72f9e8f..fff7506 100644
--- a/src/tint/resolver/resolver.h
+++ b/src/tint/resolver/resolver.h
@@ -349,6 +349,7 @@
/// Builds and returns the semantic information for an array.
/// @returns the semantic Array information, or nullptr if an error is raised.
+ /// @param array_source the source of the array
/// @param el_source the source of the array element, or the array if the array does not have a
/// locally-declared element AST node.
/// @param count_source the source of the array count, or the array if the array does not have a
@@ -356,7 +357,8 @@
/// @param el_ty the Array element type
/// @param el_count the number of elements in the array.
/// @param explicit_stride the explicit byte stride of the array. Zero means implicit stride.
- type::Array* Array(const Source& el_source,
+ type::Array* Array(const Source& array_source,
+ const Source& el_source,
const Source& count_source,
const type::Type* el_ty,
const type::ArrayCount* el_count,
@@ -496,6 +498,10 @@
/// @note: Will raise an ICE if @p symbol is not a builtin type.
type::Type* BuiltinType(builtin::Builtin builtin_ty, const ast::Identifier* ident);
+ /// @returns the nesting depth of @ty as defined in
+ /// https://gpuweb.github.io/gpuweb/wgsl/#composite-types
+ size_t NestDepth(const type::Type* ty) const;
+
// ArrayConstructorSig represents a unique array constructor signature.
// It is a tuple of the array type, number of arguments provided and earliest evaluation stage.
using ArrayConstructorSig =
@@ -566,6 +572,7 @@
logical_binary_lhs_to_parent_;
utils::Hashset<const ast::Expression*, 8> skip_const_eval_;
IdentifierResolveHint identifier_resolve_hint_;
+ utils::Hashmap<const type::Type*, size_t, 8> nest_depth_;
};
} // namespace tint::resolver
diff --git a/src/tint/resolver/resolver_test.cc b/src/tint/resolver/resolver_test.cc
index 25155ff..a601ef0 100644
--- a/src/tint/resolver/resolver_test.cc
+++ b/src/tint/resolver/resolver_test.cc
@@ -46,6 +46,7 @@
#include "src/tint/type/reference.h"
#include "src/tint/type/sampled_texture.h"
#include "src/tint/type/texture_dimension.h"
+#include "src/tint/utils/string_stream.h"
using ::testing::ElementsAre;
using ::testing::HasSubstr;
@@ -1647,7 +1648,7 @@
ast::Type rhs_type = params.create_rhs_type(*this);
auto* result_type = params.create_result_type(*this);
- std::stringstream ss;
+ utils::StringStream ss;
ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type);
SCOPED_TRACE(ss.str());
@@ -1679,7 +1680,7 @@
ast::Type lhs_type = create_lhs_type(*this);
ast::Type rhs_type = create_rhs_type(*this);
- std::stringstream ss;
+ utils::StringStream ss;
ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type);
ss << ", After aliasing: " << FriendlyName(lhs_type) << " " << params.op << " "
@@ -1728,7 +1729,7 @@
ast::Type lhs_type = lhs_create_type_func(*this);
ast::Type rhs_type = rhs_create_type_func(*this);
- std::stringstream ss;
+ utils::StringStream ss;
ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type);
SCOPED_TRACE(ss.str());
@@ -2434,5 +2435,195 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
+size_t kMaxNestDepthOfCompositeType = 255;
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_Structs_Valid) {
+ auto* s = Structure("S", utils::Vector{Member("m", ty.i32())});
+ size_t depth = 1; // Depth of struct
+ size_t iterations = kMaxNestDepthOfCompositeType - depth;
+ for (size_t i = 0; i < iterations; ++i) {
+ s = Structure("S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
+ }
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_Structs_Invalid) {
+ auto* s = Structure("S", utils::Vector{Member("m", ty.i32())});
+ size_t depth = 1; // Depth of struct
+ size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
+ for (size_t i = 0; i < iterations; ++i) {
+ auto source = i == iterations - 1 ? Source{{12, 34}} : Source{{0, i}};
+ s = Structure(source, "S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
+ }
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: struct 'S254' has nesting depth of 256, maximum is 255");
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsWithVector_Valid) {
+ auto* s = Structure("S", utils::Vector{Member("m", ty.vec3<i32>())});
+ size_t depth = 2; // Despth of struct + vector
+ size_t iterations = kMaxNestDepthOfCompositeType - depth;
+ for (size_t i = 0; i < iterations; ++i) {
+ s = Structure("S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
+ }
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsWithVector_Invalid) {
+ auto* s = Structure("S", utils::Vector{Member("m", ty.vec3<i32>())});
+ size_t depth = 2; // Despth of struct + vector
+ size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
+ for (size_t i = 0; i < iterations; ++i) {
+ auto source = i == iterations - 1 ? Source{{12, 34}} : Source{{0, i}};
+ s = Structure(source, "S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
+ }
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: struct 'S253' has nesting depth of 256, maximum is 255");
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsWithMatrix_Valid) {
+ auto* s = Structure("S", utils::Vector{Member("m", ty.mat3x3<f32>())});
+ size_t depth = 3; // Depth of struct + matrix
+ size_t iterations = kMaxNestDepthOfCompositeType - depth;
+ for (size_t i = 0; i < iterations; ++i) {
+ s = Structure("S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
+ }
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsWithMatrix_Invalid) {
+ auto* s = Structure("S", utils::Vector{Member("m", ty.mat3x3<f32>())});
+ size_t depth = 3; // Depth of struct + matrix
+ size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
+ for (size_t i = 0; i < iterations; ++i) {
+ auto source = i == iterations - 1 ? Source{{12, 34}} : Source{{0, i}};
+ s = Structure(source, "S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
+ }
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: struct 'S252' has nesting depth of 256, maximum is 255");
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_Arrays_Valid) {
+ auto a = ty.array(ty.i32(), 10_u);
+ size_t depth = 1; // Depth of array
+ size_t iterations = kMaxNestDepthOfCompositeType - depth;
+ for (size_t i = 0; i < iterations; ++i) {
+ a = ty.array(a, 1_u);
+ }
+ Alias("a", a);
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_Arrays_Invalid) {
+ auto a = ty.array(Source{{99, 88}}, ty.i32(), 10_u);
+ size_t depth = 1; // Depth of array
+ size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
+ for (size_t i = 0; i < iterations; ++i) {
+ auto source = (i == iterations - 1) ? Source{{12, 34}} : Source{{0, i}};
+ a = ty.array(source, a, 1_u);
+ }
+ Alias("a", a);
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: array has nesting depth of 256, maximum is 255");
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfVector_Valid) {
+ auto a = ty.array(ty.vec3<i32>(), 10_u);
+ size_t depth = 2; // Depth of array + vector
+ size_t iterations = kMaxNestDepthOfCompositeType - depth;
+ for (size_t i = 0; i < iterations; ++i) {
+ a = ty.array(a, 1_u);
+ }
+ Alias("a", a);
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfVector_Invalid) {
+ auto a = ty.array(Source{{99, 88}}, ty.vec3<i32>(), 10_u);
+ size_t depth = 2; // Depth of array + vector
+ size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
+ for (size_t i = 0; i < iterations; ++i) {
+ auto source = (i == iterations - 1) ? Source{{12, 34}} : Source{{0, i}};
+ a = ty.array(source, a, 1_u);
+ }
+ Alias("a", a);
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: array has nesting depth of 256, maximum is 255");
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfMatrix_Valid) {
+ auto a = ty.array(ty.mat3x3<f32>(), 10_u);
+ size_t depth = 3; // Depth of array + matrix
+ size_t iterations = kMaxNestDepthOfCompositeType - depth;
+ for (size_t i = 0; i < iterations; ++i) {
+ a = ty.array(a, 1_u);
+ }
+ Alias("a", a);
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfMatrix_Invalid) {
+ auto a = ty.array(ty.mat3x3<f32>(), 10_u);
+ size_t depth = 3; // Depth of array + matrix
+ size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
+ for (size_t i = 0; i < iterations; ++i) {
+ auto source = (i == iterations - 1) ? Source{{12, 34}} : Source{{0, i}};
+ a = ty.array(source, a, 1_u);
+ }
+ Alias("a", a);
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: array has nesting depth of 256, maximum is 255");
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsOfArray_Valid) {
+ auto a = ty.array(ty.mat3x3<f32>(), 10_u);
+ auto* s = Structure("S", utils::Vector{Member("m", a)});
+ size_t depth = 4; // Depth of struct + array + matrix
+ size_t iterations = kMaxNestDepthOfCompositeType - depth;
+ for (size_t i = 0; i < iterations; ++i) {
+ s = Structure("S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
+ }
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsOfArray_Invalid) {
+ auto a = ty.array(ty.mat3x3<f32>(), 10_u);
+ auto* s = Structure("S", utils::Vector{Member("m", a)});
+ size_t depth = 4; // Depth of struct + array + matrix
+ size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
+ for (size_t i = 0; i < iterations; ++i) {
+ auto source = i == iterations - 1 ? Source{{12, 34}} : Source{{0, i}};
+ s = Structure(source, "S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
+ }
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: struct 'S251' has nesting depth of 256, maximum is 255");
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfStruct_Valid) {
+ auto* s = Structure("S", utils::Vector{Member("m", ty.mat3x3<f32>())});
+ auto a = ty.array(ty.Of(s), 10_u);
+ size_t depth = 4; // Depth of array + struct + matrix
+ size_t iterations = kMaxNestDepthOfCompositeType - depth;
+ for (size_t i = 0; i < iterations; ++i) {
+ a = ty.array(a, 1_u);
+ }
+ Alias("a", a);
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfStruct_Invalid) {
+ auto* s = Structure("S", utils::Vector{Member("m", ty.mat3x3<f32>())});
+ auto a = ty.array(ty.Of(s), 10_u);
+ size_t depth = 4; // Depth of array + struct + matrix
+ size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
+ for (size_t i = 0; i < iterations; ++i) {
+ auto source = (i == iterations - 1) ? Source{{12, 34}} : Source{{0, i}};
+ a = ty.array(source, a, 1_u);
+ }
+ Alias("a", a);
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: array has nesting depth of 256, maximum is 255");
+}
+
} // namespace
} // namespace tint::resolver
diff --git a/src/tint/resolver/uniformity.cc b/src/tint/resolver/uniformity.cc
index 37fba4c..93402b6 100644
--- a/src/tint/resolver/uniformity.cc
+++ b/src/tint/resolver/uniformity.cc
@@ -40,6 +40,7 @@
#include "src/tint/sem/while_statement.h"
#include "src/tint/utils/block_allocator.h"
#include "src/tint/utils/map.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/unique_vector.h"
// Set to `1` to dump the uniformity graph for each function in graphviz format.
@@ -1352,14 +1353,14 @@
// To determine if we're dereferencing a partial pointer, unwrap *&
// chains; if the final expression is an identifier, see if it's a
// partial pointer. If it's not an identifier, then it must be an
- // index/accessor expression, and thus a partial pointer.
+ // index/member accessor expression, and thus a partial pointer.
auto* e = UnwrapIndirectAndAddressOfChain(u);
if (auto* var_user = sem_.Get<sem::VariableUser>(e)) {
if (current_function_->partial_ptrs.Contains(var_user->Variable())) {
return true;
}
} else {
- TINT_ASSERT(Resolver, e->Is<ast::IndexAccessorExpression>());
+ TINT_ASSERT(Resolver, e->Is<ast::AccessorExpression>());
return true;
}
return false;
@@ -1778,7 +1779,7 @@
non_uniform_source->ast,
[&](const ast::IdentifierExpression* ident) {
auto* var = sem_.GetVal(ident)->UnwrapLoad()->As<sem::VariableUser>()->Variable();
- std::ostringstream ss;
+ utils::StringStream ss;
if (auto* param = var->As<sem::Parameter>()) {
auto* func = param->Owner()->As<sem::Function>();
ss << param_type(param) << "'" << NameFor(ident) << "' of '" << NameFor(func)
@@ -1791,7 +1792,7 @@
},
[&](const ast::Variable* v) {
auto* var = sem_.Get(v);
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "reading from " << var_type(var) << "'" << NameFor(v)
<< "' may result in a non-uniform value";
diagnostics_.add_note(diag::System::Resolver, ss.str(), v->source);
@@ -1808,7 +1809,7 @@
case Node::kFunctionCallArgumentContents: {
auto* arg = c->args[non_uniform_source->arg_index];
auto* var = sem_.GetVal(arg)->RootIdentifier();
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "reading from " << var_type(var) << "'" << NameFor(var)
<< "' may result in a non-uniform value";
diagnostics_.add_note(diag::System::Resolver, ss.str(),
@@ -1895,7 +1896,7 @@
// Show the place where the non-uniform argument was passed.
// If this is a builtin, this will be the trigger location for the failure.
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "possibly non-uniform value passed" << (is_value ? "" : " via pointer")
<< " here";
report(call->args[cause->arg_index]->source, ss.str(), /* note */ user_func != nullptr);
@@ -1907,7 +1908,7 @@
{
// Show a builtin was reachable from this call (which may be the call itself).
// This will be the trigger location for the failure.
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "'" << NameFor(builtin_call->target)
<< "' must only be called from uniform control flow";
report(builtin_call->source, ss.str(), /* note */ false);
@@ -1915,7 +1916,7 @@
if (builtin_call != call) {
// The call was to a user function, so show that call too.
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "called ";
if (target->As<sem::Function>() != SemCall(builtin_call)->Stmt()->Function()) {
ss << "indirectly ";
diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc
index fec74b3..0a79058 100644
--- a/src/tint/resolver/uniformity_test.cc
+++ b/src/tint/resolver/uniformity_test.cc
@@ -21,6 +21,7 @@
#include "src/tint/program_builder.h"
#include "src/tint/reader/wgsl/parser.h"
#include "src/tint/resolver/uniformity.h"
+#include "src/tint/utils/string_stream.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -6374,6 +6375,43 @@
)");
}
+TEST_F(UniformityAnalysisTest, StructMember_MemberBecomesUniformThroughPartialPointer) {
+ // For aggregate types, we conservatively consider them to be non-uniform once they
+ // become non-uniform. Test that after assigning a uniform value to a member, that member is
+ // still considered to be non-uniform.
+ std::string src = R"(
+struct S {
+ a : i32,
+ b : i32,
+}
+@group(0) @binding(0) var<storage, read_write> rw : i32;
+
+fn foo() {
+ var s : S;
+ s.a = rw;
+ *&s.a = 0;
+ if (s.a == 0) {
+ workgroupBarrier();
+ }
+}
+)";
+
+ RunTest(src, false);
+ EXPECT_EQ(error_,
+ R"(test:13:5 error: 'workgroupBarrier' must only be called from uniform control flow
+ workgroupBarrier();
+ ^^^^^^^^^^^^^^^^
+
+test:12:3 note: control flow depends on possibly non-uniform value
+ if (s.a == 0) {
+ ^^
+
+test:10:9 note: reading from read_write storage buffer 'rw' may result in a non-uniform value
+ s.a = rw;
+ ^^
+)");
+}
+
TEST_F(UniformityAnalysisTest, StructMember_MemberBecomesUniformThroughCapturedPartialPointer) {
// For aggregate types, we conservatively consider them to be non-uniform once they
// become non-uniform. Test that after assigning a uniform value to a member, that member is
@@ -7890,7 +7928,7 @@
TEST_P(UniformityAnalysisDiagnosticFilterTest, Directive) {
auto& param = GetParam();
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "diagnostic(" << param << ", derivative_uniformity);"
<< R"(
@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
@@ -7909,7 +7947,7 @@
if (param == builtin::DiagnosticSeverity::kOff) {
EXPECT_TRUE(error_.empty());
} else {
- std::ostringstream err;
+ utils::StringStream err;
err << ToStr(param) << ": 'textureSample' must only be called";
EXPECT_THAT(error_, ::testing::HasSubstr(err.str()));
}
@@ -7917,7 +7955,7 @@
TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnFunction) {
auto& param = GetParam();
- std::ostringstream ss;
+ utils::StringStream ss;
ss << R"(
@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
@group(0) @binding(1) var t : texture_2d<f32>;
@@ -7936,7 +7974,7 @@
if (param == builtin::DiagnosticSeverity::kOff) {
EXPECT_TRUE(error_.empty());
} else {
- std::ostringstream err;
+ utils::StringStream err;
err << ToStr(param) << ": 'textureSample' must only be called";
EXPECT_THAT(error_, ::testing::HasSubstr(err.str()));
}
@@ -7944,7 +7982,7 @@
TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnBlock) {
auto& param = GetParam();
- std::ostringstream ss;
+ utils::StringStream ss;
ss << R"(
@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
@group(0) @binding(1) var t : texture_2d<f32>;
@@ -7962,7 +8000,7 @@
if (param == builtin::DiagnosticSeverity::kOff) {
EXPECT_TRUE(error_.empty());
} else {
- std::ostringstream err;
+ utils::StringStream err;
err << ToStr(param) << ": 'textureSample' must only be called";
EXPECT_THAT(error_, ::testing::HasSubstr(err.str()));
}
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
index b272b15..f8f4c4d 100644
--- a/src/tint/resolver/validator.cc
+++ b/src/tint/resolver/validator.cc
@@ -71,11 +71,15 @@
#include "src/tint/utils/reverse.h"
#include "src/tint/utils/scoped_assignment.h"
#include "src/tint/utils/string.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/utils/transform.h"
namespace tint::resolver {
namespace {
+constexpr size_t kMaxFunctionParameters = 255;
+constexpr size_t kMaxSwitchCaseSelectors = 16383;
+
bool IsValidStorageTextureDimension(type::TextureDimension dim) {
switch (dim) {
case type::TextureDimension::k1d:
@@ -377,7 +381,7 @@
// Value type has to match storage type
if (storage_ty != value_type) {
- std::stringstream s;
+ utils::StringStream s;
s << "cannot initialize " << v->Kind() << " of type '" << sem_.TypeNameOf(storage_ty)
<< "' with value of type '" << sem_.TypeNameOf(initializer_ty) << "'";
AddError(s.str(), v->source);
@@ -467,7 +471,9 @@
}
// Validate that member is at a valid byte offset
- if (m->Offset() % required_align != 0) {
+ if (m->Offset() % required_align != 0 &&
+ !enabled_extensions_.Contains(
+ builtin::Extension::kChromiumInternalRelaxedUniformLayout)) {
AddError("the offset of a struct member of type '" +
m->Type()->UnwrapRef()->FriendlyName(symbols_) +
"' in address space '" + utils::ToString(address_space) +
@@ -493,7 +499,9 @@
auto* const prev_member = (i == 0) ? nullptr : str->Members()[i - 1];
if (prev_member && is_uniform_struct(prev_member->Type())) {
const uint32_t prev_to_curr_offset = m->Offset() - prev_member->Offset();
- if (prev_to_curr_offset % 16 != 0) {
+ if (prev_to_curr_offset % 16 != 0 &&
+ !enabled_extensions_.Contains(
+ builtin::Extension::kChromiumInternalRelaxedUniformLayout)) {
AddError(
"uniform storage requires that the number of bytes between the "
"start of the previous member of type struct and the current "
@@ -526,7 +534,9 @@
return false;
}
- if (address_space == builtin::AddressSpace::kUniform) {
+ if (address_space == builtin::AddressSpace::kUniform &&
+ !enabled_extensions_.Contains(
+ builtin::Extension::kChromiumInternalRelaxedUniformLayout)) {
// We already validated that this array member is itself aligned to 16 bytes above, so
// we only need to validate that stride is a multiple of 16 bytes.
if (arr->Stride() % 16 != 0) {
@@ -833,7 +843,7 @@
break;
}
if (!ok) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << "function parameter of pointer type cannot be in '" << sc
<< "' address space";
AddError(ss.str(), decl->source);
@@ -861,7 +871,7 @@
ast::PipelineStage stage,
const bool is_input) const {
auto* type = storage_ty->UnwrapRef();
- std::stringstream stage_name;
+ utils::StringStream stage_name;
stage_name << stage;
bool is_stage_mismatch = false;
bool is_output = !is_input;
@@ -874,7 +884,7 @@
is_stage_mismatch = true;
}
if (!(type->is_float_vector() && type->As<type::Vector>()->Width() == 4)) {
- std::stringstream err;
+ utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'vec4<f32>'";
AddError(err.str(), attr->source);
return false;
@@ -889,7 +899,7 @@
is_stage_mismatch = true;
}
if (!(type->is_unsigned_integer_vector() && type->As<type::Vector>()->Width() == 3)) {
- std::stringstream err;
+ utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'vec3<u32>'";
AddError(err.str(), attr->source);
return false;
@@ -901,7 +911,7 @@
is_stage_mismatch = true;
}
if (!type->Is<type::F32>()) {
- std::stringstream err;
+ utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'f32'";
AddError(err.str(), attr->source);
return false;
@@ -913,7 +923,7 @@
is_stage_mismatch = true;
}
if (!type->Is<type::Bool>()) {
- std::stringstream err;
+ utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'bool'";
AddError(err.str(), attr->source);
return false;
@@ -925,7 +935,7 @@
is_stage_mismatch = true;
}
if (!type->Is<type::U32>()) {
- std::stringstream err;
+ utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'u32'";
AddError(err.str(), attr->source);
return false;
@@ -938,7 +948,7 @@
is_stage_mismatch = true;
}
if (!type->Is<type::U32>()) {
- std::stringstream err;
+ utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'u32'";
AddError(err.str(), attr->source);
return false;
@@ -949,7 +959,7 @@
is_stage_mismatch = true;
}
if (!type->Is<type::U32>()) {
- std::stringstream err;
+ utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'u32'";
AddError(err.str(), attr->source);
return false;
@@ -961,7 +971,7 @@
is_stage_mismatch = true;
}
if (!type->Is<type::U32>()) {
- std::stringstream err;
+ utils::StringStream err;
err << "store type of @builtin(" << builtin << ") must be 'u32'";
AddError(err.str(), attr->source);
return false;
@@ -972,7 +982,7 @@
}
if (is_stage_mismatch) {
- std::stringstream err;
+ utils::StringStream err;
err << "@builtin(" << builtin << ") cannot be used in "
<< (is_input ? "input of " : "output of ") << stage_name.str() << " pipeline stage";
AddError(err.str(), attr->source);
@@ -1040,8 +1050,10 @@
}
}
- if (decl->params.Length() > 255) {
- AddError("functions may declare at most 255 parameters", decl->source);
+ if (decl->params.Length() > kMaxFunctionParameters) {
+ AddError("function declares " + std::to_string(decl->params.Length()) +
+ " parameters, maximum is " + std::to_string(kMaxFunctionParameters),
+ decl->source);
return false;
}
@@ -1145,7 +1157,7 @@
pipeline_io_attribute = attr;
if (builtins.Contains(builtin)) {
- std::stringstream err;
+ utils::StringStream err;
err << "@builtin(" << builtin << ") appears multiple times as pipeline "
<< (param_or_ret == ParamOrRetType::kParameter ? "input" : "output");
AddError(err.str(), decl->source);
@@ -1938,7 +1950,7 @@
if (stage != ast::PipelineStage::kCompute) {
for (auto* var : func->DirectlyReferencedGlobals()) {
if (var->AddressSpace() == builtin::AddressSpace::kWorkgroup) {
- std::stringstream stage_name;
+ utils::StringStream stage_name;
stage_name << stage;
for (auto* user : var->Users()) {
if (func == user->Stmt()->Function()) {
@@ -1962,7 +1974,7 @@
for (auto* builtin : func->DirectlyCalledBuiltins()) {
if (!builtin->SupportedStages().Contains(stage)) {
auto* call = func->FindDirectCallTo(builtin);
- std::stringstream err;
+ utils::StringStream err;
err << "built-in cannot be used by " << stage << " pipeline stage";
AddError(err.str(),
call ? call->Declaration()->source : func->Declaration()->source);
@@ -1976,7 +1988,7 @@
auto check_no_discards = [&](const sem::Function* func, const sem::Function* entry_point) {
if (auto* discard = func->DiscardStatement()) {
auto stage = entry_point->Declaration()->PipelineStage();
- std::stringstream err;
+ utils::StringStream err;
err << "discard statement cannot be used in " << stage << " pipeline stage";
AddError(err.str(), discard->Declaration()->source);
backtrace(func, entry_point);
@@ -2272,7 +2284,7 @@
}
if (!locations.Add(location)) {
- std::stringstream err;
+ utils::StringStream err;
err << "@location(" << location << ") appears multiple times";
AddError(err.str(), loc_attr->source);
return false;
@@ -2305,6 +2317,13 @@
}
bool Validator::SwitchStatement(const ast::SwitchStatement* s) {
+ if (s->body.Length() > kMaxSwitchCaseSelectors) {
+ AddError("switch statement has " + std::to_string(s->body.Length()) +
+ " case selectors, max is " + std::to_string(kMaxSwitchCaseSelectors),
+ s->source);
+ return false;
+ }
+
auto* cond_ty = sem_.TypeOf(s->condition);
if (!cond_ty->is_integer_scalar()) {
AddError("switch statement selector expression must be of a scalar integer type",
@@ -2525,12 +2544,12 @@
auto diag_added = diagnostics.Add(dc->rule_name->symbol, dc);
if (!diag_added && (*diag_added.value)->severity != dc->severity) {
{
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "conflicting diagnostic " << use;
AddError(ss.str(), dc->rule_name->source);
}
{
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "severity of '" << symbols_.NameFor(dc->rule_name->symbol) << "' set to '"
<< dc->severity << "' here";
AddNote(ss.str(), (*diag_added.value)->rule_name->source);
diff --git a/src/tint/resolver/value_constructor_validation_test.cc b/src/tint/resolver/value_constructor_validation_test.cc
index 8ab1cab..21603fe 100644
--- a/src/tint/resolver/value_constructor_validation_test.cc
+++ b/src/tint/resolver/value_constructor_validation_test.cc
@@ -17,6 +17,7 @@
#include "src/tint/sem/value_constructor.h"
#include "src/tint/sem/value_conversion.h"
#include "src/tint/type/reference.h"
+#include "src/tint/utils/string_stream.h"
using namespace tint::number_suffixes; // NOLINT
@@ -354,7 +355,7 @@
auto rhs_type = params.rhs_type(*this);
auto* rhs_value_expr = params.rhs_value_expr(*this, 0);
- std::stringstream ss;
+ utils::StringStream ss;
ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "("
<< FriendlyName(rhs_type) << "(<rhs value expr>))";
SCOPED_TRACE(ss.str());
@@ -447,7 +448,7 @@
auto rhs_type = rhs_params.ast(*this);
auto* rhs_value_expr = rhs_params.expr_from_double(*this, 0);
- std::stringstream ss;
+ utils::StringStream ss;
ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "("
<< FriendlyName(rhs_type) << "(<rhs value expr>))";
SCOPED_TRACE(ss.str());
@@ -2414,7 +2415,7 @@
Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name();
- std::stringstream args_tys;
+ utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns - 1; i++) {
ast::Type vec_type = param.create_column_ast_type(*this);
@@ -2443,7 +2444,7 @@
Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name();
- std::stringstream args_tys;
+ utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns * param.rows - 1; i++) {
args.Push(Call(param.create_element_ast_type(*this)));
@@ -2471,7 +2472,7 @@
Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name();
- std::stringstream args_tys;
+ utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns + 1; i++) {
ast::Type vec_type = param.create_column_ast_type(*this);
@@ -2500,7 +2501,7 @@
Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name();
- std::stringstream args_tys;
+ utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns * param.rows + 1; i++) {
args.Push(Call(param.create_element_ast_type(*this)));
@@ -2527,7 +2528,7 @@
Enable(builtin::Extension::kF16);
- std::stringstream args_tys;
+ utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) {
auto vec_type = ty.vec<u32>(param.rows);
@@ -2555,7 +2556,7 @@
Enable(builtin::Extension::kF16);
- std::stringstream args_tys;
+ utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) {
args.Push(Expr(1_u));
@@ -2588,7 +2589,7 @@
Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name();
- std::stringstream args_tys;
+ utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) {
ast::Type valid_vec_type = param.create_column_ast_type(*this);
@@ -2626,7 +2627,7 @@
Enable(builtin::Extension::kF16);
const std::string element_type_name = param.get_element_type_name();
- std::stringstream args_tys;
+ utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 8> args;
for (uint32_t i = 0; i < param.columns; i++) {
ast::Type valid_vec_type = param.create_column_ast_type(*this);
@@ -2715,7 +2716,7 @@
auto* elem_type_alias = Alias("ElemType", param.create_element_ast_type(*this));
- std::stringstream args_tys;
+ utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 4> args;
for (uint32_t i = 0; i < param.columns; i++) {
auto vec_type = ty.vec(ty.u32(), param.rows);
@@ -2797,7 +2798,7 @@
ast::Type matrix_type = param.create_mat_ast_type(*this);
auto* u32_type_alias = Alias("UnsignedInt", ty.u32());
- std::stringstream args_tys;
+ utils::StringStream args_tys;
utils::Vector<const ast::Expression*, 4> args;
for (uint32_t i = 0; i < param.columns; i++) {
auto vec_type = ty.vec(ty.Of(u32_type_alias), param.rows);
@@ -2874,7 +2875,7 @@
Enable(builtin::Extension::kF16);
- std::stringstream err;
+ utils::StringStream err;
err << "12:34 error: no matching constructor for mat" << param.columns << "x" << param.rows
<< "(";
@@ -2905,7 +2906,7 @@
Enable(builtin::Extension::kF16);
- std::stringstream err;
+ utils::StringStream err;
err << "12:34 error: no matching constructor for mat" << param.columns << "x" << param.rows
<< "(";
@@ -3073,7 +3074,7 @@
auto* tc = Call(ty.Of(s), values);
WrapInFunction(tc);
- std::stringstream err;
+ utils::StringStream err;
err << "error: type in structure constructor does not match struct member ";
err << "type: expected '" << str_params.name() << "', found '" << ctor_params.name() << "'";
EXPECT_FALSE(r()->Resolve());
diff --git a/src/tint/transform/builtin_polyfill.cc b/src/tint/transform/builtin_polyfill.cc
index 606c6ce..259eb11 100644
--- a/src/tint/transform/builtin_polyfill.cc
+++ b/src/tint/transform/builtin_polyfill.cc
@@ -582,6 +582,33 @@
return name;
}
+ /// Builds the polyfill function for the `reflect` builtin
+ /// @param ty the parameter and return type for the function
+ /// @return the polyfill function name
+ Symbol reflect(const type::Type* ty) {
+ auto name = b.Symbols().New("tint_reflect");
+
+ // WGSL polyfill function:
+ // fn tint_reflect(e1 : T, e2 : T) -> T {
+ // let factor = (-2.0 * dot(e1, e2));
+ // return (e1 + (factor * e2));
+ // }
+ // Using -2.0 instead of 2.0 in factor to prevent the optimization that cause wrong result.
+ // See https://crbug.com/tint/1798 for more details.
+ auto body = utils::Vector{
+ b.Decl(b.Let("factor", b.Mul(-2.0_a, b.Call("dot", "e1", "e2")))),
+ b.Return(b.Add("e1", b.Mul("factor", "e2"))),
+ };
+ b.Func(name,
+ utils::Vector{
+ b.Param("e1", T(ty)),
+ b.Param("e2", T(ty)),
+ },
+ T(ty), body);
+
+ return name;
+ }
+
/// Builds the polyfill function for the `saturate` builtin
/// @param ty the parameter and return type for the function
/// @return the polyfill function name
@@ -1007,6 +1034,18 @@
builtin, [&] { return s.insertBits(builtin->ReturnType()); });
}
break;
+ case sem::BuiltinType::kReflect:
+ // Only polyfill for vec2<f32>. See https://crbug.com/tint/1798 for more
+ // details.
+ if (polyfill.reflect_vec2_f32) {
+ auto& sig = builtin->Signature();
+ auto* vec = sig.return_type->As<type::Vector>();
+ if (vec && vec->Width() == 2 && vec->type()->Is<type::F32>()) {
+ fn = builtin_polyfills.GetOrCreate(
+ builtin, [&] { return s.reflect(builtin->ReturnType()); });
+ }
+ }
+ break;
case sem::BuiltinType::kSaturate:
if (polyfill.saturate) {
fn = builtin_polyfills.GetOrCreate(
diff --git a/src/tint/transform/builtin_polyfill.h b/src/tint/transform/builtin_polyfill.h
index 521940c..b070248 100644
--- a/src/tint/transform/builtin_polyfill.h
+++ b/src/tint/transform/builtin_polyfill.h
@@ -70,6 +70,8 @@
bool int_div_mod = false;
/// Should float modulos be polyfilled to emit a precise modulo operation as per the spec?
bool precise_float_mod = false;
+ /// Should `reflect()` be polyfilled for vec2<f32>?
+ bool reflect_vec2_f32 = false;
/// Should `saturate()` be polyfilled?
bool saturate = false;
/// Should `sign()` be polyfilled for integer types?
diff --git a/src/tint/transform/builtin_polyfill_test.cc b/src/tint/transform/builtin_polyfill_test.cc
index 09d17b8..8c0d787 100644
--- a/src/tint/transform/builtin_polyfill_test.cc
+++ b/src/tint/transform/builtin_polyfill_test.cc
@@ -3045,6 +3045,177 @@
}
////////////////////////////////////////////////////////////////////////////////
+// reflect for vec2<f32>
+////////////////////////////////////////////////////////////////////////////////
+DataMap polyfillReflectVec2F32() {
+ BuiltinPolyfill::Builtins builtins;
+ builtins.reflect_vec2_f32 = true;
+ DataMap data;
+ data.Add<BuiltinPolyfill::Config>(builtins);
+ return data;
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunReflect_vec2_f32) {
+ auto* src = R"(
+fn f() {
+ let e1 = vec2<f32>(1.0f);
+ let e2 = vec2<f32>(1.0f);
+ let x = reflect(e1, e2);
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+ EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillReflectVec2F32()));
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunReflect_vec2_f16) {
+ auto* src = R"(
+enable f16;
+
+fn f() {
+ let e1 = vec2<f16>(1.0h);
+ let e2 = vec2<f16>(1.0h);
+ let x = reflect(e1, e2);
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillReflectVec2F32()));
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunReflect_vec3_f32) {
+ auto* src = R"(
+fn f() {
+ let e1 = vec3<f32>(1.0f);
+ let e2 = vec3<f32>(1.0f);
+ let x = reflect(e1, e2);
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillReflectVec2F32()));
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunReflect_vec3_f16) {
+ auto* src = R"(
+enable f16;
+
+fn f() {
+ let e1 = vec3<f16>(1.0h);
+ let e2 = vec3<f16>(1.0h);
+ let x = reflect(e1, e2);
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillReflectVec2F32()));
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunReflect_vec4_f32) {
+ auto* src = R"(
+fn f() {
+ let e1 = vec3<f32>(1.0f);
+ let e2 = vec3<f32>(1.0f);
+ let x = reflect(e1, e2);
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillReflectVec2F32()));
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunReflect_vec4_f16) {
+ auto* src = R"(
+enable f16;
+
+fn f() {
+ let e1 = vec3<f16>(1.0h);
+ let e2 = vec3<f16>(1.0h);
+ let x = reflect(e1, e2);
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillReflectVec2F32()));
+}
+
+TEST_F(BuiltinPolyfillTest, Reflect_ConstantExpression) {
+ auto* src = R"(
+fn f() {
+ let r : vec2<f32> = reflect(vec2<f32>(1.0), vec2<f32>(1.0));
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillReflectVec2F32()));
+}
+
+TEST_F(BuiltinPolyfillTest, Reflect_vec2_f32) {
+ auto* src = R"(
+fn f() {
+ let v = 0.5f;
+ let r : vec2<f32> = reflect(vec2<f32>(v), vec2<f32>(v));
+}
+)";
+
+ auto* expect = R"(
+fn tint_reflect(e1 : vec2<f32>, e2 : vec2<f32>) -> vec2<f32> {
+ let factor = (-2.0 * dot(e1, e2));
+ return (e1 + (factor * e2));
+}
+
+fn f() {
+ let v = 0.5f;
+ let r : vec2<f32> = tint_reflect(vec2<f32>(v), vec2<f32>(v));
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillReflectVec2F32());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, Reflect_multiple_types) {
+ auto* src = R"(
+enable f16;
+
+fn f() {
+ let in_f32 = 0.5f;
+ let out_f32_vec2 : vec2<f32> = reflect(vec2<f32>(in_f32), vec2<f32>(in_f32));
+ let out_f32_vec3 : vec3<f32> = reflect(vec3<f32>(in_f32), vec3<f32>(in_f32));
+ let out_f32_vec4 : vec4<f32> = reflect(vec4<f32>(in_f32), vec4<f32>(in_f32));
+ let in_f16 = 0.5h;
+ let out_f16_vec2 : vec2<f16> = reflect(vec2<f16>(in_f16), vec2<f16>(in_f16));
+ let out_f16_vec3 : vec3<f16> = reflect(vec3<f16>(in_f16), vec3<f16>(in_f16));
+ let out_f16_vec4 : vec4<f16> = reflect(vec4<f16>(in_f16), vec4<f16>(in_f16));
+}
+)";
+
+ auto* expect = R"(
+enable f16;
+
+fn tint_reflect(e1 : vec2<f32>, e2 : vec2<f32>) -> vec2<f32> {
+ let factor = (-2.0 * dot(e1, e2));
+ return (e1 + (factor * e2));
+}
+
+fn f() {
+ let in_f32 = 0.5f;
+ let out_f32_vec2 : vec2<f32> = tint_reflect(vec2<f32>(in_f32), vec2<f32>(in_f32));
+ let out_f32_vec3 : vec3<f32> = reflect(vec3<f32>(in_f32), vec3<f32>(in_f32));
+ let out_f32_vec4 : vec4<f32> = reflect(vec4<f32>(in_f32), vec4<f32>(in_f32));
+ let in_f16 = 0.5h;
+ let out_f16_vec2 : vec2<f16> = reflect(vec2<f16>(in_f16), vec2<f16>(in_f16));
+ let out_f16_vec3 : vec3<f16> = reflect(vec3<f16>(in_f16), vec3<f16>(in_f16));
+ let out_f16_vec4 : vec4<f16> = reflect(vec4<f16>(in_f16), vec4<f16>(in_f16));
+}
+)";
+
+ auto got = Run<BuiltinPolyfill>(src, polyfillReflectVec2F32());
+
+ EXPECT_EQ(expect, str(got));
+}
+
+////////////////////////////////////////////////////////////////////////////////
// saturate
////////////////////////////////////////////////////////////////////////////////
DataMap polyfillSaturate() {
diff --git a/src/tint/transform/decompose_memory_access.cc b/src/tint/transform/decompose_memory_access.cc
index 28ecebd..0030ca1 100644
--- a/src/tint/transform/decompose_memory_access.cc
+++ b/src/tint/transform/decompose_memory_access.cc
@@ -36,6 +36,7 @@
#include "src/tint/utils/block_allocator.h"
#include "src/tint/utils/hash.h"
#include "src/tint/utils/map.h"
+#include "src/tint/utils/string_stream.h"
using namespace tint::number_suffixes; // NOLINT
@@ -695,7 +696,7 @@
: Base(pid, nid), op(o), type(ty), address_space(as), buffer(buf) {}
DecomposeMemoryAccess::Intrinsic::~Intrinsic() = default;
std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
- std::stringstream ss;
+ utils::StringStream ss;
switch (op) {
case Op::kLoad:
ss << "intrinsic_load_";
diff --git a/src/tint/transform/direct_variable_access.cc b/src/tint/transform/direct_variable_access.cc
index a6ef9d8..00d1e67 100644
--- a/src/tint/transform/direct_variable_access.cc
+++ b/src/tint/transform/direct_variable_access.cc
@@ -32,6 +32,7 @@
#include "src/tint/type/abstract_int.h"
#include "src/tint/utils/reverse.h"
#include "src/tint/utils/scoped_assignment.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::DirectVariableAccess);
TINT_INSTANTIATE_TYPEINFO(tint::transform::DirectVariableAccess::Config);
@@ -687,7 +688,7 @@
// Build an appropriate variant function name.
// This is derived from the original function name and the pointer parameter
// chains.
- std::stringstream ss;
+ utils::StringStream ss;
ss << ctx.src->Symbols().NameFor(target->Declaration()->name->symbol);
for (auto* param : target->Parameters()) {
if (auto indices = target_signature.Find(param)) {
@@ -1080,7 +1081,7 @@
/// @returns a name describing the given shape
std::string AccessShapeName(const AccessShape& shape) {
- std::stringstream ss;
+ utils::StringStream ss;
if (IsPrivateOrFunction(shape.root.address_space)) {
ss << "F";
diff --git a/src/tint/transform/packed_vec3.cc b/src/tint/transform/packed_vec3.cc
index 6337197..956adcb 100644
--- a/src/tint/transform/packed_vec3.cc
+++ b/src/tint/transform/packed_vec3.cc
@@ -18,16 +18,23 @@
#include <string>
#include <utility>
+#include "src/tint/ast/assignment_statement.h"
+#include "src/tint/builtin/builtin.h"
#include "src/tint/program_builder.h"
+#include "src/tint/sem/array_count.h"
#include "src/tint/sem/index_accessor_expression.h"
-#include "src/tint/sem/member_accessor_expression.h"
+#include "src/tint/sem/load.h"
#include "src/tint/sem/statement.h"
+#include "src/tint/sem/type_expression.h"
#include "src/tint/sem/variable.h"
+#include "src/tint/type/array.h"
+#include "src/tint/type/reference.h"
+#include "src/tint/type/vector.h"
#include "src/tint/utils/hashmap.h"
#include "src/tint/utils/hashset.h"
+#include "src/tint/utils/vector.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::PackedVec3);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::PackedVec3::Attribute);
using namespace tint::number_suffixes; // NOLINT
@@ -39,105 +46,447 @@
/// @param program the source program
explicit State(const Program* program) : src(program) {}
+ /// The name of the struct member used when wrapping packed vec3 types.
+ static constexpr const char* kStructMemberName = "elements";
+
+ /// The names of the structures used to wrap packed vec3 types.
+ utils::Hashmap<const type::Type*, Symbol, 4> packed_vec3_wrapper_struct_names;
+
+ /// A cache of host-shareable structures that have been rewritten.
+ utils::Hashmap<const type::Type*, Symbol, 4> rewritten_structs;
+
+ /// A map from type to the name of a helper function used to pack that type.
+ utils::Hashmap<const type::Type*, Symbol, 4> pack_helpers;
+
+ /// A map from type to the name of a helper function used to unpack that type.
+ utils::Hashmap<const type::Type*, Symbol, 4> unpack_helpers;
+
+ /// @param ty the type to test
+ /// @returns true if `ty` is a vec3, false otherwise
+ bool IsVec3(const type::Type* ty) {
+ if (auto* vec = ty->As<type::Vector>()) {
+ if (vec->Width() == 3) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// @param ty the type to test
+ /// @returns true if `ty` is or contains a vec3, false otherwise
+ bool ContainsVec3(const type::Type* ty) {
+ return Switch(
+ ty, //
+ [&](const type::Vector* vec) { return IsVec3(vec); },
+ [&](const type::Matrix* mat) { return ContainsVec3(mat->ColumnType()); },
+ [&](const type::Array* arr) { return ContainsVec3(arr->ElemType()); },
+ [&](const type::Struct* str) {
+ for (auto* member : str->Members()) {
+ if (ContainsVec3(member->Type())) {
+ return true;
+ }
+ }
+ return false;
+ });
+ }
+
+ /// Create a `__packed_vec3` type with the same element type as `ty`.
+ /// @param ty a three-element vector type
+ /// @returns the new AST type
+ ast::Type MakePackedVec3(const type::Type* ty) {
+ auto* vec = ty->As<type::Vector>();
+ TINT_ASSERT(Transform, vec != nullptr && vec->Width() == 3);
+ return b.ty(builtin::Builtin::kPackedVec3, CreateASTTypeFor(ctx, vec->type()));
+ }
+
+ /// Recursively rewrite a type using `__packed_vec3`, if needed.
+ /// When used as an array element type, the `__packed_vec3` type will be wrapped in a structure
+ /// and given an `@align()` attribute to give it alignment it needs to yield the correct array
+ /// element stride. For vec3 types used in structures directly, the `@align()` attribute is
+ /// placed on the containing structure instead. Matrices with three rows become arrays of
+ /// columns, and used the aligned wrapper struct for the column type.
+ /// @param ty the type to rewrite
+ /// @param array_element `true` if this is being called for the element of an array
+ /// @returns the new AST type, or nullptr if rewriting was not necessary
+ ast::Type RewriteType(const type::Type* ty, bool array_element = false) {
+ return Switch(
+ ty,
+ [&](const type::Vector* vec) -> ast::Type {
+ if (IsVec3(vec)) {
+ if (array_element) {
+ // Create a struct with a single `__packed_vec3` member.
+ // Give the struct member the same alignment as the original unpacked vec3
+ // type, to avoid changing the array element stride.
+ return b.ty(packed_vec3_wrapper_struct_names.GetOrCreate(vec, [&]() {
+ auto name = b.Symbols().New(
+ "tint_packed_vec3_" + vec->type()->FriendlyName(src->Symbols()) +
+ (array_element ? "_array_element" : "_struct_member"));
+ auto* member =
+ b.Member(kStructMemberName, MakePackedVec3(vec),
+ utils::Vector{b.MemberAlign(AInt(vec->Align()))});
+ b.Structure(b.Ident(name), utils::Vector{member}, utils::Empty);
+ return name;
+ }));
+ } else {
+ return MakePackedVec3(vec);
+ }
+ }
+ return {};
+ },
+ [&](const type::Matrix* mat) -> ast::Type {
+ // Rewrite the matrix as an array of columns that use the aligned wrapper struct.
+ auto new_col_type = RewriteType(mat->ColumnType(), /* array_element */ true);
+ if (new_col_type) {
+ return b.ty.array(new_col_type, u32(mat->columns()));
+ }
+ return {};
+ },
+ [&](const type::Array* arr) -> ast::Type {
+ // Rewrite the array with the modified element type.
+ auto new_type = RewriteType(arr->ElemType(), /* array_element */ true);
+ if (new_type) {
+ utils::Vector<const ast::Attribute*, 1> attrs;
+ if (arr->Count()->Is<type::RuntimeArrayCount>()) {
+ return b.ty.array(new_type, std::move(attrs));
+ } else if (auto count = arr->ConstantCount()) {
+ return b.ty.array(new_type, u32(count.value()), std::move(attrs));
+ } else {
+ TINT_ICE(Transform, b.Diagnostics())
+ << type::Array::kErrExpectedConstantCount;
+ return {};
+ }
+ }
+ return {};
+ },
+ [&](const sem::Struct* str) -> ast::Type {
+ if (ContainsVec3(str)) {
+ auto name = rewritten_structs.GetOrCreate(str, [&]() {
+ utils::Vector<const ast::StructMember*, 4> members;
+ for (auto* member : str->Members()) {
+ // If the member type contains a vec3, rewrite it.
+ auto new_type = RewriteType(member->Type());
+ if (new_type) {
+ // Copy the member attributes.
+ bool needs_align = true;
+ utils::Vector<const ast::Attribute*, 4> attributes;
+ for (auto* attr : member->Declaration()->attributes) {
+ if (attr->IsAnyOf<ast::StructMemberAlignAttribute,
+ ast::StructMemberOffsetAttribute>()) {
+ needs_align = false;
+ }
+ attributes.Push(ctx.Clone(attr));
+ }
+ // If the alignment wasn't already specified, add an attribute to
+ // make sure that we don't alter the alignment when using the packed
+ // vector type.
+ if (needs_align) {
+ attributes.Push(b.MemberAlign(AInt(member->Align())));
+ }
+ members.Push(b.Member(ctx.Clone(member->Name()), new_type,
+ std::move(attributes)));
+ } else {
+ // No vec3s, just clone the member as is.
+ members.Push(ctx.Clone(member->Declaration()));
+ }
+ }
+ // Create the new structure.
+ auto struct_name = b.Symbols().New(
+ src->Symbols().NameFor(str->Declaration()->name->symbol) +
+ "_tint_packed_vec3");
+ b.Structure(struct_name, std::move(members));
+ return struct_name;
+ });
+ return b.ty(name);
+ }
+ return {};
+ });
+ }
+
+ /// Create a helper function to recursively pack or unpack a composite that contains vec3 types.
+ /// @param name_prefix the name of the helper function
+ /// @param ty the composite type to pack or unpack
+ /// @param pack_or_unpack_element a function that packs or unpacks an element with a given type
+ /// @param in_type a function that create an AST type for the input type
+ /// @param out_type a function that create an AST type for the output type
+ /// @returns the name of the helper function
+ Symbol MakePackUnpackHelper(
+ const char* name_prefix,
+ const type::Type* ty,
+ const std::function<const ast::Expression*(const ast::Expression*, const type::Type*)>&
+ pack_or_unpack_element,
+ const std::function<ast::Type()>& in_type,
+ const std::function<ast::Type()>& out_type) {
+ // Allocate a variable to hold the return value of the function.
+ utils::Vector<const ast::Statement*, 4> statements;
+ statements.Push(b.Decl(b.Var("result", out_type())));
+
+ // Helper that generates a loop to copy and pack/unpack elements of an array to the result:
+ // for (var i = 0u; i < num_elements; i = i + 1) {
+ // result[i] = pack_or_unpack_element(in[i]);
+ // }
+ auto copy_array_elements = [&](uint32_t num_elements, const type::Type* element_type) {
+ // Generate an expression for packing or unpacking an element of the array.
+ auto* element = pack_or_unpack_element(b.IndexAccessor("in", "i"), element_type);
+ statements.Push(b.For( //
+ b.Decl(b.Var("i", b.ty.u32())), //
+ b.LessThan("i", u32(num_elements)), //
+ b.Assign("i", b.Add("i", 1_a)), //
+ b.Block(utils::Vector{
+ b.Assign(b.IndexAccessor("result", "i"), element),
+ })));
+ };
+
+ // Copy the elements of the value over to the result.
+ Switch(
+ ty,
+ [&](const type::Array* arr) {
+ TINT_ASSERT(Transform, arr->ConstantCount());
+ copy_array_elements(arr->ConstantCount().value(), arr->ElemType());
+ },
+ [&](const type::Matrix* mat) {
+ copy_array_elements(mat->columns(), mat->ColumnType());
+ },
+ [&](const sem::Struct* str) {
+ // Copy the struct members over one at a time, packing/unpacking as necessary.
+ for (auto* member : str->Members()) {
+ const ast::Expression* element =
+ b.MemberAccessor("in", b.Ident(ctx.Clone(member->Name())));
+ if (ContainsVec3(member->Type())) {
+ element = pack_or_unpack_element(element, member->Type());
+ }
+ statements.Push(b.Assign(
+ b.MemberAccessor("result", b.Ident(ctx.Clone(member->Name()))), element));
+ }
+ });
+
+ // Return the result.
+ statements.Push(b.Return("result"));
+
+ // Create the function and return its name.
+ auto name = b.Symbols().New(name_prefix);
+ b.Func(name, utils::Vector{b.Param("in", in_type())}, out_type(), std::move(statements));
+ return name;
+ }
+
+ /// Unpack the composite value `expr` to the unpacked type `ty`. If `ty` is a matrix, this will
+ /// produce a regular matNx3 value from an array of packed column vectors.
+ /// @param expr the composite value expression to unpack
+ /// @param ty the unpacked type
+ /// @returns an expression that holds the unpacked value
+ const ast::Expression* UnpackComposite(const ast::Expression* expr, const type::Type* ty) {
+ auto helper = unpack_helpers.GetOrCreate(ty, [&]() {
+ return MakePackUnpackHelper(
+ "tint_unpack_vec3_in_composite", ty,
+ [&](const ast::Expression* element,
+ const type::Type* element_type) -> const ast::Expression* {
+ if (element_type->Is<type::Vector>()) {
+ // Unpack a `__packed_vec3` by casting it to a regular vec3.
+ // If it is an array element, extract the vector from the wrapper struct.
+ if (element->Is<ast::IndexAccessorExpression>()) {
+ element = b.MemberAccessor(element, kStructMemberName);
+ }
+ return b.Call(CreateASTTypeFor(ctx, element_type), element);
+ } else {
+ return UnpackComposite(element, element_type);
+ }
+ },
+ [&]() { return RewriteType(ty); }, //
+ [&]() { return CreateASTTypeFor(ctx, ty); });
+ });
+ return b.Call(helper, expr);
+ }
+
+ /// Pack the composite value `expr` from the unpacked type `ty`. If `ty` is a matrix, this will
+ /// produce an array of packed column vectors.
+ /// @param expr the composite value expression to pack
+ /// @param ty the unpacked type
+ /// @returns an expression that holds the packed value
+ const ast::Expression* PackComposite(const ast::Expression* expr, const type::Type* ty) {
+ auto helper = pack_helpers.GetOrCreate(ty, [&]() {
+ return MakePackUnpackHelper(
+ "tint_pack_vec3_in_composite", ty,
+ [&](const ast::Expression* element,
+ const type::Type* element_type) -> const ast::Expression* {
+ if (element_type->Is<type::Vector>()) {
+ // Pack a vector element by casting it to a packed_vec3.
+ // If it is an array element, construct a wrapper struct.
+ auto* packed = b.Call(MakePackedVec3(element_type), element);
+ if (element->Is<ast::IndexAccessorExpression>()) {
+ packed = b.Call(RewriteType(element_type, true), packed);
+ }
+ return packed;
+ } else {
+ return PackComposite(element, element_type);
+ }
+ },
+ [&]() { return CreateASTTypeFor(ctx, ty); }, //
+ [&]() { return RewriteType(ty); });
+ });
+ return b.Call(helper, expr);
+ }
+
+ /// @returns true if there are host-shareable vec3's that need transforming
+ bool ShouldRun() {
+ // Check for vec3s in the types of all uniform and storage buffer variables to determine
+ // if the transform is necessary.
+ for (auto* decl : src->AST().GlobalVariables()) {
+ auto* var = sem.Get<sem::GlobalVariable>(decl);
+ if (var && builtin::IsHostShareable(var->AddressSpace()) &&
+ ContainsVec3(var->Type()->UnwrapRef())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/// Runs the transform
/// @returns the new program or SkipTransform if the transform is not required
ApplyResult Run() {
- // Packed vec3<T> struct members
- utils::Hashset<const sem::StructMember*, 8> members;
-
- // Find all the packed vector struct members, and apply the @internal(packed_vector)
- // attribute.
- for (auto* decl : ctx.src->AST().GlobalDeclarations()) {
- if (auto* str = sem.Get<sem::Struct>(decl)) {
- if (str->IsHostShareable()) {
- for (auto* member : str->Members()) {
- if (auto* vec = member->Type()->As<type::Vector>()) {
- if (vec->Width() == 3) {
- members.Add(member);
-
- // Apply the PackedVec3::Attribute to the member
- ctx.InsertFront(
- member->Declaration()->attributes,
- b.ASTNodes().Create<Attribute>(b.ID(), b.AllocateNodeID()));
- }
- }
- }
- }
- }
- }
-
- if (members.IsEmpty()) {
+ if (!ShouldRun()) {
return SkipTransform;
}
- // Walk the nodes, starting with the most deeply nested, finding all the AST expressions
- // that load a whole packed vector (not a scalar / swizzle of the vector).
- utils::Hashset<const sem::ValueExpression*, 16> refs;
+ // Changing the types of certain structure members can trigger stricter layout validation
+ // rules for the uniform address space. In particular, replacing 16-bit matrices with arrays
+ // violates the requirement that the array element stride is a multiple of 16 bytes, and
+ // replacing vec3s with a structure violates the requirement that there must be at least 16
+ // bytes from the start of a structure to the start of the next member.
+ // Disable these validation rules using an internal extension, as MSL does not have these
+ // restrictions.
+ b.Enable(builtin::Extension::kChromiumInternalRelaxedUniformLayout);
+
+ // Track expressions that need to be packed or unpacked.
+ utils::Hashset<const sem::ValueExpression*, 8> to_pack;
+ utils::Hashset<const sem::ValueExpression*, 8> to_unpack;
+
+ // Replace vec3 types in host-shareable address spaces with `__packed_vec3` types, and
+ // collect expressions that need to be converted to or from values that use the
+ // `__packed_vec3` type.
for (auto* node : ctx.src->ASTNodes().Objects()) {
- auto* sem_node = sem.Get(node);
- if (sem_node) {
- if (auto* expr = sem_node->As<sem::ValueExpression>()) {
- sem_node = expr->UnwrapLoad();
- }
- }
Switch(
- sem_node, //
- [&](const sem::StructMemberAccess* access) {
- if (members.Contains(access->Member())) {
- // Access to a packed vector member. Seed the expression tracking.
- refs.Add(access);
- }
- },
- [&](const sem::IndexAccessorExpression* access) {
- // Not loading a whole packed vector. Ignore.
- refs.Remove(access->Object()->UnwrapLoad());
- },
- [&](const sem::Swizzle* access) {
- // Not loading a whole packed vector. Ignore.
- refs.Remove(access->Object()->UnwrapLoad());
- },
- [&](const sem::VariableUser* user) {
- auto* v = user->Variable();
- if (v->Declaration()->Is<ast::Let>() && // if variable is let...
- v->Type()->Is<type::Pointer>() && // and let is a pointer...
- refs.Contains(v->Initializer())) { // and pointer is to a packed vector...
- refs.Add(user); // then propagate tracking to pointer usage
- }
- },
- [&](const sem::ValueExpression* expr) {
- if (auto* unary = expr->Declaration()->As<ast::UnaryOpExpression>()) {
- if (unary->op == ast::UnaryOp::kAddressOf ||
- unary->op == ast::UnaryOp::kIndirection) {
- // Memory access on the packed vector. Track these.
- auto* inner = sem.GetVal(unary->expr);
- if (refs.Remove(inner)) {
- refs.Add(expr);
- }
+ sem.Get(node),
+ [&](const sem::TypeExpression* type) {
+ // Rewrite pointers to types that contain vec3s.
+ auto* ptr = type->Type()->As<type::Pointer>();
+ if (ptr && builtin::IsHostShareable(ptr->AddressSpace())) {
+ auto new_store_type = RewriteType(ptr->StoreType());
+ if (new_store_type) {
+ auto access = ptr->AddressSpace() == builtin::AddressSpace::kStorage
+ ? ptr->Access()
+ : builtin::Access::kUndefined;
+ auto new_ptr_type =
+ b.ty.pointer(new_store_type, ptr->AddressSpace(), access);
+ ctx.Replace(node, new_ptr_type.expr);
}
- // Note: non-memory ops (e.g. '-') are ignored, leaving any tracked
- // reference at the inner expression, so we'd cast, then apply the unary op.
}
},
- [&](const sem::Statement* e) {
- if (auto* assign = e->Declaration()->As<ast::AssignmentStatement>()) {
- // We don't want to cast packed_vectors if they're being assigned to.
- refs.Remove(sem.GetVal(assign->lhs));
+ [&](const sem::Variable* var) {
+ if (!builtin::IsHostShareable(var->AddressSpace())) {
+ return;
+ }
+
+ // Rewrite the var type, if it contains vec3s.
+ auto new_store_type = RewriteType(var->Type()->UnwrapRef());
+ if (new_store_type) {
+ ctx.Replace(var->Declaration()->type.expr, new_store_type.expr);
+ }
+ },
+ [&](const sem::Statement* stmt) {
+ // Pack the RHS of assignment statements that are writing to packed types.
+ if (auto* assign = stmt->Declaration()->As<ast::AssignmentStatement>()) {
+ auto* lhs = sem.GetVal(assign->lhs);
+ auto* rhs = sem.GetVal(assign->rhs);
+ if (!ContainsVec3(rhs->Type()) ||
+ !builtin::IsHostShareable(
+ lhs->Type()->As<type::Reference>()->AddressSpace())) {
+ // Skip assignments to address spaces that are not host-shareable, or
+ // that do not contain vec3 types.
+ return;
+ }
+
+ // Pack the RHS expression.
+ if (to_unpack.Contains(rhs)) {
+ // The expression will already be packed, so skip the pending unpack.
+ to_unpack.Remove(rhs);
+
+ // If the expression produces a vec3 from an array element, extract
+ // the packed vector from the wrapper struct.
+ if (IsVec3(rhs->Type()) &&
+ rhs->UnwrapLoad()->Is<sem::IndexAccessorExpression>()) {
+ ctx.Replace(rhs->Declaration(),
+ b.MemberAccessor(ctx.Clone(rhs->Declaration()),
+ kStructMemberName));
+ }
+ } else if (rhs) {
+ to_pack.Add(rhs);
+ }
+ }
+ },
+ [&](const sem::Load* load) {
+ // Unpack loads of types that contain vec3s in host-shareable address spaces.
+ if (ContainsVec3(load->Type()) &&
+ builtin::IsHostShareable(load->ReferenceType()->AddressSpace())) {
+ to_unpack.Add(load);
+ }
+ },
+ [&](const sem::IndexAccessorExpression* accessor) {
+ // If the expression produces a reference to a vec3 in a host-shareable address
+ // space from an array element, extract the packed vector from the wrapper
+ // struct.
+ if (auto* ref = accessor->Type()->As<type::Reference>()) {
+ if (IsVec3(ref->StoreType()) &&
+ builtin::IsHostShareable(ref->AddressSpace())) {
+ ctx.Replace(node, b.MemberAccessor(ctx.Clone(accessor->Declaration()),
+ kStructMemberName));
+ }
}
});
}
- // Wrap the load expressions with a cast to the unpacked type.
- utils::Hashmap<const type::Vector*, Symbol, 3> unpack_fns;
- for (auto* ref : refs) {
- // ref is either a packed vec3 that needs casting, or a pointer to a vec3 which we just
- // leave alone.
- if (auto* vec_ty = ref->Type()->UnwrapRef()->As<type::Vector>()) {
- auto* expr = ref->Declaration();
- ctx.Replace(expr, [this, vec_ty, expr] { //
- auto* packed = ctx.CloneWithoutTransform(expr);
- return b.Call(CreateASTTypeFor(ctx, vec_ty), packed);
- });
+ // Sort the pending pack/unpack operations by AST node ID to make the order deterministic.
+ auto to_unpack_sorted = to_unpack.Vector();
+ auto to_pack_sorted = to_pack.Vector();
+ auto pred = [&](auto* expr_a, auto* expr_b) {
+ return expr_a->Declaration()->node_id < expr_b->Declaration()->node_id;
+ };
+ to_unpack_sorted.Sort(pred);
+ to_pack_sorted.Sort(pred);
+
+ // Apply all of the pending unpack operations that we have collected.
+ for (auto* expr : to_unpack_sorted) {
+ TINT_ASSERT(Transform, ContainsVec3(expr->Type()));
+ auto* packed = ctx.Clone(expr->Declaration());
+ const ast::Expression* unpacked = nullptr;
+ if (IsVec3(expr->Type())) {
+ if (expr->UnwrapLoad()->Is<sem::IndexAccessorExpression>()) {
+ // If we are unpacking a vec3 from an array element, extract the vector from the
+ // wrapper struct.
+ packed = b.MemberAccessor(packed, kStructMemberName);
+ }
+ // Cast the packed vector to a regular vec3.
+ unpacked = b.Call(CreateASTTypeFor(ctx, expr->Type()), packed);
+ } else {
+ // Use a helper function to unpack an array or matrix.
+ unpacked = UnpackComposite(packed, expr->Type());
}
+ TINT_ASSERT(Transform, unpacked != nullptr);
+ ctx.Replace(expr->Declaration(), unpacked);
+ }
+
+ // Apply all of the pending pack operations that we have collected.
+ for (auto* expr : to_pack_sorted) {
+ TINT_ASSERT(Transform, ContainsVec3(expr->Type()));
+ auto* unpacked = ctx.Clone(expr->Declaration());
+ const ast::Expression* packed = nullptr;
+ if (IsVec3(expr->Type())) {
+ // Cast the regular vec3 to a packed vector type.
+ packed = b.Call(MakePackedVec3(expr->Type()), unpacked);
+ } else {
+ // Use a helper function to pack an array or matrix.
+ packed = PackComposite(unpacked, expr->Type());
+ }
+ TINT_ASSERT(Transform, packed != nullptr);
+ ctx.Replace(expr->Declaration(), packed);
}
ctx.Clone();
@@ -153,21 +502,8 @@
CloneContext ctx = {&b, src, /* auto_clone_symbols */ true};
/// Alias to the semantic info in ctx.src
const sem::Info& sem = ctx.src->Sem();
- /// Alias to the symbols in ctx.src
- const SymbolTable& sym = ctx.src->Symbols();
};
-PackedVec3::Attribute::Attribute(ProgramID pid, ast::NodeID nid) : Base(pid, nid) {}
-PackedVec3::Attribute::~Attribute() = default;
-
-const PackedVec3::Attribute* PackedVec3::Attribute::Clone(CloneContext* ctx) const {
- return ctx->dst->ASTNodes().Create<Attribute>(ctx->dst->ID(), ctx->dst->AllocateNodeID());
-}
-
-std::string PackedVec3::Attribute::InternalName() const {
- return "packed_vector";
-}
-
PackedVec3::PackedVec3() = default;
PackedVec3::~PackedVec3() = default;
diff --git a/src/tint/transform/packed_vec3.h b/src/tint/transform/packed_vec3.h
index 0d304fa..89e8286 100644
--- a/src/tint/transform/packed_vec3.h
+++ b/src/tint/transform/packed_vec3.h
@@ -15,42 +15,31 @@
#ifndef SRC_TINT_TRANSFORM_PACKED_VEC3_H_
#define SRC_TINT_TRANSFORM_PACKED_VEC3_H_
-#include <string>
-
-#include "src/tint/ast/internal_attribute.h"
#include "src/tint/transform/transform.h"
namespace tint::transform {
/// A transform to be used by the MSL backend which will:
-/// * Apply the `@internal('packed_vector')` attribute (PackedVec3::Attribute) to all host-sharable
-/// structure members that have a vec3<T> type.
+/// * Replace `vec3<T>` types with an internal `__packed_vec3` type when they are used in
+/// host-shareable address spaces.
+/// * Wrap generated `__packed_vec3` types in a structure when they are used in arrays, so that we
+/// ensure that the array has the correct element stride.
+/// * Multi-version structures that contain `vec3<T>` types when they are used in host-shareable
+/// memory, to avoid modifying uses in other address spaces.
+/// * Rewrite matrix types that have three rows into arrays of column vectors.
+/// * Insert calls to helper functions to convert expressions that use these types to or from the
+/// regular vec3 types when accessing host-shareable memory.
/// * Cast all direct (not sub-accessed) loads of these packed vectors to the 'unpacked' vec3<T>
/// type before usage.
///
-/// This transform papers over overload holes in the MSL standard library where an MSL
-/// `packed_vector` type cannot be interchangable used as a regular `vec` type.
+/// This transform is necessary in order to emit vec3 types with the correct size (so that scalars
+/// can follow them in structures), and also to ensure that padding bytes are preserved when writing
+/// to a vec3, an array of vec3 elements, or a matrix with vec3 column type.
+///
+/// @note Depends on the following transforms to have been run first:
+/// * ExpandCompoundAssignment
class PackedVec3 final : public Castable<PackedVec3, Transform> {
public:
- /// Attribute is the attribute applied to padded vector structure members.
- class Attribute final : public Castable<Attribute, ast::InternalAttribute> {
- public:
- /// Constructor
- /// @param pid the identifier of the program that owns this node
- /// @param nid the unique node identifier
- Attribute(ProgramID pid, ast::NodeID nid);
- /// Destructor
- ~Attribute() override;
-
- /// @returns "packed_vector".
- std::string InternalName() const override;
-
- /// Performs a deep clone of this object using the CloneContext `ctx`.
- /// @param ctx the clone context
- /// @return the newly cloned object
- const Attribute* Clone(CloneContext* ctx) const override;
- };
-
/// Constructor
PackedVec3();
/// Destructor
diff --git a/src/tint/transform/packed_vec3_test.cc b/src/tint/transform/packed_vec3_test.cc
index 0f5c92e..670bc05 100644
--- a/src/tint/transform/packed_vec3_test.cc
+++ b/src/tint/transform/packed_vec3_test.cc
@@ -18,7 +18,12 @@
#include <utility>
#include <vector>
+#include "src/tint/ast/module.h"
+#include "src/tint/program_builder.h"
+#include "src/tint/sem/struct.h"
+#include "src/tint/sem/variable.h"
#include "src/tint/transform/test_helper.h"
+#include "src/tint/type/array.h"
#include "src/tint/utils/string.h"
namespace tint::transform {
@@ -32,14 +37,29 @@
EXPECT_FALSE(ShouldRun<PackedVec3>(src));
}
-TEST_F(PackedVec3Test, ShouldRun_NonHostSharableStruct) {
+TEST_F(PackedVec3Test, ShouldRun_NoHostShareableVec3s) {
auto* src = R"(
struct S {
v : vec3<f32>,
+ m : mat3x3<f32>,
+ a : array<vec3<f32>, 4>,
}
+var<private> p_s : S;
+var<private> p_v : vec3<f32>;
+var<private> p_m : mat3x3<f32>;
+var<private> p_a : array<vec3<f32>, 4>;
+
+var<workgroup> w_s : S;
+var<workgroup> w_v : vec3<f32>;
+var<workgroup> w_m : mat3x3<f32>;
+var<workgroup> w_a : array<vec3<f32>, 4>;
+
fn f() {
- var v : S; // function address-space - not host sharable
+ var f_s : S;
+ var f_v : vec3<f32>;
+ var f_m : mat3x3<f32>;
+ var f_a : array<vec3<f32>, 4>;
}
)";
@@ -53,13 +73,85 @@
v2 : vec2<f32>,
}
-@group(0) @binding(0) var<uniform> P : S; // Host sharable
+@group(0) @binding(0) var<uniform> Ps : S; // Host sharable
+@group(0) @binding(1) var<uniform> Pv4 : vec4<f32>; // Host sharable
+@group(0) @binding(2) var<uniform> Pv2 : vec2<f32>; // Host sharable
)";
EXPECT_FALSE(ShouldRun<PackedVec3>(src));
}
-TEST_F(PackedVec3Test, ShouldRun_HostSharableStruct) {
+TEST_F(PackedVec3Test, ShouldRun_OtherMatrices) {
+ auto* src = R"(
+struct S {
+ m2x2 : mat2x2<f32>,
+ m2x4 : mat2x4<f32>,
+ m3x2 : mat3x2<f32>,
+ m3x4 : mat3x4<f32>,
+ m4x2 : mat4x2<f32>,
+ m4x4 : mat4x4<f32>,
+}
+
+@group(0) @binding(0) var<uniform> Ps : S; // Host sharable
+@group(0) @binding(1) var<uniform> Pm2x2 : mat2x2<f32>; // Host sharable
+@group(0) @binding(2) var<uniform> Pm2x4 : mat2x4<f32>; // Host sharable
+@group(0) @binding(3) var<uniform> Pm3x2 : mat3x2<f32>; // Host sharable
+@group(0) @binding(4) var<uniform> Pm3x4 : mat3x4<f32>; // Host sharable
+@group(0) @binding(5) var<uniform> Pm4x2 : mat4x2<f32>; // Host sharable
+@group(0) @binding(6) var<uniform> Pm4x4 : mat4x4<f32>; // Host sharable
+)";
+
+ EXPECT_FALSE(ShouldRun<PackedVec3>(src));
+}
+
+TEST_F(PackedVec3Test, ShouldRun_ArrayOfNonVec3) {
+ auto* src = R"(
+struct S {
+ arr_v : array<vec2<f32>, 4>,
+ arr_m : array<mat3x2<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> Ps : S; // Host sharable
+@group(0) @binding(1) var<storage> Parr_v : array<vec2<f32>, 4>; // Host sharable
+@group(0) @binding(2) var<storage> Parr_m : array<mat3x2<f32>, 4>; // Host sharable
+)";
+
+ EXPECT_FALSE(ShouldRun<PackedVec3>(src));
+}
+
+TEST_F(PackedVec3Test, ShouldRun_HostSharable_Vec3) {
+ auto* src = R"(
+@group(0) @binding(0) var<uniform> P : vec3<f32>; // Host sharable
+)";
+
+ EXPECT_TRUE(ShouldRun<PackedVec3>(src));
+}
+
+TEST_F(PackedVec3Test, ShouldRun_HostSharable_Mat3x3) {
+ auto* src = R"(
+@group(0) @binding(0) var<uniform> P : mat3x3<f32>; // Host sharable
+)";
+
+ EXPECT_TRUE(ShouldRun<PackedVec3>(src));
+}
+
+TEST_F(PackedVec3Test, ShouldRun_HostSharable_ArrayOfVec3) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> P : array<vec3<f32>>; // Host sharable
+)";
+
+ EXPECT_TRUE(ShouldRun<PackedVec3>(src));
+}
+
+TEST_F(PackedVec3Test, ShouldRun_HostSharable_ArrayOfMat3x3) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> P : array<mat3x3<f32>>; // Host sharable
+)";
+
+ EXPECT_TRUE(ShouldRun<PackedVec3>(src));
+}
+
+TEST_F(PackedVec3Test, ShouldRun_HostSharableStruct_Vec3) {
auto* src = R"(
struct S {
v : vec3<f32>,
@@ -71,61 +163,3929 @@
EXPECT_TRUE(ShouldRun<PackedVec3>(src));
}
-TEST_F(PackedVec3Test, UniformAddressSpace) {
+TEST_F(PackedVec3Test, ShouldRun_HostSharableStruct_Mat3x3) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<uniform> P : S; // Host sharable
+)";
+
+ EXPECT_TRUE(ShouldRun<PackedVec3>(src));
+}
+
+TEST_F(PackedVec3Test, ShouldRun_HostSharableStruct_ArrayOfVec3) {
+ auto* src = R"(
+struct S {
+ a : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<uniform> P : S; // Host sharable
+)";
+
+ EXPECT_TRUE(ShouldRun<PackedVec3>(src));
+}
+
+TEST_F(PackedVec3Test, ShouldRun_HostSharableStruct_ArrayOfMat3x3) {
+ auto* src = R"(
+struct S {
+ a : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<uniform> P : S; // Host sharable
+)";
+
+ EXPECT_TRUE(ShouldRun<PackedVec3>(src));
+}
+
+TEST_F(PackedVec3Test, Vec3_ReadVector) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> v : vec3<f32>;
+
+fn f() {
+ let x = v;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+@group(0) @binding(0) var<storage> v : __packed_vec3<f32>;
+
+fn f() {
+ let x = vec3<f32>(v);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Vec3_ReadComponent_MemberAccessChain) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> v : vec3<f32>;
+
+fn f() {
+ let x = v.yz.x;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+@group(0) @binding(0) var<storage> v : __packed_vec3<f32>;
+
+fn f() {
+ let x = vec3<f32>(v).yz.x;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Vec3_ReadComponent_IndexAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> v : vec3<f32>;
+
+fn f() {
+ let x = v[1];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+@group(0) @binding(0) var<storage> v : __packed_vec3<f32>;
+
+fn f() {
+ let x = v[1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Vec3_WriteVector_ValueRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> v : vec3<f32>;
+
+fn f() {
+ v = vec3(1.23);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+@group(0) @binding(0) var<storage, read_write> v : __packed_vec3<f32>;
+
+fn f() {
+ v = __packed_vec3<f32>(vec3(1.23));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Vec3_WriteVector_RefRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> v : vec3<f32>;
+@group(0) @binding(1) var<uniform> in : vec3<f32>;
+
+fn f() {
+ v = in;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+@group(0) @binding(0) var<storage, read_write> v : __packed_vec3<f32>;
+
+@group(0) @binding(1) var<uniform> in : __packed_vec3<f32>;
+
+fn f() {
+ v = in;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Vec3_WriteComponent_MemberAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> v : vec3<f32>;
+
+fn f() {
+ v.y = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+@group(0) @binding(0) var<storage, read_write> v : __packed_vec3<f32>;
+
+fn f() {
+ v.y = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Vec3_WriteComponent_IndexAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> v : vec3<f32>;
+
+fn f() {
+ v[1] = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+@group(0) @binding(0) var<storage, read_write> v : __packed_vec3<f32>;
+
+fn f() {
+ v[1] = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVec3_ReadArray) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> arr : array<vec3<f32>, 4>;
+
+fn f() {
+ let x = arr;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+@group(0) @binding(0) var<storage> arr : array<tint_packed_vec3_f32_array_element, 4u>;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite(arr);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVec3_ReadVector) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> arr : array<vec3<f32>, 4>;
+
+fn f() {
+ let x = arr[0];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> arr : array<tint_packed_vec3_f32_array_element, 4u>;
+
+fn f() {
+ let x = vec3<f32>(arr[0].elements);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVec3_ReadComponent_MemberAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> arr : array<vec3<f32>, 4>;
+
+fn f() {
+ let x = arr[0].y;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> arr : array<tint_packed_vec3_f32_array_element, 4u>;
+
+fn f() {
+ let x = arr[0].elements.y;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVec3_ReadComponent_IndexAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> arr : array<vec3<f32>, 4>;
+
+fn f() {
+ let x = arr[0][1];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> arr : array<tint_packed_vec3_f32_array_element, 4u>;
+
+fn f() {
+ let x = arr[0].elements[1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVec3_WriteArray_ValueRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<vec3<f32>, 2>;
+
+fn f() {
+ arr = array(vec3(1.5, 2.5, 3.5), vec3(4.5, 5.5, 6.5));
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+fn tint_pack_vec3_in_composite(in : array<vec3<f32>, 2u>) -> array<tint_packed_vec3_f32_array_element, 2u> {
+ var result : array<tint_packed_vec3_f32_array_element, 2u>;
+ for(var i : u32; (i < 2u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<tint_packed_vec3_f32_array_element, 2u>;
+
+fn f() {
+ arr = tint_pack_vec3_in_composite(array(vec3(1.5, 2.5, 3.5), vec3(4.5, 5.5, 6.5)));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVec3_WriteArray_RefRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<vec3<f32>, 2>;
+@group(0) @binding(1) var<uniform> in : array<vec3<f32>, 2>;
+
+fn f() {
+ arr = in;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<tint_packed_vec3_f32_array_element, 2u>;
+
+@group(0) @binding(1) var<uniform> in : array<tint_packed_vec3_f32_array_element, 2u>;
+
+fn f() {
+ arr = in;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVec3_WriteVector_ValueRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<vec3<f32>, 4>;
+
+fn f() {
+ arr[0] = vec3(1.23);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<tint_packed_vec3_f32_array_element, 4u>;
+
+fn f() {
+ arr[0].elements = __packed_vec3<f32>(vec3(1.23));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVec3_WriteVector_RefRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<vec3<f32>, 4>;
+@group(0) @binding(1) var<uniform> in_arr : array<vec3<f32>, 4>;
+@group(0) @binding(2) var<uniform> in_vec : vec3<f32>;
+
+fn f() {
+ arr[0] = in_arr[0];
+ arr[1] = in_vec;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<tint_packed_vec3_f32_array_element, 4u>;
+
+@group(0) @binding(1) var<uniform> in_arr : array<tint_packed_vec3_f32_array_element, 4u>;
+
+@group(0) @binding(2) var<uniform> in_vec : __packed_vec3<f32>;
+
+fn f() {
+ arr[0].elements = in_arr[0].elements;
+ arr[1].elements = in_vec;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVec3_WriteComponent_MemberAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<vec3<f32>, 4>;
+
+fn f() {
+ arr[0].y = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<tint_packed_vec3_f32_array_element, 4u>;
+
+fn f() {
+ arr[0].elements.y = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVec3_WriteComponent_IndexAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<vec3<f32>, 4>;
+
+fn f() {
+ arr[0][1] = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<tint_packed_vec3_f32_array_element, 4u>;
+
+fn f() {
+ arr[0].elements[1] = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Matrix_ReadMatrix) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> m : mat3x3<f32>;
+
+fn f() {
+ let x = m;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+@group(0) @binding(0) var<storage> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite(m);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Matrix_ReadColumn) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> m : mat3x3<f32>;
+
+fn f() {
+ let x = m[1];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ let x = vec3<f32>(m[1].elements);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Matrix_ReadComponent_MemberAccessChain) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> m : mat3x3<f32>;
+
+fn f() {
+ let x = m[1].yz.x;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ let x = vec3<f32>(m[1].elements).yz.x;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Matrix_ReadComponent_IndexAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> m : mat3x3<f32>;
+
+fn f() {
+ let x = m[2][1];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ let x = m[2].elements[1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Matrix_WriteMatrix_ValueRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> m : mat3x3<f32>;
+
+fn f() {
+ m = mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+@group(0) @binding(0) var<storage, read_write> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ m = tint_pack_vec3_in_composite(mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Matrix_WriteMatrix_RefRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> m : mat3x3<f32>;
+@group(0) @binding(1) var<uniform> in : mat3x3<f32>;
+
+fn f() {
+ m = in;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+@group(0) @binding(1) var<uniform> in : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ m = in;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Matrix_WriteColumn_ValueRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> m : mat3x3<f32>;
+
+fn f() {
+ m[1] = vec3(1.23);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ m[1].elements = __packed_vec3<f32>(vec3(1.23));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Matrix_WriteColumn_RefRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> m : mat3x3<f32>;
+@group(0) @binding(1) var<uniform> in_mat : mat3x3<f32>;
+@group(0) @binding(1) var<uniform> in_vec : vec3<f32>;
+
+fn f() {
+ m[0] = in_mat[0];
+ m[1] = in_vec;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+@group(0) @binding(1) var<uniform> in_mat : array<tint_packed_vec3_f32_array_element, 3u>;
+
+@group(0) @binding(1) var<uniform> in_vec : __packed_vec3<f32>;
+
+fn f() {
+ m[0].elements = in_mat[0].elements;
+ m[1].elements = in_vec;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Matrix_WriteComponent_MemberAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> m : mat3x3<f32>;
+
+fn f() {
+ m[1].y = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ m[1].elements.y = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Matrix_WriteComponent_IndexAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> m : mat3x3<f32>;
+
+fn f() {
+ m[1][2] = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ m[1].elements[2] = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_ReadArray) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> arr : array<mat3x3<f32>, 4>;
+
+fn f() {
+ let x = arr;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+@group(0) @binding(0) var<storage> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite_1(arr);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_ReadMatrix) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> arr : array<mat3x3<f32>, 4>;
+
+fn f() {
+ let x = arr[0];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+@group(0) @binding(0) var<storage> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite(arr[0]);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_ReadColumn) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> arr : array<mat3x3<f32>, 4>;
+
+fn f() {
+ let x = arr[0][1];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+fn f() {
+ let x = vec3<f32>(arr[0][1].elements);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_ReadComponent_MemberAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> arr : array<mat3x3<f32>, 4>;
+
+fn f() {
+ let x = arr[0][1].y;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+fn f() {
+ let x = arr[0][1].elements.y;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_ReadComponent_IndexAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage> arr : array<mat3x3<f32>, 4>;
+
+fn f() {
+ let x = arr[0][1][2];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+fn f() {
+ let x = arr[0][1].elements[2];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_WriteArray_ValueRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<mat3x3<f32>, 2>;
+
+fn f() {
+ arr = array(mat3x3<f32>(), mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5));
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : array<mat3x3<f32>, 2u>) -> array<array<tint_packed_vec3_f32_array_element, 3u>, 2u> {
+ var result : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>;
+ for(var i : u32; (i < 2u); i = (i + 1)) {
+ result[i] = tint_pack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>;
+
+fn f() {
+ arr = tint_pack_vec3_in_composite_1(array(mat3x3<f32>(), mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5)));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_WriteArray_RefRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<mat3x3<f32>, 2>;
+@group(0) @binding(1) var<uniform> in : array<mat3x3<f32>, 2>;
+
+fn f() {
+ arr = in;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>;
+
+@group(0) @binding(1) var<uniform> in : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>;
+
+fn f() {
+ arr = in;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_WriteMatrix_ValueRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<mat3x3<f32>, 4>;
+
+fn f() {
+ arr[0] = mat3x3(1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+fn f() {
+ arr[0] = tint_pack_vec3_in_composite(mat3x3(1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_WriteMatrix_RefRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<mat3x3<f32>, 4>;
+@group(0) @binding(1) var<uniform> in_arr : array<mat3x3<f32>, 4>;
+@group(0) @binding(2) var<uniform> in_mat : mat3x3<f32>;
+
+fn f() {
+ arr[0] = in_arr[0];
+ arr[1] = in_mat;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(1) var<uniform> in_arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(2) var<uniform> in_mat : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ arr[0] = in_arr[0];
+ arr[1] = in_mat;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_WriteVector_ValueRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<mat3x3<f32>, 4>;
+
+fn f() {
+ arr[0][1] = vec3(1.23);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+fn f() {
+ arr[0][1].elements = __packed_vec3<f32>(vec3(1.23));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_WriteVector_RefRHS) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<mat3x3<f32>, 4>;
+@group(0) @binding(1) var<uniform> in_arr : array<mat3x3<f32>, 4>;
+@group(0) @binding(2) var<uniform> in_mat : mat3x3<f32>;
+@group(0) @binding(3) var<uniform> in_vec : vec3<f32>;
+
+fn f() {
+ arr[0][0] = arr[0][1];
+ arr[0][1] = in_mat[2];
+ arr[0][2] = in_vec;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(1) var<uniform> in_arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(2) var<uniform> in_mat : array<tint_packed_vec3_f32_array_element, 3u>;
+
+@group(0) @binding(3) var<uniform> in_vec : __packed_vec3<f32>;
+
+fn f() {
+ arr[0][0].elements = arr[0][1].elements;
+ arr[0][1].elements = in_mat[2].elements;
+ arr[0][2].elements = in_vec;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_WriteComponent_MemberAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<mat3x3<f32>, 4>;
+
+fn f() {
+ arr[0][1].y = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+fn f() {
+ arr[0][1].elements.y = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrix_WriteComponent_IndexAccessor) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr : array<mat3x3<f32>, 4>;
+
+fn f() {
+ arr[0][1][2] = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+fn f() {
+ arr[0][1].elements[2] = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Vec3_ReadStruct) {
auto* src = R"(
struct S {
v : vec3<f32>,
}
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+fn tint_unpack_vec3_in_composite(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.v = vec3<f32>(in.v);
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite(P);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Vec3_ReadVector) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.v;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = vec3<f32>(P.v);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Vec3_ReadComponent_MemberAccessChain) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.v.yz.x;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = vec3<f32>(P.v).yz.x;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Vec3_ReadComponent_IndexAccessor) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.v[1];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = P.v[1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Vec3_WriteStruct_ValueRHS) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P = S(vec3(1.23));
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+fn tint_pack_vec3_in_composite(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.v = __packed_vec3<f32>(in.v);
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P = tint_pack_vec3_in_composite(S(vec3(1.23)));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Vec3_WriteStruct_RefRHS) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in : S;
+
+fn f() {
+ P = in;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in : S_tint_packed_vec3;
+
+fn f() {
+ P = in;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Vec3_WriteVector_ValueRHS) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.v = vec3(1.23);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.v = __packed_vec3<f32>(vec3(1.23));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Vec3_WriteVector_RefRHS) {
+ auto* src = R"(
+struct S {
+ v1 : vec3<f32>,
+ v2 : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in_str : S;
+@group(0) @binding(2) var<uniform> in_vec : vec3<f32>;
+
+fn f() {
+ P.v1 = in_str.v1;
+ P.v2 = in_vec;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v1 : __packed_vec3<f32>,
+ @align(16)
+ v2 : __packed_vec3<f32>,
+}
+
+struct S {
+ v1 : vec3<f32>,
+ v2 : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in_str : S_tint_packed_vec3;
+
+@group(0) @binding(2) var<uniform> in_vec : __packed_vec3<f32>;
+
+fn f() {
+ P.v1 = in_str.v1;
+ P.v2 = in_vec;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Vec3_WriteComponent_MemberAccessor) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.v.y = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.v.y = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Vec3_WriteComponent_IndexAccessor) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.v[1] = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.v[1] = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_ReadStruct) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.arr = tint_unpack_vec3_in_composite(in.arr);
+ return result;
+}
+
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite_1(P);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_ReadArray) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.arr;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite(P.arr);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_ReadVector) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.arr[0];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = vec3<f32>(P.arr[0].elements);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_ReadComponent_MemberAccessor) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.arr[0].y;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = P.arr[0].elements.y;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_ReadComponent_IndexAccessor) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.arr[0][1];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = P.arr[0].elements[1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_WriteStruct_ValueRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P = S(array(vec3(1.5, 4.5, 7.5), vec3(9.5, 6.5, 3.5)));
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 2u>,
+}
+
+fn tint_pack_vec3_in_composite(in : array<vec3<f32>, 2u>) -> array<tint_packed_vec3_f32_array_element, 2u> {
+ var result : array<tint_packed_vec3_f32_array_element, 2u>;
+ for(var i : u32; (i < 2u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.arr = tint_pack_vec3_in_composite(in.arr);
+ return result;
+}
+
+struct S {
+ arr : array<vec3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P = tint_pack_vec3_in_composite_1(S(array(vec3(1.5, 4.5, 7.5), vec3(9.5, 6.5, 3.5))));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_WriteStruct_RefRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in : S;
+
+fn f() {
+ P = in;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 2u>,
+}
+
+struct S {
+ arr : array<vec3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in : S_tint_packed_vec3;
+
+fn f() {
+ P = in;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_WriteArray_ValueRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.arr = array(vec3(1.5, 4.5, 7.5), vec3(9.5, 6.5, 3.5));
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 2u>,
+}
+
+fn tint_pack_vec3_in_composite(in : array<vec3<f32>, 2u>) -> array<tint_packed_vec3_f32_array_element, 2u> {
+ var result : array<tint_packed_vec3_f32_array_element, 2u>;
+ for(var i : u32; (i < 2u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+struct S {
+ arr : array<vec3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.arr = tint_pack_vec3_in_composite(array(vec3(1.5, 4.5, 7.5), vec3(9.5, 6.5, 3.5)));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_WriteArray_RefRHS) {
+ auto* src = R"(
+struct S {
+ arr1 : array<vec3<f32>, 2>,
+ arr2 : array<vec3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in_str : S;
+@group(0) @binding(2) var<uniform> in_arr : array<vec3<f32>, 2>;
+
+fn f() {
+ P.arr1 = in_str.arr1;
+ P.arr2 = in_arr;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr1 : array<tint_packed_vec3_f32_array_element, 2u>,
+ @align(16)
+ arr2 : array<tint_packed_vec3_f32_array_element, 2u>,
+}
+
+struct S {
+ arr1 : array<vec3<f32>, 2>,
+ arr2 : array<vec3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in_str : S_tint_packed_vec3;
+
+@group(0) @binding(2) var<uniform> in_arr : array<tint_packed_vec3_f32_array_element, 2u>;
+
+fn f() {
+ P.arr1 = in_str.arr1;
+ P.arr2 = in_arr;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_WriteVector_ValueRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.arr[0] = vec3(1.23);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.arr[0].elements = __packed_vec3<f32>(vec3(1.23));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_WriteVector_RefRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in_str : S;
+@group(0) @binding(2) var<uniform> in_arr : array<vec3<f32>, 4>;
+@group(0) @binding(3) var<uniform> in_vec : vec3<f32>;
+
+fn f() {
+ P.arr[0] = in_str.arr[0];
+ P.arr[1] = in_arr[1];
+ P.arr[2] = in_vec;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in_str : S_tint_packed_vec3;
+
+@group(0) @binding(2) var<uniform> in_arr : array<tint_packed_vec3_f32_array_element, 4u>;
+
+@group(0) @binding(3) var<uniform> in_vec : __packed_vec3<f32>;
+
+fn f() {
+ P.arr[0].elements = in_str.arr[0].elements;
+ P.arr[1].elements = in_arr[1].elements;
+ P.arr[2].elements = in_vec;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_WriteComponent_MemberAccessor) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.arr[0].y = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.arr[0].elements.y = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfVec3_WriteComponent_IndexAccessor) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.arr[0][1] = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.arr[0].elements[1] = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_ReadStruct) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.m = tint_unpack_vec3_in_composite(in.m);
+ return result;
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite_1(P);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_ReadMatrix) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.m;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite(P.m);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_ReadColumn) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.m[1];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = vec3<f32>(P.m[1].elements);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_ReadComponent_MemberAccessChain) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.m[1].yz.x;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = vec3<f32>(P.m[1].elements).yz.x;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_ReadComponent_IndexAccessor) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.m[2][1];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = P.m[2].elements[1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_WriteStruct_ValueRHS) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P = S(mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5));
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.m = tint_pack_vec3_in_composite(in.m);
+ return result;
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P = tint_pack_vec3_in_composite_1(S(mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5)));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_WriteStruct_RefRHS) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in : S;
+
+fn f() {
+ P = in;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in : S_tint_packed_vec3;
+
+fn f() {
+ P = in;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_WriteMatrix_ValueRHS) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.m = mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.m = tint_pack_vec3_in_composite(mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_WriteMatrix_RefRHS) {
+ auto* src = R"(
+struct S {
+ m1 : mat3x3<f32>,
+ m2 : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in_str : S;
+@group(0) @binding(2) var<uniform> in_mat : mat3x3<f32>;
+
+fn f() {
+ P.m1 = in_str.m1;
+ P.m2 = in_mat;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m1 : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ m2 : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+struct S {
+ m1 : mat3x3<f32>,
+ m2 : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in_str : S_tint_packed_vec3;
+
+@group(0) @binding(2) var<uniform> in_mat : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ P.m1 = in_str.m1;
+ P.m2 = in_mat;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_WriteColumn_ValueRHS) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.m[1] = vec3(1.23);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.m[1].elements = __packed_vec3<f32>(vec3(1.23));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_WriteColumn_RefRHS) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in_str : S;
+@group(0) @binding(2) var<uniform> in_mat : mat3x3<f32>;
+@group(0) @binding(3) var<uniform> in_vec : vec3<f32>;
+
+fn f() {
+ P.m[0] = in_str.m[0];
+ P.m[1] = in_mat[1];
+ P.m[2] = in_vec;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in_str : S_tint_packed_vec3;
+
+@group(0) @binding(2) var<uniform> in_mat : array<tint_packed_vec3_f32_array_element, 3u>;
+
+@group(0) @binding(3) var<uniform> in_vec : __packed_vec3<f32>;
+
+fn f() {
+ P.m[0].elements = in_str.m[0].elements;
+ P.m[1].elements = in_mat[1].elements;
+ P.m[2].elements = in_vec;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_WriteComponent_MemberAccessor) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.m[1].y = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.m[1].elements.y = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_Matrix_WriteComponent_IndexAccessor) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.m[1][2] = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.m[1].elements[2] = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_ReadStruct) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_2(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.arr = tint_unpack_vec3_in_composite_1(in.arr);
+ return result;
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite_2(P);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_ReadArray) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.arr;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite_1(P.arr);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_ReadMatrix) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.arr[0];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite(P.arr[0]);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_ReadColumn) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.arr[0][1];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = vec3<f32>(P.arr[0][1].elements);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_ReadComponent_MemberAccessor) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.arr[0][1].y;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = P.arr[0][1].elements.y;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_ReadComponent_IndexAccessor) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ let x = P.arr[0][1][2];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = P.arr[0][1].elements[2];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_WriteStruct_ValueRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P = S(array(mat3x3<f32>(), mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5)));
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>,
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : array<mat3x3<f32>, 2u>) -> array<array<tint_packed_vec3_f32_array_element, 3u>, 2u> {
+ var result : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>;
+ for(var i : u32; (i < 2u); i = (i + 1)) {
+ result[i] = tint_pack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_2(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.arr = tint_pack_vec3_in_composite_1(in.arr);
+ return result;
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P = tint_pack_vec3_in_composite_2(S(array(mat3x3<f32>(), mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5))));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_WriteStruct_RefRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in : S;
+
+fn f() {
+ P = in;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>,
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in : S_tint_packed_vec3;
+
+fn f() {
+ P = in;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_WriteArray_ValueRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.arr = array(mat3x3<f32>(), mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5));
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>,
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : array<mat3x3<f32>, 2u>) -> array<array<tint_packed_vec3_f32_array_element, 3u>, 2u> {
+ var result : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>;
+ for(var i : u32; (i < 2u); i = (i + 1)) {
+ result[i] = tint_pack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.arr = tint_pack_vec3_in_composite_1(array(mat3x3<f32>(), mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5)));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_WriteArray_RefRHS) {
+ auto* src = R"(
+struct S {
+ arr1 : array<mat3x3<f32>, 2>,
+ arr2 : array<mat3x3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in_str : S;
+@group(0) @binding(2) var<uniform> in_arr : array<mat3x3<f32>, 2>;
+
+fn f() {
+ P.arr1 = in_str.arr1;
+ P.arr2 = in_arr;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr1 : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>,
+ @align(16)
+ arr2 : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>,
+}
+
+struct S {
+ arr1 : array<mat3x3<f32>, 2>,
+ arr2 : array<mat3x3<f32>, 2>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in_str : S_tint_packed_vec3;
+
+@group(0) @binding(2) var<uniform> in_arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 2u>;
+
+fn f() {
+ P.arr1 = in_str.arr1;
+ P.arr2 = in_arr;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_WriteMatrix_ValueRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.arr[0] = mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.arr[0] = tint_pack_vec3_in_composite(mat3x3(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_WriteMatrix_RefRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in_str : S;
+@group(0) @binding(2) var<uniform> in_arr : array<mat3x3<f32>, 4>;
+@group(0) @binding(3) var<uniform> in_mat : mat3x3<f32>;
+
+fn f() {
+ P.arr[0] = in_str.arr[0];
+ P.arr[1] = in_arr[1];
+ P.arr[2] = in_mat;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in_str : S_tint_packed_vec3;
+
+@group(0) @binding(2) var<uniform> in_arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(3) var<uniform> in_mat : array<tint_packed_vec3_f32_array_element, 3u>;
+
+fn f() {
+ P.arr[0] = in_str.arr[0];
+ P.arr[1] = in_arr[1];
+ P.arr[2] = in_mat;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_WriteVector_ValueRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.arr[0][1] = vec3(1.23);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.arr[0][1].elements = __packed_vec3<f32>(vec3(1.23));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_WriteVector_RefRHS) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(1) var<uniform> in_str : S;
+@group(0) @binding(2) var<uniform> in_arr : array<mat3x3<f32>, 4>;
+@group(0) @binding(3) var<uniform> in_mat : mat3x3<f32>;
+@group(0) @binding(4) var<uniform> in_vec : vec3<f32>;
+
+fn f() {
+ P.arr[0][0] = in_str.arr[0][1];
+ P.arr[1][1] = in_arr[3][2];
+ P.arr[2][2] = in_mat[1];
+ P.arr[3][0] = in_vec;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<uniform> in_str : S_tint_packed_vec3;
+
+@group(0) @binding(2) var<uniform> in_arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(3) var<uniform> in_mat : array<tint_packed_vec3_f32_array_element, 3u>;
+
+@group(0) @binding(4) var<uniform> in_vec : __packed_vec3<f32>;
+
+fn f() {
+ P.arr[0][0].elements = in_str.arr[0][1].elements;
+ P.arr[1][1].elements = in_arr[3][2].elements;
+ P.arr[2][2].elements = in_mat[1].elements;
+ P.arr[3][0].elements = in_vec;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_WriteComponent_MemberAccessor) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.arr[0][1].y = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.arr[0][1].elements.y = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ArrayOfMatrix_WriteComponent_IndexAccessor) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ P.arr[0][1][2] = 1.23;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4u>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ P.arr[0][1].elements[2] = 1.23;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ExistingMemberAttributes) {
+ auto* src = R"(
+struct S {
+ @align(32) @size(32) v : vec3<f32>,
+ @align(64) @size(64) arr : array<vec3<f32>, 4>,
+ @align(128) @size(128) x : u32,
+}
+
@group(0) @binding(0) var<uniform> P : S;
fn f() {
- let x = P.v;
+ let x = P.v[0];
}
)";
auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(32) @size(32)
+ v : __packed_vec3<f32>,
+ @align(64) @size(64)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(128) @size(128)
+ x : u32,
+}
+
struct S {
- @internal(packed_vector)
+ @align(32) @size(32)
v : vec3<f32>,
+ @align(64) @size(64)
+ arr : array<vec3<f32>, 4>,
+ @align(128) @size(128)
+ x : u32,
+}
+
+@group(0) @binding(0) var<uniform> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = P.v[0];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructMember_ExistingMemberAttributes_SizeMatchesUnpackedVec3) {
+ // Test that the type we replace a vec3 with is not larger than it should be.
+ auto* src = R"(
+struct S {
+ @size(12) v : vec3<f32>,
+ @size(64) arr : array<vec3<f32>, 4>,
}
@group(0) @binding(0) var<uniform> P : S;
fn f() {
- let x = vec3<f32>(P.v);
-}
-)";
-
- DataMap data;
- auto got = Run<PackedVec3>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PackedVec3Test, StorageAddressSpace) {
- auto* src = R"(
-struct S {
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = P.v;
+ let x = P.v[0];
}
)";
auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
}
-@group(0) @binding(0) var<storage> P : S;
+struct S_tint_packed_vec3 {
+ @size(12) @align(16)
+ v : __packed_vec3<f32>,
+ @size(64) @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct S {
+ @size(12)
+ v : vec3<f32>,
+ @size(64)
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<uniform> P : S_tint_packed_vec3;
fn f() {
- let x = vec3<f32>(P.v);
+ let x = P.v[0];
}
)";
@@ -135,29 +4095,52 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(PackedVec3Test, ExistingMemberAttributes) {
+TEST_F(PackedVec3Test, StructMember_ExistingMemberAttributes_AlignTooSmall) {
+ // Test that we add an @align() attribute when the new alignment of the packed vec3 struct would
+ // be too small.
auto* src = R"(
struct S {
- @align(32) @size(64) v : vec3<f32>,
+ a : u32,
+ v : vec3<f32>,
+ b : u32,
+ arr : array<vec3<f32>, 4>,
}
-@group(0) @binding(0) var<storage> P : S;
+@group(0) @binding(0) var<uniform> P : S;
fn f() {
- let x = P.v;
+ let x = P.v[0];
}
)";
auto* expect = R"(
-struct S {
- @internal(packed_vector) @align(32) @size(64)
- v : vec3<f32>,
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
}
-@group(0) @binding(0) var<storage> P : S;
+struct S_tint_packed_vec3 {
+ a : u32,
+ @align(16)
+ v : __packed_vec3<f32>,
+ b : u32,
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct S {
+ a : u32,
+ v : vec3<f32>,
+ b : u32,
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<uniform> P : S_tint_packed_vec3;
fn f() {
- let x = vec3<f32>(P.v);
+ let x = P.v[0];
}
)";
@@ -167,7 +4150,441 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(PackedVec3Test, MultipleVectors) {
+TEST_F(PackedVec3Test, StructMember_ExistingMemberAttributes_ExplicitOffset) {
+ // Test that the we do not add an @align attribute if @offset is present.
+
+ // struct S {
+ // a : u32,
+ // @offset(32) v : vec3<f32>,
+ // b : u32,
+ // @offset(128) arr : array<vec3<f32>, 4>,
+ // }
+ //
+ // @group(0) @binding(0) var<uniform> P : S;
+ ProgramBuilder b;
+ b.Structure("S", utils::Vector{
+ b.Member("a", b.ty.u32()),
+ b.Member("v", b.ty.vec3<f32>(), utils::Vector{b.MemberOffset(AInt(32))}),
+ b.Member("b", b.ty.u32()),
+ b.Member("arr", b.ty.array(b.ty.vec3<f32>(), b.Expr(AInt(4))),
+ utils::Vector{b.MemberOffset(AInt(128))}),
+ });
+ b.GlobalVar("P", builtin::AddressSpace::kStorage, b.ty("S"),
+ utils::Vector{b.Group(AInt(0)), b.Binding(AInt(0))});
+ Program src(std::move(b));
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ a : u32,
+ @size(28)
+ padding : u32,
+ /* @offset(32) */
+ v : __packed_vec3<f32>,
+ b : u32,
+ @size(80)
+ padding_1 : u32,
+ /* @offset(128) */
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct S {
+ a : u32,
+ @size(16)
+ padding_2 : u32,
+ /* @offset(32) */
+ v : vec3<f32>,
+ b : u32,
+ @size(80)
+ padding_3 : u32,
+ /* @offset(128) */
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(std::move(src), data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructValueConstructor_ViaIndexAccessor) {
+ auto* src = R"(
+struct S {
+ a : vec3<f32>,
+ b : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> s : S;
+
+fn f() {
+ let value_arr : array<vec3<f32>, 4> = array<vec3<f32>, 4>();
+ let x = S(value_arr[0], s.arr[0], value_arr);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ a : __packed_vec3<f32>,
+ @align(16)
+ b : __packed_vec3<f32>,
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct S {
+ a : vec3<f32>,
+ b : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> s : S_tint_packed_vec3;
+
+fn f() {
+ let value_arr : array<vec3<f32>, 4> = array<vec3<f32>, 4>();
+ let x = S(value_arr[0], vec3<f32>(s.arr[0].elements), value_arr);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, WrapperStructLayout_MixedUsage) {
+ // Test the layout of the generated wrapper struct(s) when vec3s are used in both structures and
+ // arrays.
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+ a : u32,
+}
+
+@group(0) @binding(0) var<storage, read_write> str : S;
+@group(0) @binding(1) var<storage, read_write> arr : array<vec3<f32>, 4>;
+
+fn main() {
+ str.v = arr[0];
+ arr[1] = str.v;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ a : u32,
+}
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S {
+ v : vec3<f32>,
+ a : u32,
+}
+
+@group(0) @binding(0) var<storage, read_write> str : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<storage, read_write> arr : array<tint_packed_vec3_f32_array_element, 4u>;
+
+fn main() {
+ str.v = arr[0].elements;
+ arr[1].elements = str.v;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ auto& vars = got.program.AST().GlobalVariables();
+ ASSERT_EQ(vars.Length(), 2u);
+
+ {
+ // Check the layout of the struct type of "str".
+ // The first member should have an alignment of 16 bytes, a size of 12 bytes, and the second
+ // member should have an offset of 12 bytes.
+ auto* sem_str = got.program.Sem().Get(vars[0]);
+ auto* str_ty = sem_str->Type()->UnwrapRef()->As<sem::Struct>();
+ ASSERT_NE(str_ty, nullptr);
+ ASSERT_EQ(str_ty->Members().Length(), 2u);
+ EXPECT_EQ(str_ty->Members()[0]->Align(), 16u);
+ EXPECT_EQ(str_ty->Members()[0]->Size(), 12u);
+ EXPECT_EQ(str_ty->Members()[1]->Offset(), 12u);
+ }
+
+ {
+ // Check the layout of the array type of "arr".
+ // The element stride should be 16 bytes.
+ auto* sem_arr = got.program.Sem().Get(vars[1]);
+ auto* arr_ty = sem_arr->Type()->UnwrapRef()->As<type::Array>();
+ ASSERT_NE(arr_ty, nullptr);
+ EXPECT_EQ(arr_ty->Stride(), 16u);
+ }
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, PackUnpackStructWithNonVec3Members) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
+ a : u32,
+ b : vec4<f32>,
+ c : array<vec4<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
+
+fn f() {
+ let x = P;
+ P = x;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+ a : u32,
+ b : vec4<f32>,
+ c : array<vec4<f32>, 4>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.v = vec3<f32>(in.v);
+ result.arr = tint_unpack_vec3_in_composite(in.arr);
+ result.a = in.a;
+ result.b = in.b;
+ result.c = in.c;
+ return result;
+}
+
+fn tint_pack_vec3_in_composite(in : array<vec3<f32>, 4u>) -> array<tint_packed_vec3_f32_array_element, 4u> {
+ var result : array<tint_packed_vec3_f32_array_element, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.v = __packed_vec3<f32>(in.v);
+ result.arr = tint_pack_vec3_in_composite(in.arr);
+ result.a = in.a;
+ result.b = in.b;
+ result.c = in.c;
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
+ a : u32,
+ b : vec4<f32>,
+ c : array<vec4<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn f() {
+ let x = tint_unpack_vec3_in_composite_1(P);
+ P = tint_pack_vec3_in_composite_1(x);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Struct_ShaderIO) {
+ // Test that we do not modify structures that are used for shader IO.
+ auto* src = R"(
+struct S1 {
+ @location(0) v : vec3<f32>,
+}
+
+struct S2 {
+ @location(0) v : vec3<f32>,
+ @builtin(position) pos : vec4<f32>,
+}
+
+@vertex
+fn main(s1 : S1) -> S2 {
+ let v : vec3<f32> = s1.v;
+ var s2 : S2;
+ s2.v = v;
+ return s2;
+}
+)";
+
+ auto* expect = R"(
+struct S1 {
+ @location(0)
+ v : vec3<f32>,
+}
+
+struct S2 {
+ @location(0)
+ v : vec3<f32>,
+ @builtin(position)
+ pos : vec4<f32>,
+}
+
+@vertex
+fn main(s1 : S1) -> S2 {
+ let v : vec3<f32> = s1.v;
+ var s2 : S2;
+ s2.v = v;
+ return s2;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ModfReturnStruct) {
+ // Test that we do not try to modify accessors on the anonymous structure returned by modf.
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> output : vec3<f32>;
+
+const values = array(modf(vec3(1.0, 2.0, 3.0)).fract);
+
+@compute @workgroup_size(1)
+fn main() {
+ output = values[0];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+@group(0) @binding(0) var<storage, read_write> output : __packed_vec3<f32>;
+
+const values = array(modf(vec3(1.0, 2.0, 3.0)).fract);
+
+@compute @workgroup_size(1)
+fn main() {
+ output = __packed_vec3<f32>(values[0]);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ModfReturnStruct_PointerToMember) {
+ // Test that we can pass a pointer to the vec3 member of the modf return struct to a function
+ // parameter to which we also pass a pointer to a vec3 member on a host-shareable struct.
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct S {
+ v : vec3<f32>
+}
+
+@group(0) @binding(0) var<storage, read_write> output : S;
+
+fn foo(p : ptr<function, vec3<f32>>) {
+ (*p) = vec3(1, 2, 3);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var f : S;
+ var modf_ret = modf(vec3(1.0, 2.0, 3.0));
+ foo(&f.v);
+ foo(&modf_ret.fract);
+ output.v = modf_ret.fract;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+enable chromium_experimental_full_ptr_parameters;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> output : S_tint_packed_vec3;
+
+fn foo(p : ptr<function, vec3<f32>>) {
+ *(p) = vec3(1, 2, 3);
+}
+
+@compute @workgroup_size(1)
+fn main() {
+ var f : S;
+ var modf_ret = modf(vec3(1.0, 2.0, 3.0));
+ foo(&(f.v));
+ foo(&(modf_ret.fract));
+ output.v = __packed_vec3<f32>(modf_ret.fract);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MultipleStructMembers) {
auto* src = R"(
struct S {
v2_a : vec2<f32>,
@@ -176,6 +4593,9 @@
v2_b : vec2<f32>,
v3_b : vec3<f32>,
v4_b : vec4<f32>,
+ v2_arr : array<vec2<f32>, 4>,
+ v3_arr : array<vec3<f32>, 4>,
+ v4_arr : array<vec4<f32>, 4>,
}
@group(0) @binding(0) var<storage> P : S;
@@ -187,22 +4607,56 @@
let v2_b = P.v2_b;
let v3_b = P.v3_b;
let v4_b = P.v4_b;
+ let v2_arr : array<vec2<f32>, 4> = P.v2_arr;
+ let v3_arr : array<vec3<f32>, 4> = P.v3_arr;
+ let v4_arr : array<vec4<f32>, 4> = P.v4_arr;
}
)";
auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ v2_a : vec2<f32>,
+ @align(16)
+ v3_a : __packed_vec3<f32>,
+ v4_a : vec4<f32>,
+ v2_b : vec2<f32>,
+ @align(16)
+ v3_b : __packed_vec3<f32>,
+ v4_b : vec4<f32>,
+ v2_arr : array<vec2<f32>, 4>,
+ @align(16)
+ v3_arr : array<tint_packed_vec3_f32_array_element, 4u>,
+ v4_arr : array<vec4<f32>, 4>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
struct S {
v2_a : vec2<f32>,
- @internal(packed_vector)
v3_a : vec3<f32>,
v4_a : vec4<f32>,
v2_b : vec2<f32>,
- @internal(packed_vector)
v3_b : vec3<f32>,
v4_b : vec4<f32>,
+ v2_arr : array<vec2<f32>, 4>,
+ v3_arr : array<vec3<f32>, 4>,
+ v4_arr : array<vec4<f32>, 4>,
}
-@group(0) @binding(0) var<storage> P : S;
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
fn f() {
let v2_a = P.v2_a;
@@ -211,6 +4665,9 @@
let v2_b = P.v2_b;
let v3_b = vec3<f32>(P.v3_b);
let v4_b = P.v4_b;
+ let v2_arr : array<vec2<f32>, 4> = P.v2_arr;
+ let v3_arr : array<vec3<f32>, 4> = tint_unpack_vec3_in_composite(P.v3_arr);
+ let v4_arr : array<vec4<f32>, 4> = P.v4_arr;
}
)";
@@ -220,31 +4677,1116 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(PackedVec3Test, MixedAddressSpace) {
+TEST_F(PackedVec3Test, Vec3Pointers) {
auto* src = R"(
struct S {
v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
}
-@group(0) @binding(0) var<storage> P : S;
+@group(0) @binding(0) var<storage, read_write> v : vec3<f32>;
+@group(0) @binding(1) var<storage, read_write> arr_v : array<vec3<f32>, 4>;
+@group(0) @binding(2) var<storage, read_write> m : mat3x3<f32>;
+@group(0) @binding(3) var<storage, read_write> arr_m : array<mat3x3<f32>, 4>;
+@group(0) @binding(4) var<storage, read_write> str : S;
+
+fn f() {
+ let p_v = &v;
+ let v = *p_v;
+ *p_v = v;
+
+ let p_arr_v = &arr_v[0];
+ let arr_v = *p_arr_v;
+ *p_arr_v = arr_v;
+
+ let p_m = &m[0];
+ let m = *p_m;
+ *p_m = m;
+
+ let p_arr_m = &arr_m[0][1];
+ let arr_m = *p_arr_m;
+ *p_arr_m = arr_m;
+
+ let p_str_v = &str.v;
+ let str_v = *p_str_v;
+ *p_str_v = str_v;
+
+ let p_str_arr_v = &str.arr_v[0];
+ let str_arr_v = *p_str_arr_v;
+ *p_str_arr_v = str_arr_v;
+
+ let p_str_m = &str.m[0];
+ let str_m = *p_str_m;
+ *p_str_m = str_m;
+
+ let p_str_arr_m = &str.arr_m[0][1];
+ let str_arr_m = *p_str_arr_m;
+ *p_str_arr_m = str_arr_m;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> v : __packed_vec3<f32>;
+
+@group(0) @binding(1) var<storage, read_write> arr_v : array<tint_packed_vec3_f32_array_element, 4u>;
+
+@group(0) @binding(2) var<storage, read_write> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+@group(0) @binding(3) var<storage, read_write> arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(4) var<storage, read_write> str : S_tint_packed_vec3;
+
+fn f() {
+ let p_v = &(v);
+ let v = vec3<f32>(*(p_v));
+ *(p_v) = __packed_vec3<f32>(v);
+ let p_arr_v = &(arr_v[0].elements);
+ let arr_v = vec3<f32>(*(p_arr_v));
+ *(p_arr_v) = __packed_vec3<f32>(arr_v);
+ let p_m = &(m[0].elements);
+ let m = vec3<f32>(*(p_m));
+ *(p_m) = __packed_vec3<f32>(m);
+ let p_arr_m = &(arr_m[0][1].elements);
+ let arr_m = vec3<f32>(*(p_arr_m));
+ *(p_arr_m) = __packed_vec3<f32>(arr_m);
+ let p_str_v = &(str.v);
+ let str_v = vec3<f32>(*(p_str_v));
+ *(p_str_v) = __packed_vec3<f32>(str_v);
+ let p_str_arr_v = &(str.arr_v[0].elements);
+ let str_arr_v = vec3<f32>(*(p_str_arr_v));
+ *(p_str_arr_v) = __packed_vec3<f32>(str_arr_v);
+ let p_str_m = &(str.m[0].elements);
+ let str_m = vec3<f32>(*(p_str_m));
+ *(p_str_m) = __packed_vec3<f32>(str_m);
+ let p_str_arr_m = &(str.arr_m[0][1].elements);
+ let str_arr_m = vec3<f32>(*(p_str_arr_m));
+ *(p_str_arr_m) = __packed_vec3<f32>(str_arr_m);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MatrixPointers) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> m : mat3x3<f32>;
+@group(0) @binding(1) var<storage, read_write> arr_m : array<mat3x3<f32>, 4>;
+@group(0) @binding(2) var<storage, read_write> str : S;
+
+fn f() {
+ let p_m = &m;
+ let m = *p_m;
+ *p_m = m;
+
+ let p_arr_m = &arr_m[0];
+ let arr_m = *p_arr_m;
+ *p_arr_m = arr_m;
+
+ let p_str_m = &str.m;
+ let str_m = *p_str_m;
+ *p_str_m = str_m;
+
+ let p_str_arr_m = &str.arr_m[0];
+ let str_arr_m = *p_str_arr_m;
+ *p_str_arr_m = str_arr_m;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+struct S {
+ m : mat3x3<f32>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+@group(0) @binding(1) var<storage, read_write> arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(2) var<storage, read_write> str : S_tint_packed_vec3;
+
+fn f() {
+ let p_m = &(m);
+ let m = tint_unpack_vec3_in_composite(*(p_m));
+ *(p_m) = tint_pack_vec3_in_composite(m);
+ let p_arr_m = &(arr_m[0]);
+ let arr_m = tint_unpack_vec3_in_composite(*(p_arr_m));
+ *(p_arr_m) = tint_pack_vec3_in_composite(arr_m);
+ let p_str_m = &(str.m);
+ let str_m = tint_unpack_vec3_in_composite(*(p_str_m));
+ *(p_str_m) = tint_pack_vec3_in_composite(str_m);
+ let p_str_arr_m = &(str.arr_m[0]);
+ let str_arr_m = tint_unpack_vec3_in_composite(*(p_str_arr_m));
+ *(p_str_arr_m) = tint_pack_vec3_in_composite(str_arr_m);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVec3Pointers) {
+ auto* src = R"(
+struct S {
+ arr_v : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_v : array<vec3<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> str : S;
+
+fn f() {
+ let p_arr_v = &arr_v;
+ let arr_v = *p_arr_v;
+ *p_arr_v = arr_v;
+
+ let p_str_arr_v = &str.arr_v;
+ let str_arr_v = *p_str_arr_v;
+ *p_str_arr_v = str_arr_v;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite(in : array<vec3<f32>, 4u>) -> array<tint_packed_vec3_f32_array_element, 4u> {
+ var result : array<tint_packed_vec3_f32_array_element, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+struct S {
+ arr_v : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_v : array<tint_packed_vec3_f32_array_element, 4u>;
+
+@group(0) @binding(1) var<storage, read_write> str : S_tint_packed_vec3;
+
+fn f() {
+ let p_arr_v = &(arr_v);
+ let arr_v = tint_unpack_vec3_in_composite(*(p_arr_v));
+ *(p_arr_v) = tint_pack_vec3_in_composite(arr_v);
+ let p_str_arr_v = &(str.arr_v);
+ let str_arr_v = tint_unpack_vec3_in_composite(*(p_str_arr_v));
+ *(p_str_arr_v) = tint_pack_vec3_in_composite(str_arr_v);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrixPointers) {
+ auto* src = R"(
+struct S {
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_m : array<mat3x3<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> str : S;
+
+fn f() {
+ let p_arr_m = &arr_m;
+ let arr_m = *p_arr_m;
+ *p_arr_m = arr_m;
+
+ let p_str_arr_m = &str.arr_m;
+ let str_arr_m = *p_str_arr_m;
+ *p_str_arr_m = str_arr_m;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : array<mat3x3<f32>, 4u>) -> array<array<tint_packed_vec3_f32_array_element, 3u>, 4u> {
+ var result : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_pack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+struct S {
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(1) var<storage, read_write> str : S_tint_packed_vec3;
+
+fn f() {
+ let p_arr_m = &(arr_m);
+ let arr_m = tint_unpack_vec3_in_composite_1(*(p_arr_m));
+ *(p_arr_m) = tint_pack_vec3_in_composite_1(arr_m);
+ let p_str_arr_m = &(str.arr_m);
+ let str_arr_m = tint_unpack_vec3_in_composite_1(*(p_str_arr_m));
+ *(p_str_arr_m) = tint_pack_vec3_in_composite_1(str_arr_m);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructPointers) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> str : S;
+
+fn f() {
+ let p_str = &str;
+ let str = *p_str;
+ *p_str = str;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_2(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_3(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.v = vec3<f32>(in.v);
+ result.m = tint_unpack_vec3_in_composite(in.m);
+ result.arr_v = tint_unpack_vec3_in_composite_1(in.arr_v);
+ result.arr_m = tint_unpack_vec3_in_composite_2(in.arr_m);
+ return result;
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : array<vec3<f32>, 4u>) -> array<tint_packed_vec3_f32_array_element, 4u> {
+ var result : array<tint_packed_vec3_f32_array_element, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_2(in : array<mat3x3<f32>, 4u>) -> array<array<tint_packed_vec3_f32_array_element, 3u>, 4u> {
+ var result : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_pack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_3(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.v = __packed_vec3<f32>(in.v);
+ result.m = tint_pack_vec3_in_composite(in.m);
+ result.arr_v = tint_pack_vec3_in_composite_1(in.arr_v);
+ result.arr_m = tint_pack_vec3_in_composite_2(in.arr_m);
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> str : S_tint_packed_vec3;
+
+fn f() {
+ let p_str = &(str);
+ let str = tint_unpack_vec3_in_composite_3(*(p_str));
+ *(p_str) = tint_pack_vec3_in_composite_3(str);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, VectorPointerParameters) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> v : vec3<f32>;
+@group(0) @binding(1) var<storage, read_write> arr_v : array<vec3<f32>, 4>;
+@group(0) @binding(2) var<storage, read_write> m : mat3x3<f32>;
+@group(0) @binding(3) var<storage, read_write> arr_m : array<mat3x3<f32>, 4>;
+@group(0) @binding(4) var<storage, read_write> str : S;
+
+fn load(p : ptr<storage, vec3<f32>, read_write>) -> vec3<f32> {
+ return *p;
+}
+
+fn store(p : ptr<storage, vec3<f32>, read_write>) {
+ *p = vec3(1, 2, 3);
+}
+
+fn f() {
+ load(&v);
+ store(&v);
+ load(&arr_v[0]);
+ store(&arr_v[0]);
+ load(&m[0]);
+ store(&m[0]);
+ load(&arr_m[0][1]);
+ store(&arr_m[0][1]);
+ load(&str.v);
+ store(&str.v);
+ load(&str.arr_v[0]);
+ store(&str.arr_v[0]);
+ load(&str.m[0]);
+ store(&str.m[0]);
+ load(&str.arr_m[0][1]);
+ store(&str.arr_m[0][1]);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+enable chromium_experimental_full_ptr_parameters;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> v : __packed_vec3<f32>;
+
+@group(0) @binding(1) var<storage, read_write> arr_v : array<tint_packed_vec3_f32_array_element, 4u>;
+
+@group(0) @binding(2) var<storage, read_write> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+@group(0) @binding(3) var<storage, read_write> arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(4) var<storage, read_write> str : S_tint_packed_vec3;
+
+fn load(p : ptr<storage, __packed_vec3<f32>, read_write>) -> vec3<f32> {
+ return vec3<f32>(*(p));
+}
+
+fn store(p : ptr<storage, __packed_vec3<f32>, read_write>) {
+ *(p) = __packed_vec3<f32>(vec3(1, 2, 3));
+}
+
+fn f() {
+ load(&(v));
+ store(&(v));
+ load(&(arr_v[0].elements));
+ store(&(arr_v[0].elements));
+ load(&(m[0].elements));
+ store(&(m[0].elements));
+ load(&(arr_m[0][1].elements));
+ store(&(arr_m[0][1].elements));
+ load(&(str.v));
+ store(&(str.v));
+ load(&(str.arr_v[0].elements));
+ store(&(str.arr_v[0].elements));
+ load(&(str.m[0].elements));
+ store(&(str.m[0].elements));
+ load(&(str.arr_m[0][1].elements));
+ store(&(str.arr_m[0][1].elements));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MatrixPointerParameters) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct S {
+ m : mat3x3<f32>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> m : mat3x3<f32>;
+@group(0) @binding(1) var<storage, read_write> arr_m : array<mat3x3<f32>, 4>;
+@group(0) @binding(2) var<storage, read_write> str : S;
+
+fn load(p : ptr<storage, mat3x3<f32>, read_write>) -> mat3x3<f32> {
+ return *p;
+}
+
+fn store(p : ptr<storage, mat3x3<f32>, read_write>) {
+ *p = mat3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
+}
+
+fn f() {
+ load(&m);
+ store(&m);
+ load(&arr_m[0]);
+ store(&arr_m[0]);
+ load(&str.m);
+ store(&str.m);
+ load(&str.arr_m[0]);
+ store(&str.arr_m[0]);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+enable chromium_experimental_full_ptr_parameters;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+struct S {
+ m : mat3x3<f32>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+@group(0) @binding(1) var<storage, read_write> arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(2) var<storage, read_write> str : S_tint_packed_vec3;
+
+fn load(p : ptr<storage, array<tint_packed_vec3_f32_array_element, 3u>, read_write>) -> mat3x3<f32> {
+ return tint_unpack_vec3_in_composite(*(p));
+}
+
+fn store(p : ptr<storage, array<tint_packed_vec3_f32_array_element, 3u>, read_write>) {
+ *(p) = tint_pack_vec3_in_composite(mat3x3(1, 2, 3, 4, 5, 6, 7, 8, 9));
+}
+
+fn f() {
+ load(&(m));
+ store(&(m));
+ load(&(arr_m[0]));
+ store(&(arr_m[0]));
+ load(&(str.m));
+ store(&(str.m));
+ load(&(str.arr_m[0]));
+ store(&(str.arr_m[0]));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfVectorPointerParameters) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct S {
+ arr_v : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_v : array<vec3<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> str : S;
+
+fn load(p : ptr<storage, array<vec3<f32>, 4>, read_write>) -> array<vec3<f32>, 4> {
+ return *p;
+}
+
+fn store(p : ptr<storage, array<vec3<f32>, 4>, read_write>) {
+ *p = array(vec3(1.0), vec3(2.0), vec3(3.0), vec3(4.0));
+}
+
+fn f() {
+ load(&arr_v);
+ store(&arr_v);
+ load(&str.arr_v);
+ store(&str.arr_v);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+enable chromium_experimental_full_ptr_parameters;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite(in : array<vec3<f32>, 4u>) -> array<tint_packed_vec3_f32_array_element, 4u> {
+ var result : array<tint_packed_vec3_f32_array_element, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+struct S {
+ arr_v : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_v : array<tint_packed_vec3_f32_array_element, 4u>;
+
+@group(0) @binding(1) var<storage, read_write> str : S_tint_packed_vec3;
+
+fn load(p : ptr<storage, array<tint_packed_vec3_f32_array_element, 4u>, read_write>) -> array<vec3<f32>, 4> {
+ return tint_unpack_vec3_in_composite(*(p));
+}
+
+fn store(p : ptr<storage, array<tint_packed_vec3_f32_array_element, 4u>, read_write>) {
+ *(p) = tint_pack_vec3_in_composite(array(vec3(1.0), vec3(2.0), vec3(3.0), vec3(4.0)));
+}
+
+fn f() {
+ load(&(arr_v));
+ store(&(arr_v));
+ load(&(str.arr_v));
+ store(&(str.arr_v));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ArrayOfMatrixPointerParameters) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct S {
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_m : array<mat3x3<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> str : S;
+
+fn load(p : ptr<storage, array<mat3x3<f32>, 4>, read_write>) -> array<mat3x3<f32>, 4> {
+ return *p;
+}
+
+fn store(p : ptr<storage, array<mat3x3<f32>, 4>, read_write>) {
+ *p = array(mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>());
+}
+
+fn f() {
+ load(&arr_m);
+ store(&arr_m);
+ load(&str.arr_m);
+ store(&str.arr_m);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+enable chromium_experimental_full_ptr_parameters;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : array<mat3x3<f32>, 4u>) -> array<array<tint_packed_vec3_f32_array_element, 3u>, 4u> {
+ var result : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_pack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+struct S {
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(1) var<storage, read_write> str : S_tint_packed_vec3;
+
+fn load(p : ptr<storage, array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>, read_write>) -> array<mat3x3<f32>, 4> {
+ return tint_unpack_vec3_in_composite_1(*(p));
+}
+
+fn store(p : ptr<storage, array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>, read_write>) {
+ *(p) = tint_pack_vec3_in_composite_1(array(mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>()));
+}
+
+fn f() {
+ load(&(arr_m));
+ store(&(arr_m));
+ load(&(str.arr_m));
+ store(&(str.arr_m));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, StructPointerParameters) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> str : S;
+
+fn load(p : ptr<storage, S, read_write>) -> S {
+ return *p;
+}
+
+fn store(p : ptr<storage, S, read_write>) {
+ *p = S();
+}
+
+fn f() {
+ load(&str);
+ store(&str);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+enable chromium_experimental_full_ptr_parameters;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_2(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_3(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.v = vec3<f32>(in.v);
+ result.m = tint_unpack_vec3_in_composite(in.m);
+ result.arr_v = tint_unpack_vec3_in_composite_1(in.arr_v);
+ result.arr_m = tint_unpack_vec3_in_composite_2(in.arr_m);
+ return result;
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : array<vec3<f32>, 4u>) -> array<tint_packed_vec3_f32_array_element, 4u> {
+ var result : array<tint_packed_vec3_f32_array_element, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_2(in : array<mat3x3<f32>, 4u>) -> array<array<tint_packed_vec3_f32_array_element, 3u>, 4u> {
+ var result : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_pack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_3(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.v = __packed_vec3<f32>(in.v);
+ result.m = tint_pack_vec3_in_composite(in.m);
+ result.arr_v = tint_pack_vec3_in_composite_1(in.arr_v);
+ result.arr_m = tint_pack_vec3_in_composite_2(in.arr_m);
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> str : S_tint_packed_vec3;
+
+fn load(p : ptr<storage, S_tint_packed_vec3, read_write>) -> S {
+ return tint_unpack_vec3_in_composite_3(*(p));
+}
+
+fn store(p : ptr<storage, S_tint_packed_vec3, read_write>) {
+ *(p) = tint_pack_vec3_in_composite_3(S());
+}
+
+fn f() {
+ load(&(str));
+ store(&(str));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MixedAddressSpace_Struct) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S;
fn f() {
var f : S;
- let x = f.v;
+ let v = f.v;
+ let arr = f.arr;
+ P = f;
}
)";
auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
}
-@group(0) @binding(0) var<storage> P : S;
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+fn tint_pack_vec3_in_composite(in : array<vec3<f32>, 4u>) -> array<tint_packed_vec3_f32_array_element, 4u> {
+ var result : array<tint_packed_vec3_f32_array_element, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.v = __packed_vec3<f32>(in.v);
+ result.arr = tint_pack_vec3_in_composite(in.arr);
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
fn f() {
var f : S;
- let x = vec3<f32>(f.v);
+ let v = f.v;
+ let arr = f.arr;
+ P = tint_pack_vec3_in_composite_1(f);
}
)";
@@ -254,29 +5796,88 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(PackedVec3Test, ReadMemberAccessChain) {
+TEST_F(PackedVec3Test, MixedAddressSpace_NestedStruct) {
auto* src = R"(
struct S {
v : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
}
-@group(0) @binding(0) var<storage> P : S;
+struct Outer {
+ inner : S,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : Outer;
fn f() {
- let x = P.v.yz.x;
+ var f : Outer;
+ let v = f.inner.v;
+ let arr = f.inner.arr;
+ P = f;
+ P.inner = f.inner;
+ P.inner.v = f.inner.v;
}
)";
auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
}
-@group(0) @binding(0) var<storage> P : S;
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+struct Outer_tint_packed_vec3 {
+ @align(16)
+ inner : S_tint_packed_vec3,
+}
+
+fn tint_pack_vec3_in_composite(in : array<vec3<f32>, 4u>) -> array<tint_packed_vec3_f32_array_element, 4u> {
+ var result : array<tint_packed_vec3_f32_array_element, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.v = __packed_vec3<f32>(in.v);
+ result.arr = tint_pack_vec3_in_composite(in.arr);
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_2(in : Outer) -> Outer_tint_packed_vec3 {
+ var result : Outer_tint_packed_vec3;
+ result.inner = tint_pack_vec3_in_composite_1(in.inner);
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
+}
+
+struct Outer {
+ inner : S,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : Outer_tint_packed_vec3;
fn f() {
- let x = P.v.yz.x;
+ var f : Outer;
+ let v = f.inner.v;
+ let arr = f.inner.arr;
+ P = tint_pack_vec3_in_composite_2(f);
+ P.inner = tint_pack_vec3_in_composite_1(f.inner);
+ P.inner.v = __packed_vec3<f32>(f.inner.v);
}
)";
@@ -286,305 +5887,94 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(PackedVec3Test, ReadVector) {
+TEST_F(PackedVec3Test, MixedAddressSpace_AnotherStructNotShared) {
+ // Test that we can pass a pointers to a members of both shared and non-shared structs to the
+ // same function.
auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
struct S {
v : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
}
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = P.v;
-}
-)";
-
- auto* expect = R"(
-struct S {
- @internal(packed_vector)
+struct NotShared {
v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = vec3<f32>(P.v);
-}
-)";
-
- DataMap data;
- auto got = Run<PackedVec3>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PackedVec3Test, ReadIndexAccessor) {
- auto* src = R"(
-struct S {
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = P.v[1];
-}
-)";
-
- auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = P.v[1];
-}
-)";
-
- DataMap data;
- auto got = Run<PackedVec3>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PackedVec3Test, ReadViaStructPtrDirect) {
- auto* src = R"(
-struct S {
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = (*(&(*(&P)))).v;
-}
-)";
-
- auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = vec3<f32>((*(&(*(&(P))))).v);
-}
-)";
-
- DataMap data;
- auto got = Run<PackedVec3>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PackedVec3Test, ReadViaVectorPtrDirect) {
- auto* src = R"(
-struct S {
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = *(&(*(&(P.v))));
-}
-)";
-
- auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = vec3<f32>(*(&(*(&(P.v)))));
-}
-)";
-
- DataMap data;
- auto got = Run<PackedVec3>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PackedVec3Test, ReadViaStructPtrViaLet) {
- auto* src = R"(
-struct S {
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let p0 = &P;
- let p1 = &(*(p0));
- let a = (*p1).v;
- let p2 = &(*(p1));
- let b = (*p2).v;
- let c = (*p2).v;
-}
-)";
-
- auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let p0 = &(P);
- let p1 = &(*(p0));
- let a = vec3<f32>((*(p1)).v);
- let p2 = &(*(p1));
- let b = vec3<f32>((*(p2)).v);
- let c = vec3<f32>((*(p2)).v);
-}
-)";
-
- DataMap data;
- auto got = Run<PackedVec3>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PackedVec3Test, ReadViaVectorPtrViaLet) {
- auto* src = R"(
-struct S {
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let p0 = &(P.v);
- let p1 = &(*(p0));
- let a = *p1;
- let p2 = &(*(p1));
- let b = *p2;
- let c = *p2;
-}
-)";
-
- auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let p0 = &(P.v);
- let p1 = &(*(p0));
- let a = vec3<f32>(*(p1));
- let p2 = &(*(p1));
- let b = vec3<f32>(*(p2));
- let c = vec3<f32>(*(p2));
-}
-)";
-
- DataMap data;
- auto got = Run<PackedVec3>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PackedVec3Test, ReadUnaryOp) {
- auto* src = R"(
-struct S {
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = -P.v;
-}
-)";
-
- auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = -(vec3<f32>(P.v));
-}
-)";
-
- DataMap data;
- auto got = Run<PackedVec3>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PackedVec3Test, ReadBinaryOp) {
- auto* src = R"(
-struct S {
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = P.v + P.v;
-}
-)";
-
- auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
-}
-
-@group(0) @binding(0) var<storage> P : S;
-
-fn f() {
- let x = (vec3<f32>(P.v) + vec3<f32>(P.v));
-}
-)";
-
- DataMap data;
- auto got = Run<PackedVec3>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(PackedVec3Test, WriteVector) {
- auto* src = R"(
-struct S {
- v : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
}
@group(0) @binding(0) var<storage, read_write> P : S;
+fn g(p : ptr<function, vec3<f32>>) -> vec3<f32> {
+ return *p;
+}
+
fn f() {
- P.v = vec3(1.23);
+ var f1 : S;
+ var f2 : NotShared;
+ g(&f1.v);
+ g(&f1.arr[0]);
+ g(&f2.v);
+ g(&f2.arr[0]);
+ P = f1;
}
)";
auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
+enable chromium_internal_relaxed_uniform_layout;
+enable chromium_experimental_full_ptr_parameters;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
}
-@group(0) @binding(0) var<storage, read_write> P : S;
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+fn tint_pack_vec3_in_composite(in : array<vec3<f32>, 4u>) -> array<tint_packed_vec3_f32_array_element, 4u> {
+ var result : array<tint_packed_vec3_f32_array_element, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.v = __packed_vec3<f32>(in.v);
+ result.arr = tint_pack_vec3_in_composite(in.arr);
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
+}
+
+struct NotShared {
+ v : vec3<f32>,
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> P : S_tint_packed_vec3;
+
+fn g(p : ptr<function, vec3<f32>>) -> vec3<f32> {
+ return *(p);
+}
fn f() {
- P.v = vec3(1.23);
+ var f1 : S;
+ var f2 : NotShared;
+ g(&(f1.v));
+ g(&(f1.arr[0]));
+ g(&(f2.v));
+ g(&(f2.arr[0]));
+ P = tint_pack_vec3_in_composite_1(f1);
}
)";
@@ -594,29 +5984,103 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(PackedVec3Test, WriteMemberAccess) {
+TEST_F(PackedVec3Test, MixedAddressSpace_InitFromLoad_ExplicitVarType) {
auto* src = R"(
struct S {
v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
}
-@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(0) var<storage> P : S;
fn f() {
- P.v.y = 1.23;
+ var f1 : S = P;
+ var f2 : vec3<f32> = P.v;
+ var f3 : mat3x3<f32> = P.m;
+ var f4 : array<vec3<f32>, 4> = P.arr_v;
+ var f5 : array<mat3x3<f32>, 4> = P.arr_m;
+ let v_1 = f1.v;
+ let v_2 = f2;
+ let v_3 = f3[0];
+ let v_4 = f4[1];
+ let v_5 = f5[2][2];
}
)";
auto* expect = R"(
-struct S {
- @internal(packed_vector)
- v : vec3<f32>,
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
}
-@group(0) @binding(0) var<storage, read_write> P : S;
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_2(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_3(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.v = vec3<f32>(in.v);
+ result.m = tint_unpack_vec3_in_composite(in.m);
+ result.arr_v = tint_unpack_vec3_in_composite_1(in.arr_v);
+ result.arr_m = tint_unpack_vec3_in_composite_2(in.arr_m);
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
fn f() {
- P.v.y = 1.23;
+ var f1 : S = tint_unpack_vec3_in_composite_3(P);
+ var f2 : vec3<f32> = vec3<f32>(P.v);
+ var f3 : mat3x3<f32> = tint_unpack_vec3_in_composite(P.m);
+ var f4 : array<vec3<f32>, 4> = tint_unpack_vec3_in_composite_1(P.arr_v);
+ var f5 : array<mat3x3<f32>, 4> = tint_unpack_vec3_in_composite_2(P.arr_m);
+ let v_1 = f1.v;
+ let v_2 = f2;
+ let v_3 = f3[0];
+ let v_4 = f4[1];
+ let v_5 = f5[2][2];
}
)";
@@ -626,29 +6090,1998 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(PackedVec3Test, WriteIndexAccessor) {
+TEST_F(PackedVec3Test, MixedAddressSpace_InitFromLoad_InferredVarType) {
auto* src = R"(
struct S {
v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
}
-@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(0) var<storage> P : S;
fn f() {
- P.v[1] = 1.23;
+ var f1 = P;
+ var f2 = P.v;
+ var f3 = P.m;
+ var f4 = P.arr_v;
+ var f5 = P.arr_m;
+ let v_1 = f1.v;
+ let v_2 = f2;
+ let v_3 = f3[0];
+ let v_4 = f4[1];
+ let v_5 = f5[2][2];
}
)";
auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_2(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_3(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.v = vec3<f32>(in.v);
+ result.m = tint_unpack_vec3_in_composite(in.m);
+ result.arr_v = tint_unpack_vec3_in_composite_1(in.arr_v);
+ result.arr_m = tint_unpack_vec3_in_composite_2(in.arr_m);
+ return result;
+}
+
struct S {
- @internal(packed_vector)
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ var f1 = tint_unpack_vec3_in_composite_3(P);
+ var f2 = vec3<f32>(P.v);
+ var f3 = tint_unpack_vec3_in_composite(P.m);
+ var f4 = tint_unpack_vec3_in_composite_1(P.arr_v);
+ var f5 = tint_unpack_vec3_in_composite_2(P.arr_m);
+ let v_1 = f1.v;
+ let v_2 = f2;
+ let v_3 = f3[0];
+ let v_4 = f4[1];
+ let v_5 = f5[2][2];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MixedAddressSpace_InitFromValue_ExplicitVarType) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ var f1 : S = S();
+ var f2 : vec3<f32> = vec3<f32>();
+ var f3 : mat3x3<f32> = mat3x3<f32>();
+ var f4 : array<vec3<f32>, 4> = array(vec3<f32>(), vec3<f32>(), vec3<f32>(), vec3<f32>());
+ var f5 : array<mat3x3<f32>, 4> = array(mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>());
+ let v_1 = f1.v;
+ let v_2 = f2;
+ let v_3 = f3[0];
+ let v_4 = f4[1];
+ let v_5 = f5[2][2];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ var f1 : S = S();
+ var f2 : vec3<f32> = vec3<f32>();
+ var f3 : mat3x3<f32> = mat3x3<f32>();
+ var f4 : array<vec3<f32>, 4> = array(vec3<f32>(), vec3<f32>(), vec3<f32>(), vec3<f32>());
+ var f5 : array<mat3x3<f32>, 4> = array(mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>());
+ let v_1 = f1.v;
+ let v_2 = f2;
+ let v_3 = f3[0];
+ let v_4 = f4[1];
+ let v_5 = f5[2][2];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MixedAddressSpace_InitFromValue_InferredVarType) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ var f1 = S();
+ var f2 = vec3<f32>();
+ var f3 = mat3x3<f32>();
+ var f4 = array(vec3<f32>(), vec3<f32>(), vec3<f32>(), vec3<f32>());
+ var f5 = array(mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>());
+ let v_1 = f1.v;
+ let v_2 = f2;
+ let v_3 = f3[0];
+ let v_4 = f4[1];
+ let v_5 = f5[2][2];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ var f1 = S();
+ var f2 = vec3<f32>();
+ var f3 = mat3x3<f32>();
+ var f4 = array(vec3<f32>(), vec3<f32>(), vec3<f32>(), vec3<f32>());
+ var f5 = array(mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>(), mat3x3<f32>());
+ let v_1 = f1.v;
+ let v_2 = f2;
+ let v_3 = f3[0];
+ let v_4 = f4[1];
+ let v_5 = f5[2][2];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MixedAddressSpace_Pointers_Function) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn f() {
+ var f1 : S = P;
+ var f2 : vec3<f32> = P.v;
+ var f3 : array<vec3<f32>, 4>;
+ var f4 : mat3x3<f32> = P.m;
+ let pv_1 : ptr<function, vec3<f32>> = &f1.v;
+ let pv_2 : ptr<function, vec3<f32>> = &f2;
+ let pv_3 : ptr<function, vec3<f32>> = &f3[0];
+ let pv_4 : ptr<function, mat3x3<f32>> = &f1.m;
+ let pv_5 : ptr<function, mat3x3<f32>> = &f4;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.v = vec3<f32>(in.v);
+ result.m = tint_unpack_vec3_in_composite(in.m);
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn f() {
+ var f1 : S = tint_unpack_vec3_in_composite_1(P);
+ var f2 : vec3<f32> = vec3<f32>(P.v);
+ var f3 : array<vec3<f32>, 4>;
+ var f4 : mat3x3<f32> = tint_unpack_vec3_in_composite(P.m);
+ let pv_1 : ptr<function, vec3<f32>> = &(f1.v);
+ let pv_2 : ptr<function, vec3<f32>> = &(f2);
+ let pv_3 : ptr<function, vec3<f32>> = &(f3[0]);
+ let pv_4 : ptr<function, mat3x3<f32>> = &(f1.m);
+ let pv_5 : ptr<function, mat3x3<f32>> = &(f4);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MixedAddressSpace_Pointers_Private) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+var<private> p1 : S;
+var<private> p2 : vec3<f32>;
+var<private> p3 : array<vec3<f32>, 4>;
+var<private> p4 : mat3x3<f32>;
+
+fn f() {
+ let pv_1 : ptr<private, vec3<f32>> = &p1.v;
+ let pv_2 : ptr<private, vec3<f32>> = &p2;
+ let pv_3 : ptr<private, vec3<f32>> = &p3[0];
+ let pv_4 : ptr<private, mat3x3<f32>> = &p1.m;
+ let pv_5 : ptr<private, mat3x3<f32>> = &p4;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+var<private> p1 : S;
+
+var<private> p2 : vec3<f32>;
+
+var<private> p3 : array<vec3<f32>, 4>;
+
+var<private> p4 : mat3x3<f32>;
+
+fn f() {
+ let pv_1 : ptr<private, vec3<f32>> = &(p1.v);
+ let pv_2 : ptr<private, vec3<f32>> = &(p2);
+ let pv_3 : ptr<private, vec3<f32>> = &(p3[0]);
+ let pv_4 : ptr<private, mat3x3<f32>> = &(p1.m);
+ let pv_5 : ptr<private, mat3x3<f32>> = &(p4);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MixedAddressSpace_Pointers_Workgroup) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+var<workgroup> w1 : S;
+var<workgroup> w2 : vec3<f32>;
+var<workgroup> w3 : array<vec3<f32>, 4>;
+var<workgroup> w4 : mat3x3<f32>;
+
+fn f() {
+ let pv_1 : ptr<workgroup, vec3<f32>> = &w1.v;
+ let pv_2 : ptr<workgroup, vec3<f32>> = &w2;
+ let pv_3 : ptr<workgroup, vec3<f32>> = &w3[0];
+ let pv_4 : ptr<workgroup, mat3x3<f32>> = &w1.m;
+ let pv_5 : ptr<workgroup, mat3x3<f32>> = &w4;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+var<workgroup> w1 : S;
+
+var<workgroup> w2 : vec3<f32>;
+
+var<workgroup> w3 : array<vec3<f32>, 4>;
+
+var<workgroup> w4 : mat3x3<f32>;
+
+fn f() {
+ let pv_1 : ptr<workgroup, vec3<f32>> = &(w1.v);
+ let pv_2 : ptr<workgroup, vec3<f32>> = &(w2);
+ let pv_3 : ptr<workgroup, vec3<f32>> = &(w3[0]);
+ let pv_4 : ptr<workgroup, mat3x3<f32>> = &(w1.m);
+ let pv_5 : ptr<workgroup, mat3x3<f32>> = &(w4);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MixedAddressSpace_PointerParameters) {
+ auto* src = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S;
+
+fn g_v(p : ptr<function, vec3<f32>>) -> vec3<f32> {
+ return *p;
+}
+
+fn g_m(p : ptr<function, mat3x3<f32>>) -> mat3x3<f32> {
+ return *p;
+}
+
+fn f() {
+ var f1 : S = P;
+ var f2 : vec3<f32> = P.v;
+ var f3 : array<vec3<f32>, 4>;
+ var f4 : mat3x3<f32> = P.m;
+ g_v(&f1.v);
+ g_v(&f2);
+ g_v(&f3[0]);
+ g_m(&f1.m);
+ g_m(&f4);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+enable chromium_experimental_full_ptr_parameters;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.v = vec3<f32>(in.v);
+ result.m = tint_unpack_vec3_in_composite(in.m);
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage> P : S_tint_packed_vec3;
+
+fn g_v(p : ptr<function, vec3<f32>>) -> vec3<f32> {
+ return *(p);
+}
+
+fn g_m(p : ptr<function, mat3x3<f32>>) -> mat3x3<f32> {
+ return *(p);
+}
+
+fn f() {
+ var f1 : S = tint_unpack_vec3_in_composite_1(P);
+ var f2 : vec3<f32> = vec3<f32>(P.v);
+ var f3 : array<vec3<f32>, 4>;
+ var f4 : mat3x3<f32> = tint_unpack_vec3_in_composite(P.m);
+ g_v(&(f1.v));
+ g_v(&(f2));
+ g_v(&(f3[0]));
+ g_m(&(f1.m));
+ g_m(&(f4));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, WriteVec3Swizzle_FromRef) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> v : vec3<f32>;
+
+fn f() {
+ v = v.zyx;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+@group(0) @binding(0) var<storage, read_write> v : __packed_vec3<f32>;
+
+fn f() {
+ v = __packed_vec3<f32>(vec3<f32>(v).zyx);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, WriteVec3Swizzle_FromValue) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> v : vec3<f32>;
+
+fn f() {
+ v = vec3f(1, 2, 3).zyx;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+@group(0) @binding(0) var<storage, read_write> v : __packed_vec3<f32>;
+
+fn f() {
+ v = __packed_vec3<f32>(vec3f(1, 2, 3).zyx);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, WriteVec3Component_FromPackedValueIndexAccessor) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>
+}
+
+@group(0) @binding(0) var<storage, read_write> s : S;
+
+fn g() -> S {
+ return S();
+}
+
+fn f() {
+ s.v[0] = g().v[1];
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+struct S {
v : vec3<f32>,
}
-@group(0) @binding(0) var<storage, read_write> P : S;
+@group(0) @binding(0) var<storage, read_write> s : S_tint_packed_vec3;
+
+fn g() -> S {
+ return S();
+}
fn f() {
- P.v[1] = 1.23;
+ s.v[0] = g().v[1];
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ExtractVec3FromStructValueExpression) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S;
+
+fn f() {
+ var v_var : vec3<f32> = S().v;
+ let v_let : vec3<f32> = S().v;
+ v_var = S().v;
+ v_var = S().v * 2.0;
+ buffer = S(S().v);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+}
+
+fn tint_pack_vec3_in_composite(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.v = __packed_vec3<f32>(in.v);
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S_tint_packed_vec3;
+
+fn f() {
+ var v_var : vec3<f32> = S().v;
+ let v_let : vec3<f32> = S().v;
+ v_var = S().v;
+ v_var = (S().v * 2.0);
+ buffer = tint_pack_vec3_in_composite(S(S().v));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ExtractArrayOfVec3FromStructValueExpression) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S;
+
+fn f() {
+ var arr_var : array<vec3<f32>, 4> = S().arr;
+ let arr_let : array<vec3<f32>, 4> = S().arr;
+ arr_var = S().arr;
+ arr_var[0] = S().arr[0] * 2.0;
+ buffer = S(S().arr);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element, 4u>,
+}
+
+fn tint_pack_vec3_in_composite(in : array<vec3<f32>, 4u>) -> array<tint_packed_vec3_f32_array_element, 4u> {
+ var result : array<tint_packed_vec3_f32_array_element, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.arr = tint_pack_vec3_in_composite(in.arr);
+ return result;
+}
+
+struct S {
+ arr : array<vec3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S_tint_packed_vec3;
+
+fn f() {
+ var arr_var : array<vec3<f32>, 4> = S().arr;
+ let arr_let : array<vec3<f32>, 4> = S().arr;
+ arr_var = S().arr;
+ arr_var[0] = (S().arr[0] * 2.0);
+ buffer = tint_pack_vec3_in_composite_1(S(S().arr));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ExtractNestedArrayFromStructValueExpression) {
+ auto* src = R"(
+struct S {
+ arr : array<array<vec3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S;
+
+fn f() {
+ var arr_var : array<array<vec3<f32>, 4>, 4> = S().arr;
+ var inner_var : array<vec3<f32>, 4> = S().arr[0];
+ let arr_let : array<array<vec3<f32>, 4>, 4> = S().arr;
+ arr_var = S().arr;
+ inner_var = S().arr[0];
+ arr_var[0][0] = S().arr[0][0] * 2.0;
+ buffer = S(S().arr);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>,
+}
+
+fn tint_pack_vec3_in_composite(in : array<vec3<f32>, 4u>) -> array<tint_packed_vec3_f32_array_element, 4u> {
+ var result : array<tint_packed_vec3_f32_array_element, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : array<array<vec3<f32>, 4u>, 4u>) -> array<array<tint_packed_vec3_f32_array_element, 4u>, 4u> {
+ var result : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_pack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_2(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.arr = tint_pack_vec3_in_composite_1(in.arr);
+ return result;
+}
+
+struct S {
+ arr : array<array<vec3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S_tint_packed_vec3;
+
+fn f() {
+ var arr_var : array<array<vec3<f32>, 4>, 4> = S().arr;
+ var inner_var : array<vec3<f32>, 4> = S().arr[0];
+ let arr_let : array<array<vec3<f32>, 4>, 4> = S().arr;
+ arr_var = S().arr;
+ inner_var = S().arr[0];
+ arr_var[0][0] = (S().arr[0][0] * 2.0);
+ buffer = tint_pack_vec3_in_composite_2(S(S().arr));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ExtractMatrixFromStructValueExpression) {
+ auto* src = R"(
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S;
+
+fn f() {
+ var m_var : mat3x3<f32> = S().m;
+ let m_let : mat3x3<f32> = S().m;
+ m_var = S().m;
+ m_var = S().m * 2.0;
+ buffer = S(S().m);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.m = tint_pack_vec3_in_composite(in.m);
+ return result;
+}
+
+struct S {
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S_tint_packed_vec3;
+
+fn f() {
+ var m_var : mat3x3<f32> = S().m;
+ let m_let : mat3x3<f32> = S().m;
+ m_var = S().m;
+ m_var = (S().m * 2.0);
+ buffer = tint_pack_vec3_in_composite_1(S(S().m));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, ExtractArrayOfMatrixFromStructValueExpression) {
+ auto* src = R"(
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S;
+
+fn f() {
+ var arr_var : array<mat3x3<f32>, 4> = S().arr;
+ let arr_let : array<mat3x3<f32>, 4> = S().arr;
+ arr_var = S().arr;
+ arr_var[0] = S().arr[0] * 2.0;
+ buffer = S(S().arr);
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+}
+
+fn tint_pack_vec3_in_composite(in : mat3x3<f32>) -> array<tint_packed_vec3_f32_array_element, 3u> {
+ var result : array<tint_packed_vec3_f32_array_element, 3u>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = tint_packed_vec3_f32_array_element(__packed_vec3<f32>(in[i]));
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_1(in : array<mat3x3<f32>, 4u>) -> array<array<tint_packed_vec3_f32_array_element, 3u>, 4u> {
+ var result : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_pack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_pack_vec3_in_composite_2(in : S) -> S_tint_packed_vec3 {
+ var result : S_tint_packed_vec3;
+ result.arr = tint_pack_vec3_in_composite_1(in.arr);
+ return result;
+}
+
+struct S {
+ arr : array<mat3x3<f32>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S_tint_packed_vec3;
+
+fn f() {
+ var arr_var : array<mat3x3<f32>, 4> = S().arr;
+ let arr_let : array<mat3x3<f32>, 4> = S().arr;
+ arr_var = S().arr;
+ arr_var[0] = (S().arr[0] * 2.0);
+ buffer = tint_pack_vec3_in_composite_2(S(S().arr));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, NestedArrays_Let) {
+ auto* src = R"(
+struct S {
+ arr_v : array<array<vec3<f32>, 4>, 4>,
+ arr_m : array<array<mat3x3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_s : array<S, 4>;
+
+fn f() {
+ let full_let : array<S, 4> = arr_s;
+ let struct_let : S = arr_s[0];
+ let outer_arr_v_let : array<array<vec3<f32>, 4>, 4> = arr_s[0].arr_v;
+ let inner_arr_v_let : array<vec3<f32>, 4> = arr_s[0].arr_v[1];
+ let v_let : vec3<f32> = arr_s[0].arr_v[1][2];
+ let v_element_let : f32 = arr_s[0].arr_v[1][2].y;
+ let outer_arr_m_let : array<array<mat3x3<f32>, 4>, 4> = arr_s[0].arr_m;
+ let inner_arr_m_let : array<mat3x3<f32>, 4> = arr_s[0].arr_m[1];
+ let m_let : mat3x3<f32> = arr_s[0].arr_m[1][2];
+ let m_col_let : vec3<f32> = arr_s[0].arr_m[1][2][0];
+ let m_element_let : f32 = arr_s[0].arr_m[1][2][0].y;
+}
+)";
+
+ auto* expect = R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr_v : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>,
+ @align(16)
+ arr_m : array<array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>) -> array<array<vec3<f32>, 4u>, 4u> {
+ var result : array<array<vec3<f32>, 4u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_2(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_3(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite_2(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_4(in : array<array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>, 4u>) -> array<array<mat3x3<f32>, 4u>, 4u> {
+ var result : array<array<mat3x3<f32>, 4u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite_3(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_5(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.arr_v = tint_unpack_vec3_in_composite_1(in.arr_v);
+ result.arr_m = tint_unpack_vec3_in_composite_4(in.arr_m);
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_6(in : array<S_tint_packed_vec3, 4u>) -> array<S, 4u> {
+ var result : array<S, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite_5(in[i]);
+ }
+ return result;
+}
+
+struct S {
+ arr_v : array<array<vec3<f32>, 4>, 4>,
+ arr_m : array<array<mat3x3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_s : array<S_tint_packed_vec3, 4u>;
+
+fn f() {
+ let full_let : array<S, 4> = tint_unpack_vec3_in_composite_6(arr_s);
+ let struct_let : S = tint_unpack_vec3_in_composite_5(arr_s[0]);
+ let outer_arr_v_let : array<array<vec3<f32>, 4>, 4> = tint_unpack_vec3_in_composite_1(arr_s[0].arr_v);
+ let inner_arr_v_let : array<vec3<f32>, 4> = tint_unpack_vec3_in_composite(arr_s[0].arr_v[1]);
+ let v_let : vec3<f32> = vec3<f32>(arr_s[0].arr_v[1][2].elements);
+ let v_element_let : f32 = arr_s[0].arr_v[1][2].elements.y;
+ let outer_arr_m_let : array<array<mat3x3<f32>, 4>, 4> = tint_unpack_vec3_in_composite_4(arr_s[0].arr_m);
+ let inner_arr_m_let : array<mat3x3<f32>, 4> = tint_unpack_vec3_in_composite_3(arr_s[0].arr_m[1]);
+ let m_let : mat3x3<f32> = tint_unpack_vec3_in_composite_2(arr_s[0].arr_m[1][2]);
+ let m_col_let : vec3<f32> = vec3<f32>(arr_s[0].arr_m[1][2][0].elements);
+ let m_element_let : f32 = arr_s[0].arr_m[1][2][0].elements.y;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, NestedArrays_VarInit) {
+ auto* src = R"(
+struct S {
+ arr_v : array<array<vec3<f32>, 4>, 4>,
+ arr_m : array<array<mat3x3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_s : array<S, 4>;
+
+fn f() {
+ var full_var : array<S, 4> = arr_s;
+ var struct_var : S = arr_s[0];
+ var outer_arr_v_var : array<array<vec3<f32>, 4>, 4> = arr_s[0].arr_v;
+ var inner_arr_v_var : array<vec3<f32>, 4> = arr_s[0].arr_v[1];
+ var v_var : vec3<f32> = arr_s[0].arr_v[1][2];
+ var v_element_var : f32 = arr_s[0].arr_v[1][2].y;
+ var outer_arr_m_var : array<array<mat3x3<f32>, 4>, 4> = arr_s[0].arr_m;
+ var inner_arr_m_var : array<mat3x3<f32>, 4> = arr_s[0].arr_m[1];
+ var m_var : mat3x3<f32> = arr_s[0].arr_m[1][2];
+ var m_col_var : vec3<f32> = arr_s[0].arr_m[1][2][0];
+ var m_element_var : f32 = arr_s[0].arr_m[1][2][0].y;
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr_v : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>,
+ @align(16)
+ arr_m : array<array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>) -> array<array<vec3<f32>, 4u>, 4u> {
+ var result : array<array<vec3<f32>, 4u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_2(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_3(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite_2(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_4(in : array<array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>, 4u>) -> array<array<mat3x3<f32>, 4u>, 4u> {
+ var result : array<array<mat3x3<f32>, 4u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite_3(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_5(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.arr_v = tint_unpack_vec3_in_composite_1(in.arr_v);
+ result.arr_m = tint_unpack_vec3_in_composite_4(in.arr_m);
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_6(in : array<S_tint_packed_vec3, 4u>) -> array<S, 4u> {
+ var result : array<S, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite_5(in[i]);
+ }
+ return result;
+}
+
+struct S {
+ arr_v : array<array<vec3<f32>, 4>, 4>,
+ arr_m : array<array<mat3x3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_s : array<S_tint_packed_vec3, 4u>;
+
+fn f() {
+ var full_var : array<S, 4> = tint_unpack_vec3_in_composite_6(arr_s);
+ var struct_var : S = tint_unpack_vec3_in_composite_5(arr_s[0]);
+ var outer_arr_v_var : array<array<vec3<f32>, 4>, 4> = tint_unpack_vec3_in_composite_1(arr_s[0].arr_v);
+ var inner_arr_v_var : array<vec3<f32>, 4> = tint_unpack_vec3_in_composite(arr_s[0].arr_v[1]);
+ var v_var : vec3<f32> = vec3<f32>(arr_s[0].arr_v[1][2].elements);
+ var v_element_var : f32 = arr_s[0].arr_v[1][2].elements.y;
+ var outer_arr_m_var : array<array<mat3x3<f32>, 4>, 4> = tint_unpack_vec3_in_composite_4(arr_s[0].arr_m);
+ var inner_arr_m_var : array<mat3x3<f32>, 4> = tint_unpack_vec3_in_composite_3(arr_s[0].arr_m[1]);
+ var m_var : mat3x3<f32> = tint_unpack_vec3_in_composite_2(arr_s[0].arr_m[1][2]);
+ var m_col_var : vec3<f32> = vec3<f32>(arr_s[0].arr_m[1][2][0].elements);
+ var m_element_var : f32 = arr_s[0].arr_m[1][2][0].elements.y;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, NestedArrays_VarAssignment) {
+ auto* src = R"(
+struct S {
+ arr_v : array<array<vec3<f32>, 4>, 4>,
+ arr_m : array<array<mat3x3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_s : array<S, 4>;
+
+fn f() {
+ var full_var : array<S, 4>;
+ var struct_var : S;
+ var outer_arr_v_var : array<array<vec3<f32>, 4>, 4>;
+ var inner_arr_v_var : array<vec3<f32>, 4>;
+ var v_var : vec3<f32>;
+ var v_element_var : f32;
+ var outer_arr_m_var : array<array<mat3x3<f32>, 4>, 4>;
+ var inner_arr_m_var : array<mat3x3<f32>, 4>;
+ var m_var : mat3x3<f32>;
+ var m_col_var : vec3<f32>;
+ var m_element_var : f32;
+
+ full_var = arr_s;
+ struct_var = arr_s[0];
+ outer_arr_v_var = arr_s[0].arr_v;
+ inner_arr_v_var = arr_s[0].arr_v[1];
+ v_var = arr_s[0].arr_v[1][2];
+ v_element_var = arr_s[0].arr_v[1][2].y;
+ outer_arr_m_var = arr_s[0].arr_m;
+ inner_arr_m_var = arr_s[0].arr_m[1];
+ m_var = arr_s[0].arr_m[1][2];
+ m_col_var = arr_s[0].arr_m[1][2][0];
+ m_element_var = arr_s[0].arr_m[1][2][0].y;
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr_v : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>,
+ @align(16)
+ arr_m : array<array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_1(in : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>) -> array<array<vec3<f32>, 4u>, 4u> {
+ var result : array<array<vec3<f32>, 4u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_2(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_3(in : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>) -> array<mat3x3<f32>, 4u> {
+ var result : array<mat3x3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite_2(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_4(in : array<array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>, 4u>) -> array<array<mat3x3<f32>, 4u>, 4u> {
+ var result : array<array<mat3x3<f32>, 4u>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite_3(in[i]);
+ }
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_5(in : S_tint_packed_vec3) -> S {
+ var result : S;
+ result.arr_v = tint_unpack_vec3_in_composite_1(in.arr_v);
+ result.arr_m = tint_unpack_vec3_in_composite_4(in.arr_m);
+ return result;
+}
+
+fn tint_unpack_vec3_in_composite_6(in : array<S_tint_packed_vec3, 4u>) -> array<S, 4u> {
+ var result : array<S, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = tint_unpack_vec3_in_composite_5(in[i]);
+ }
+ return result;
+}
+
+struct S {
+ arr_v : array<array<vec3<f32>, 4>, 4>,
+ arr_m : array<array<mat3x3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_s : array<S_tint_packed_vec3, 4u>;
+
+fn f() {
+ var full_var : array<S, 4>;
+ var struct_var : S;
+ var outer_arr_v_var : array<array<vec3<f32>, 4>, 4>;
+ var inner_arr_v_var : array<vec3<f32>, 4>;
+ var v_var : vec3<f32>;
+ var v_element_var : f32;
+ var outer_arr_m_var : array<array<mat3x3<f32>, 4>, 4>;
+ var inner_arr_m_var : array<mat3x3<f32>, 4>;
+ var m_var : mat3x3<f32>;
+ var m_col_var : vec3<f32>;
+ var m_element_var : f32;
+ full_var = tint_unpack_vec3_in_composite_6(arr_s);
+ struct_var = tint_unpack_vec3_in_composite_5(arr_s[0]);
+ outer_arr_v_var = tint_unpack_vec3_in_composite_1(arr_s[0].arr_v);
+ inner_arr_v_var = tint_unpack_vec3_in_composite(arr_s[0].arr_v[1]);
+ v_var = vec3<f32>(arr_s[0].arr_v[1][2].elements);
+ v_element_var = arr_s[0].arr_v[1][2].elements.y;
+ outer_arr_m_var = tint_unpack_vec3_in_composite_4(arr_s[0].arr_m);
+ inner_arr_m_var = tint_unpack_vec3_in_composite_3(arr_s[0].arr_m[1]);
+ m_var = tint_unpack_vec3_in_composite_2(arr_s[0].arr_m[1][2]);
+ m_col_var = vec3<f32>(arr_s[0].arr_m[1][2][0].elements);
+ m_element_var = arr_s[0].arr_m[1][2][0].elements.y;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, RuntimeSizedArray) {
+ auto* src = R"(
+struct S {
+ arr : array<vec3<f32>>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_v : array<vec3<f32>>;
+@group(0) @binding(1) var<storage, read_write> s : S;
+
+fn main() {
+ s.arr[0] = arr_v[0];
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ arr : array<tint_packed_vec3_f32_array_element>,
+}
+
+struct S {
+ arr : array<vec3<f32>>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_v : array<tint_packed_vec3_f32_array_element>;
+
+@group(0) @binding(1) var<storage, read_write> s : S_tint_packed_vec3;
+
+fn main() {
+ s.arr[0].elements = arr_v[0].elements;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Mat3x3_F16_Uniform) {
+ // Test that array element alignment validation rules do not trigger when we rewrite an f16
+ // matrix into an array of vec3s in uniform storage.
+ auto* src = R"(
+enable f16;
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<uniform> m : mat3x3<f16>;
+
+fn g(p : ptr<uniform, mat3x3<f16>>) -> vec3<f16> {
+ return (*p)[0] + vec3<f16>(1);
+}
+
+fn f() {
+ let v = g(&m);
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+enable f16;
+enable chromium_experimental_full_ptr_parameters;
+
+struct tint_packed_vec3_f16_array_element {
+ @align(8)
+ elements : __packed_vec3<f16>,
+}
+
+@group(0) @binding(0) var<uniform> m : array<tint_packed_vec3_f16_array_element, 3u>;
+
+fn g(p : ptr<uniform, array<tint_packed_vec3_f16_array_element, 3u>>) -> vec3<f16> {
+ return (vec3<f16>((*(p))[0].elements) + vec3<f16>(1));
+}
+
+fn f() {
+ let v = g(&(m));
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MultipleComponentTypes_StructMembers) {
+ auto* src = R"(
+enable f16;
+
+struct S {
+ f : vec3f,
+ h : vec3h,
+ i : vec3i,
+ u : vec3u,
+}
+
+@group(0) @binding(0) var<storage, read_write> s : S;
+
+fn f() {
+ let f = s.f;
+ let h = s.h;
+ let i = s.i;
+ let u = s.u;
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+enable f16;
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ f : __packed_vec3<f32>,
+ @align(8)
+ h : __packed_vec3<f16>,
+ @align(16)
+ i : __packed_vec3<i32>,
+ @align(16)
+ u : __packed_vec3<u32>,
+}
+
+struct S {
+ f : vec3f,
+ h : vec3h,
+ i : vec3i,
+ u : vec3u,
+}
+
+@group(0) @binding(0) var<storage, read_write> s : S_tint_packed_vec3;
+
+fn f() {
+ let f = vec3<f32>(s.f);
+ let h = vec3<f16>(s.h);
+ let i = vec3<i32>(s.i);
+ let u = vec3<u32>(s.u);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, MultipleComponentTypes_ArrayElement) {
+ auto* src = R"(
+enable f16;
+
+@group(0) @binding(0) var<storage, read_write> arr_f : array<vec3f>;
+@group(0) @binding(1) var<storage, read_write> arr_h : array<vec3h>;
+@group(0) @binding(2) var<storage, read_write> arr_i : array<vec3i>;
+@group(0) @binding(3) var<storage, read_write> arr_u : array<vec3u>;
+
+fn main() {
+ let f = arr_f[0];
+ let h = arr_h[0];
+ let i = arr_i[0];
+ let u = arr_u[0];
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+enable f16;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct tint_packed_vec3_f16_array_element {
+ @align(8)
+ elements : __packed_vec3<f16>,
+}
+
+struct tint_packed_vec3_i32_array_element {
+ @align(16)
+ elements : __packed_vec3<i32>,
+}
+
+struct tint_packed_vec3_u32_array_element {
+ @align(16)
+ elements : __packed_vec3<u32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> arr_f : array<tint_packed_vec3_f32_array_element>;
+
+@group(0) @binding(1) var<storage, read_write> arr_h : array<tint_packed_vec3_f16_array_element>;
+
+@group(0) @binding(2) var<storage, read_write> arr_i : array<tint_packed_vec3_i32_array_element>;
+
+@group(0) @binding(3) var<storage, read_write> arr_u : array<tint_packed_vec3_u32_array_element>;
+
+fn main() {
+ let f = vec3<f32>(arr_f[0].elements);
+ let h = vec3<f16>(arr_h[0].elements);
+ let i = vec3<i32>(arr_i[0].elements);
+ let u = vec3<u32>(arr_u[0].elements);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Arithmetic_FromRef) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> buffer_v : vec3<f32>;
+@group(0) @binding(1) var<storage, read_write> buffer_m : mat3x3<f32>;
+@group(0) @binding(2) var<storage, read_write> buffer_arr_v : array<vec3<f32>, 4>;
+@group(0) @binding(3) var<storage, read_write> buffer_arr_m : array<mat3x3<f32>, 4>;
+@group(0) @binding(4) var<storage, read_write> buffer_nested_arr_v : array<array<vec3<f32>, 4>, 4>;
+
+fn f() {
+ var v : vec3<f32> = buffer_v * 2;
+ v = -v;
+ v = buffer_m * v;
+ v = buffer_m[0] + v;
+ v = buffer_arr_v[0] + v;
+ v = buffer_arr_m[0] * v;
+ v = buffer_arr_m[0][1] + v;
+ v = buffer_nested_arr_v[0][0] + v;
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer_v : __packed_vec3<f32>;
+
+@group(0) @binding(1) var<storage, read_write> buffer_m : array<tint_packed_vec3_f32_array_element, 3u>;
+
+@group(0) @binding(2) var<storage, read_write> buffer_arr_v : array<tint_packed_vec3_f32_array_element, 4u>;
+
+@group(0) @binding(3) var<storage, read_write> buffer_arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(4) var<storage, read_write> buffer_nested_arr_v : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>;
+
+fn f() {
+ var v : vec3<f32> = (vec3<f32>(buffer_v) * 2);
+ v = -(v);
+ v = (tint_unpack_vec3_in_composite(buffer_m) * v);
+ v = (vec3<f32>(buffer_m[0].elements) + v);
+ v = (vec3<f32>(buffer_arr_v[0].elements) + v);
+ v = (tint_unpack_vec3_in_composite(buffer_arr_m[0]) * v);
+ v = (vec3<f32>(buffer_arr_m[0][1].elements) + v);
+ v = (vec3<f32>(buffer_nested_arr_v[0][0].elements) + v);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Arithmetic_FromValue) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> buffer_v : vec3f;
+
+fn f() {
+ var v : vec3f = buffer_v;
+ v = -vec3f(1, 2, 3);
+ v = mat3x3f() * v;
+ v = mat3x3f()[0] + v;
+ v = array<vec3f, 4>()[0] + v;
+ v = array<mat3x3f, 4>()[0] * v;
+ v = array<mat3x3f, 4>()[0][1] + v;
+ v = array<array<vec3f, 4>, 4>()[0][0] + v;
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+@group(0) @binding(0) var<storage, read_write> buffer_v : __packed_vec3<f32>;
+
+fn f() {
+ var v : vec3f = vec3<f32>(buffer_v);
+ v = -(vec3f(1, 2, 3));
+ v = (mat3x3f() * v);
+ v = (mat3x3f()[0] + v);
+ v = (array<vec3f, 4>()[0] + v);
+ v = (array<mat3x3f, 4>()[0] * v);
+ v = (array<mat3x3f, 4>()[0][1] + v);
+ v = (array<array<vec3f, 4>, 4>()[0][0] + v);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Arithmetic_FromRefStruct) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+ nested_arr_v : array<array<vec3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S;
+
+fn f() {
+ var v : vec3<f32> = buffer.v * 2;
+ v = -v;
+ v = buffer.m * v;
+ v = buffer.m[0] + v;
+ v = buffer.arr_v[0] + v;
+ v = buffer.arr_m[0] * v;
+ v = buffer.arr_m[0][1] + v;
+ v = buffer.nested_arr_v[0][0] + v;
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+ @align(16)
+ nested_arr_v : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 3u>) -> mat3x3<f32> {
+ var result : mat3x3<f32>;
+ for(var i : u32; (i < 3u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+ nested_arr_v : array<array<vec3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S_tint_packed_vec3;
+
+fn f() {
+ var v : vec3<f32> = (vec3<f32>(buffer.v) * 2);
+ v = -(v);
+ v = (tint_unpack_vec3_in_composite(buffer.m) * v);
+ v = (vec3<f32>(buffer.m[0].elements) + v);
+ v = (vec3<f32>(buffer.arr_v[0].elements) + v);
+ v = (tint_unpack_vec3_in_composite(buffer.arr_m[0]) * v);
+ v = (vec3<f32>(buffer.arr_m[0][1].elements) + v);
+ v = (vec3<f32>(buffer.nested_arr_v[0][0].elements) + v);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Arithmetic_FromValueStruct) {
+ auto* src = R"(
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+ nested_arr_v : array<array<vec3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S;
+
+fn f() {
+ var v : vec3<f32> = S().v;
+ v = -S().v;
+ v = S().m * v;
+ v = S().m[0] + v;
+ v = S().arr_v[0] + v;
+ v = S().arr_m[0] * v;
+ v = S().arr_m[0][1] + v;
+ v = S().nested_arr_v[0][0] + v;
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : __packed_vec3<f32>,
+ @align(16)
+ m : array<tint_packed_vec3_f32_array_element, 3u>,
+ @align(16)
+ arr_v : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(16)
+ arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+ @align(16)
+ nested_arr_v : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>,
+}
+
+struct S {
+ v : vec3<f32>,
+ m : mat3x3<f32>,
+ arr_v : array<vec3<f32>, 4>,
+ arr_m : array<mat3x3<f32>, 4>,
+ nested_arr_v : array<array<vec3<f32>, 4>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S_tint_packed_vec3;
+
+fn f() {
+ var v : vec3<f32> = S().v;
+ v = -(S().v);
+ v = (S().m * v);
+ v = (S().m[0] + v);
+ v = (S().arr_v[0] + v);
+ v = (S().arr_m[0] * v);
+ v = (S().arr_m[0][1] + v);
+ v = (S().nested_arr_v[0][0] + v);
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Aliases) {
+ auto* src = R"(
+alias VecArray = array<vec3<f32>, 4>;
+alias MatArray = array<mat3x3<f32>, 4>;
+alias NestedArray = array<VecArray, 4>;
+
+struct S {
+ v : VecArray,
+ m : MatArray,
+ n : NestedArray,
+}
+
+@group(0) @binding(0) var<storage, read_write> s : S;
+@group(0) @binding(1) var<storage, read_write> arr_v : VecArray;
+@group(0) @binding(2) var<storage, read_write> arr_m : MatArray;
+@group(0) @binding(3) var<storage, read_write> arr_n : NestedArray;
+
+fn g(p : ptr<function, VecArray>) {
+}
+
+fn f() {
+ var f_arr_v : VecArray = s.v;
+ g(&f_arr_v);
+
+ arr_v = s.v;
+ arr_m[0] = s.m[0];
+ arr_n[1][2] = s.n[1][2];
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct tint_packed_vec3_f32_array_element {
+ @align(16)
+ elements : __packed_vec3<f32>,
+}
+
+struct S_tint_packed_vec3 {
+ @align(16)
+ v : array<tint_packed_vec3_f32_array_element, 4u>,
+ @align(16)
+ m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>,
+ @align(16)
+ n : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>,
+}
+
+fn tint_unpack_vec3_in_composite(in : array<tint_packed_vec3_f32_array_element, 4u>) -> array<vec3<f32>, 4u> {
+ var result : array<vec3<f32>, 4u>;
+ for(var i : u32; (i < 4u); i = (i + 1)) {
+ result[i] = vec3<f32>(in[i].elements);
+ }
+ return result;
+}
+
+alias VecArray = array<vec3<f32>, 4>;
+
+alias MatArray = array<mat3x3<f32>, 4>;
+
+alias NestedArray = array<VecArray, 4>;
+
+struct S {
+ v : VecArray,
+ m : MatArray,
+ n : NestedArray,
+}
+
+@group(0) @binding(0) var<storage, read_write> s : S_tint_packed_vec3;
+
+@group(0) @binding(1) var<storage, read_write> arr_v : array<tint_packed_vec3_f32_array_element, 4u>;
+
+@group(0) @binding(2) var<storage, read_write> arr_m : array<array<tint_packed_vec3_f32_array_element, 3u>, 4u>;
+
+@group(0) @binding(3) var<storage, read_write> arr_n : array<array<tint_packed_vec3_f32_array_element, 4u>, 4u>;
+
+fn g(p : ptr<function, VecArray>) {
+}
+
+fn f() {
+ var f_arr_v : VecArray = tint_unpack_vec3_in_composite(s.v);
+ g(&(f_arr_v));
+ arr_v = s.v;
+ arr_m[0] = s.m[0];
+ arr_n[1][2].elements = s.n[1][2].elements;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PackedVec3>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PackedVec3Test, Vec3Bool) {
+ // Make sure that we don't rewrite vec3<bool> types, as the `packed_bool<n>` types are reserved
+ // in MSL and might not be supported everywhere.
+ auto* src = R"(
+struct S {
+ vf : vec3<f32>,
+ af : array<vec3<f32>, 4>,
+ vb : vec3<bool>,
+ ab : array<vec3<bool>, 4>,
+}
+
+// Create a vec3 storage buffer so that the transform is not skipped.
+@group(0) @binding(0) var<storage, read_write> buffer : vec3<f32>;
+
+fn f() {
+ var f : S;
+ f.vf = buffer;
+ buffer = f.af[0];
+}
+)";
+
+ auto* expect =
+ R"(
+enable chromium_internal_relaxed_uniform_layout;
+
+struct S {
+ vf : vec3<f32>,
+ af : array<vec3<f32>, 4>,
+ vb : vec3<bool>,
+ ab : array<vec3<bool>, 4>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : __packed_vec3<f32>;
+
+fn f() {
+ var f : S;
+ f.vf = vec3<f32>(buffer);
+ buffer = __packed_vec3<f32>(f.af[0]);
}
)";
diff --git a/src/tint/transform/preserve_padding.cc b/src/tint/transform/preserve_padding.cc
index cb5a8ee..fbe785c 100644
--- a/src/tint/transform/preserve_padding.cc
+++ b/src/tint/transform/preserve_padding.cc
@@ -147,6 +147,18 @@
return body;
});
},
+ [&](const type::Matrix* mat) {
+ // Call a helper function that assigns each column separately.
+ return call_helper([&]() {
+ utils::Vector<const ast::Statement*, 4> body;
+ for (uint32_t i = 0; i < mat->columns(); i++) {
+ body.Push(MakeAssignment(mat->ColumnType(),
+ b.IndexAccessor(b.Deref(kDestParamName), u32(i)),
+ b.IndexAccessor(kValueParamName, u32(i))));
+ }
+ return body;
+ });
+ },
[&](const sem::Struct* str) {
// Call a helper function that assigns each member separately.
return call_helper([&]() {
@@ -179,6 +191,13 @@
}
return HasPadding(elem_ty);
},
+ [&](const type::Matrix* mat) {
+ auto* col_ty = mat->ColumnType();
+ if (mat->ColumnStride() > col_ty->Size()) {
+ return true;
+ }
+ return HasPadding(col_ty);
+ },
[&](const sem::Struct* str) {
uint32_t current_offset = 0;
for (auto* member : str->Members()) {
diff --git a/src/tint/transform/preserve_padding_test.cc b/src/tint/transform/preserve_padding_test.cc
index 9405210..2b4869a 100644
--- a/src/tint/transform/preserve_padding_test.cc
+++ b/src/tint/transform/preserve_padding_test.cc
@@ -466,6 +466,125 @@
EXPECT_EQ(expect, str(got));
}
+TEST_F(PreservePaddingTest, Mat3x3) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> m : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn foo() {
+ m = mat3x3<f32>();
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> m : mat3x3<f32>;
+
+fn assign_and_preserve_padding(dest : ptr<storage, mat3x3<f32>, read_write>, value : mat3x3<f32>) {
+ (*(dest))[0u] = value[0u];
+ (*(dest))[1u] = value[1u];
+ (*(dest))[2u] = value[2u];
+}
+
+@compute @workgroup_size(1)
+fn foo() {
+ assign_and_preserve_padding(&(m), mat3x3<f32>());
+}
+)";
+
+ auto got = Run<PreservePadding>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PreservePaddingTest, Mat3x3_InStruct) {
+ auto* src = R"(
+struct S {
+ a : u32,
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S;
+
+@compute @workgroup_size(1)
+fn foo() {
+ buffer = S();
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+struct S {
+ a : u32,
+ m : mat3x3<f32>,
+}
+
+@group(0) @binding(0) var<storage, read_write> buffer : S;
+
+fn assign_and_preserve_padding_1(dest : ptr<storage, mat3x3<f32>, read_write>, value : mat3x3<f32>) {
+ (*(dest))[0u] = value[0u];
+ (*(dest))[1u] = value[1u];
+ (*(dest))[2u] = value[2u];
+}
+
+fn assign_and_preserve_padding(dest : ptr<storage, S, read_write>, value : S) {
+ (*(dest)).a = value.a;
+ assign_and_preserve_padding_1(&((*(dest)).m), value.m);
+}
+
+@compute @workgroup_size(1)
+fn foo() {
+ assign_and_preserve_padding(&(buffer), S());
+}
+)";
+
+ auto got = Run<PreservePadding>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(PreservePaddingTest, ArrayOfMat3x3) {
+ auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> arr_m : array<mat3x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn foo() {
+ arr_m = array<mat3x3<f32>, 4>();
+ arr_m[0] = mat3x3<f32>();
+}
+)";
+
+ auto* expect = R"(
+enable chromium_experimental_full_ptr_parameters;
+
+@group(0) @binding(0) var<storage, read_write> arr_m : array<mat3x3<f32>, 4>;
+
+fn assign_and_preserve_padding_1(dest : ptr<storage, mat3x3<f32>, read_write>, value : mat3x3<f32>) {
+ (*(dest))[0u] = value[0u];
+ (*(dest))[1u] = value[1u];
+ (*(dest))[2u] = value[2u];
+}
+
+fn assign_and_preserve_padding(dest : ptr<storage, array<mat3x3<f32>, 4u>, read_write>, value : array<mat3x3<f32>, 4u>) {
+ for(var i = 0u; (i < 4u); i = (i + 1u)) {
+ assign_and_preserve_padding_1(&((*(dest))[i]), value[i]);
+ }
+}
+
+@compute @workgroup_size(1)
+fn foo() {
+ assign_and_preserve_padding(&(arr_m), array<mat3x3<f32>, 4>());
+ assign_and_preserve_padding_1(&(arr_m[0]), mat3x3<f32>());
+}
+)";
+
+ auto got = Run<PreservePadding>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(PreservePaddingTest, NoModify_Vec3) {
auto* src = R"(
@group(0) @binding(0) var<storage, read_write> v : vec3<u32>;
@@ -524,23 +643,6 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(PreservePaddingTest, NoModify_Mat3x3) {
- auto* src = R"(
-@group(0) @binding(0) var<storage, read_write> v : mat3x3<f32>;
-
-@compute @workgroup_size(1)
-fn foo() {
- v = mat3x3<f32>();
-}
-)";
-
- auto* expect = src;
-
- auto got = Run<PreservePadding>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
TEST_F(PreservePaddingTest, NoModify_StructNoPadding) {
auto* src = R"(
struct S {
diff --git a/src/tint/transform/promote_initializers_to_let.cc b/src/tint/transform/promote_initializers_to_let.cc
index e201f11..cb18e04 100644
--- a/src/tint/transform/promote_initializers_to_let.cc
+++ b/src/tint/transform/promote_initializers_to_let.cc
@@ -52,6 +52,11 @@
// Follow const-chains
auto* root_expr = expr;
if (expr->Stage() == sem::EvaluationStage::kConstant) {
+ if (expr->Type()->HoldsAbstract()) {
+ // Do not hoist expressions that are not materialized, as doing so would cause
+ // premature materialization.
+ return false;
+ }
while (auto* user = root_expr->UnwrapMaterialize()->As<sem::VariableUser>()) {
root_expr = user->Variable()->Initializer();
}
diff --git a/src/tint/transform/promote_initializers_to_let_test.cc b/src/tint/transform/promote_initializers_to_let_test.cc
index 1198067..539f513 100644
--- a/src/tint/transform/promote_initializers_to_let_test.cc
+++ b/src/tint/transform/promote_initializers_to_let_test.cc
@@ -1335,5 +1335,17 @@
EXPECT_EQ(expect, str(got));
}
+TEST_F(PromoteInitializersToLetTest, AssignAbstractArray_ToPhony) {
+ // Test that we do not try to hoist an abstract array expression that is the RHS of a phony
+ // assignment, as its type will not be materialized.
+ auto* src = R"(
+fn f() {
+ _ = array(1, 2, 3, 4);
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<PromoteInitializersToLet>(src));
+}
+
} // namespace
} // namespace tint::transform
diff --git a/src/tint/transform/renamer_test.cc b/src/tint/transform/renamer_test.cc
index 8ff6898..fc34251 100644
--- a/src/tint/transform/renamer_test.cc
+++ b/src/tint/transform/renamer_test.cc
@@ -1714,7 +1714,7 @@
for (auto* ty : builtin::kBuiltinStrings) {
std::string_view type(ty);
if (type != "ptr" && type != "atomic" && !utils::HasPrefix(type, "sampler") &&
- !utils::HasPrefix(type, "texture")) {
+ !utils::HasPrefix(type, "texture") && !utils::HasPrefix(type, "__")) {
out.push_back(ty);
}
}
@@ -1924,7 +1924,9 @@
std::vector<const char*> Identifiers() {
std::vector<const char*> out;
for (auto* ident : builtin::kBuiltinStrings) {
- out.push_back(ident);
+ if (!utils::HasPrefix(ident, "__")) {
+ out.push_back(ident);
+ }
}
for (auto* ident : builtin::kAddressSpaceStrings) {
if (!utils::HasPrefix(ident, "_")) {
diff --git a/src/tint/transform/transform.cc b/src/tint/transform/transform.cc
index cc09e6c..ad954ee 100644
--- a/src/tint/transform/transform.cc
+++ b/src/tint/transform/transform.cc
@@ -17,6 +17,7 @@
#include <algorithm>
#include <string>
+#include "src/tint/builtin/builtin.h"
#include "src/tint/program_builder.h"
#include "src/tint/sem/block_statement.h"
#include "src/tint/sem/for_loop_statement.h"
@@ -98,7 +99,12 @@
}
if (auto* v = ty->As<type::Vector>()) {
auto el = CreateASTTypeFor(ctx, v->type());
- return ctx.dst->ty.vec(el, v->Width());
+ if (v->Packed()) {
+ TINT_ASSERT(Transform, v->Width() == 3u);
+ return ctx.dst->ty(builtin::Builtin::kPackedVec3, el);
+ } else {
+ return ctx.dst->ty.vec(el, v->Width());
+ }
}
if (auto* a = ty->As<type::Array>()) {
auto el = CreateASTTypeFor(ctx, a->ElemType());
diff --git a/src/tint/transform/utils/hoist_to_decl_before.cc b/src/tint/transform/utils/hoist_to_decl_before.cc
index 28f6b36..0c2c6eb 100644
--- a/src/tint/transform/utils/hoist_to_decl_before.cc
+++ b/src/tint/transform/utils/hoist_to_decl_before.cc
@@ -44,10 +44,11 @@
switch (kind) {
case VariableKind::kLet: {
- auto builder = [this, expr, name] {
- return b.Decl(b.Let(
- name, Transform::CreateASTTypeFor(ctx, ctx.src->Sem().GetVal(expr)->Type()),
- ctx.CloneWithoutTransform(expr)));
+ auto* ty = ctx.src->Sem().GetVal(expr)->Type();
+ TINT_ASSERT(Transform, !ty->HoldsAbstract());
+ auto builder = [this, expr, name, ty] {
+ return b.Decl(b.Let(name, Transform::CreateASTTypeFor(ctx, ty),
+ ctx.CloneWithoutTransform(expr)));
};
if (!InsertBeforeImpl(before_expr->Stmt(), std::move(builder))) {
return false;
@@ -56,10 +57,11 @@
}
case VariableKind::kVar: {
- auto builder = [this, expr, name] {
- return b.Decl(b.Var(
- name, Transform::CreateASTTypeFor(ctx, ctx.src->Sem().GetVal(expr)->Type()),
- ctx.CloneWithoutTransform(expr)));
+ auto* ty = ctx.src->Sem().GetVal(expr)->Type();
+ TINT_ASSERT(Transform, !ty->HoldsAbstract());
+ auto builder = [this, expr, name, ty] {
+ return b.Decl(b.Var(name, Transform::CreateASTTypeFor(ctx, ty),
+ ctx.CloneWithoutTransform(expr)));
};
if (!InsertBeforeImpl(before_expr->Stmt(), std::move(builder))) {
return false;
@@ -78,7 +80,7 @@
}
}
- // Replace the initializer expression with a reference to the let
+ // Replace the source expression with a reference to the hoisted declaration.
ctx.Replace(expr, b.Expr(name));
return true;
}
diff --git a/src/tint/transform/vertex_pulling.cc b/src/tint/transform/vertex_pulling.cc
index ecc7576..09a68bb 100644
--- a/src/tint/transform/vertex_pulling.cc
+++ b/src/tint/transform/vertex_pulling.cc
@@ -26,6 +26,7 @@
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/map.h"
#include "src/tint/utils/math.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::VertexPulling);
TINT_INSTANTIATE_TYPEINFO(tint::transform::VertexPulling::Config);
@@ -59,7 +60,7 @@
/// @param out the std::ostream to write to
/// @param format the VertexFormat to write
/// @returns out so calls can be chained
-std::ostream& operator<<(std::ostream& out, VertexFormat format) {
+utils::StringStream& operator<<(utils::StringStream& out, VertexFormat format) {
switch (format) {
case VertexFormat::kUint8x2:
return out << "uint8x2";
@@ -379,7 +380,7 @@
// Base types must match between the vertex stream and the WGSL variable
if (!IsTypeCompatible(var_dt, fmt_dt)) {
- std::stringstream err;
+ utils::StringStream err;
err << "VertexAttributeDescriptor for location "
<< std::to_string(attribute_desc.shader_location) << " has format "
<< attribute_desc.format << " but shader expects "
diff --git a/src/tint/type/array.cc b/src/tint/type/array.cc
index dedf986..96c745c 100644
--- a/src/tint/type/array.cc
+++ b/src/tint/type/array.cc
@@ -21,6 +21,7 @@
#include "src/tint/type/manager.h"
#include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::Array);
@@ -81,7 +82,7 @@
}
std::string Array::FriendlyName(const SymbolTable& symbols) const {
- std::ostringstream out;
+ utils::StringStream out;
if (!IsStrideImplicit()) {
out << "@stride(" << stride_ << ") ";
}
diff --git a/src/tint/type/atomic.cc b/src/tint/type/atomic.cc
index 0459394..39e2aae 100644
--- a/src/tint/type/atomic.cc
+++ b/src/tint/type/atomic.cc
@@ -19,6 +19,7 @@
#include "src/tint/type/manager.h"
#include "src/tint/type/reference.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::Atomic);
@@ -42,7 +43,7 @@
}
std::string Atomic::FriendlyName(const SymbolTable& symbols) const {
- std::ostringstream out;
+ utils::StringStream out;
out << "atomic<" << subtype_->FriendlyName(symbols) << ">";
return out.str();
}
diff --git a/src/tint/type/depth_multisampled_texture.cc b/src/tint/type/depth_multisampled_texture.cc
index 84d7c32..fc3b753 100644
--- a/src/tint/type/depth_multisampled_texture.cc
+++ b/src/tint/type/depth_multisampled_texture.cc
@@ -19,6 +19,7 @@
#include "src/tint/type/manager.h"
#include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::DepthMultisampledTexture);
@@ -46,7 +47,7 @@
}
std::string DepthMultisampledTexture::FriendlyName(const SymbolTable&) const {
- std::ostringstream out;
+ utils::StringStream out;
out << "texture_depth_multisampled_" << dim();
return out.str();
}
diff --git a/src/tint/type/depth_texture.cc b/src/tint/type/depth_texture.cc
index ca216e7..90a6127 100644
--- a/src/tint/type/depth_texture.cc
+++ b/src/tint/type/depth_texture.cc
@@ -19,6 +19,7 @@
#include "src/tint/type/manager.h"
#include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::DepthTexture);
@@ -47,7 +48,7 @@
}
std::string DepthTexture::FriendlyName(const SymbolTable&) const {
- std::ostringstream out;
+ utils::StringStream out;
out << "texture_depth_" << dim();
return out.str();
}
diff --git a/src/tint/type/matrix.cc b/src/tint/type/matrix.cc
index 76970e6..195a9e9 100644
--- a/src/tint/type/matrix.cc
+++ b/src/tint/type/matrix.cc
@@ -19,6 +19,7 @@
#include "src/tint/type/manager.h"
#include "src/tint/type/vector.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::Matrix);
@@ -51,7 +52,7 @@
}
std::string Matrix::FriendlyName(const SymbolTable& symbols) const {
- std::ostringstream out;
+ utils::StringStream out;
out << "mat" << columns_ << "x" << rows_ << "<" << subtype_->FriendlyName(symbols) << ">";
return out.str();
}
diff --git a/src/tint/type/multisampled_texture.cc b/src/tint/type/multisampled_texture.cc
index 182ae88..0b2dfd0 100644
--- a/src/tint/type/multisampled_texture.cc
+++ b/src/tint/type/multisampled_texture.cc
@@ -19,6 +19,7 @@
#include "src/tint/type/manager.h"
#include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::MultisampledTexture);
@@ -40,7 +41,7 @@
}
std::string MultisampledTexture::FriendlyName(const SymbolTable& symbols) const {
- std::ostringstream out;
+ utils::StringStream out;
out << "texture_multisampled_" << dim() << "<" << type_->FriendlyName(symbols) << ">";
return out.str();
}
diff --git a/src/tint/type/pointer.cc b/src/tint/type/pointer.cc
index 17bbe1a..aa77816 100644
--- a/src/tint/type/pointer.cc
+++ b/src/tint/type/pointer.cc
@@ -19,6 +19,7 @@
#include "src/tint/type/manager.h"
#include "src/tint/type/reference.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::Pointer);
@@ -43,7 +44,7 @@
}
std::string Pointer::FriendlyName(const SymbolTable& symbols) const {
- std::ostringstream out;
+ utils::StringStream out;
out << "ptr<";
if (address_space_ != builtin::AddressSpace::kUndefined) {
out << address_space_ << ", ";
diff --git a/src/tint/type/reference.cc b/src/tint/type/reference.cc
index 5db6300..03ed224 100644
--- a/src/tint/type/reference.cc
+++ b/src/tint/type/reference.cc
@@ -18,6 +18,7 @@
#include "src/tint/diagnostic/diagnostic.h"
#include "src/tint/type/manager.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::Reference);
@@ -44,7 +45,7 @@
}
std::string Reference::FriendlyName(const SymbolTable& symbols) const {
- std::ostringstream out;
+ utils::StringStream out;
out << "ref<";
if (address_space_ != builtin::AddressSpace::kUndefined) {
out << address_space_ << ", ";
diff --git a/src/tint/type/sampled_texture.cc b/src/tint/type/sampled_texture.cc
index b3e7375..b3e6e10 100644
--- a/src/tint/type/sampled_texture.cc
+++ b/src/tint/type/sampled_texture.cc
@@ -19,6 +19,7 @@
#include "src/tint/type/manager.h"
#include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::SampledTexture);
@@ -39,7 +40,7 @@
}
std::string SampledTexture::FriendlyName(const SymbolTable& symbols) const {
- std::ostringstream out;
+ utils::StringStream out;
out << "texture_" << dim() << "<" << type_->FriendlyName(symbols) << ">";
return out.str();
}
diff --git a/src/tint/type/storage_texture.cc b/src/tint/type/storage_texture.cc
index beb5da6..180db4f 100644
--- a/src/tint/type/storage_texture.cc
+++ b/src/tint/type/storage_texture.cc
@@ -19,6 +19,7 @@
#include "src/tint/type/manager.h"
#include "src/tint/type/u32.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::StorageTexture);
@@ -43,7 +44,7 @@
}
std::string StorageTexture::FriendlyName(const SymbolTable&) const {
- std::ostringstream out;
+ utils::StringStream out;
out << "texture_storage_" << dim() << "<" << texel_format_ << ", " << access_ << ">";
return out.str();
}
diff --git a/src/tint/type/struct.cc b/src/tint/type/struct.cc
index c39916b..7649691 100644
--- a/src/tint/type/struct.cc
+++ b/src/tint/type/struct.cc
@@ -22,6 +22,7 @@
#include "src/tint/symbol_table.h"
#include "src/tint/type/manager.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::Struct);
TINT_INSTANTIATE_TYPEINFO(tint::type::StructMember);
@@ -96,7 +97,7 @@
}
std::string Struct::Layout(const tint::SymbolTable& symbols) const {
- std::stringstream ss;
+ utils::StringStream ss;
auto member_name_of = [&](const StructMember* sm) { return symbols.NameFor(sm->Name()); };
diff --git a/src/tint/type/vector.cc b/src/tint/type/vector.cc
index 146c1f4..9f1f415 100644
--- a/src/tint/type/vector.cc
+++ b/src/tint/type/vector.cc
@@ -18,20 +18,22 @@
#include "src/tint/diagnostic/diagnostic.h"
#include "src/tint/type/manager.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::Vector);
namespace tint::type {
-Vector::Vector(Type const* subtype, uint32_t width)
- : Base(utils::Hash(TypeInfo::Of<Vector>().full_hashcode, width, subtype),
+Vector::Vector(Type const* subtype, uint32_t width, bool packed /* = false */)
+ : Base(utils::Hash(TypeInfo::Of<Vector>().full_hashcode, width, subtype, packed),
type::Flags{
Flag::kConstructable,
Flag::kCreationFixedFootprint,
Flag::kFixedFootprint,
}),
subtype_(subtype),
- width_(width) {
+ width_(width),
+ packed_(packed) {
TINT_ASSERT(Type, width_ > 1);
TINT_ASSERT(Type, width_ < 5);
}
@@ -40,13 +42,16 @@
bool Vector::Equals(const UniqueNode& other) const {
if (auto* v = other.As<Vector>()) {
- return v->width_ == width_ && v->subtype_ == subtype_;
+ return v->width_ == width_ && v->subtype_ == subtype_ && v->packed_ == packed_;
}
return false;
}
std::string Vector::FriendlyName(const SymbolTable& symbols) const {
- std::ostringstream out;
+ utils::StringStream out;
+ if (packed_) {
+ out << "__packed_";
+ }
out << "vec" << width_ << "<" << subtype_->FriendlyName(symbols) << ">";
return out.str();
}
@@ -60,7 +65,7 @@
case 2:
return subtype_->Size() * 2;
case 3:
- return subtype_->Size() * 4;
+ return subtype_->Size() * (packed_ ? 1 : 4);
case 4:
return subtype_->Size() * 4;
}
@@ -69,7 +74,7 @@
Vector* Vector::Clone(CloneContext& ctx) const {
auto* subtype = subtype_->Clone(ctx);
- return ctx.dst.mgr->Get<Vector>(subtype, width_);
+ return ctx.dst.mgr->Get<Vector>(subtype, width_, packed_);
}
} // namespace tint::type
diff --git a/src/tint/type/vector.h b/src/tint/type/vector.h
index acffb8c..e7fd881 100644
--- a/src/tint/type/vector.h
+++ b/src/tint/type/vector.h
@@ -22,12 +22,13 @@
namespace tint::type {
/// A vector type.
-class Vector final : public Castable<Vector, Type> {
+class Vector : public Castable<Vector, Type> {
public:
/// Constructor
/// @param subtype the vector element type
/// @param size the number of elements in the vector
- Vector(Type const* subtype, uint32_t size);
+ /// @param packed the optional 'packed' modifier
+ Vector(Type const* subtype, uint32_t size, bool packed = false);
/// Destructor
~Vector() override;
@@ -50,10 +51,12 @@
/// @returns the size in bytes of the type. This may include tail padding.
uint32_t Size() const override;
- /// @returns the alignment in bytes of the type. This may include tail
- /// padding.
+ /// @returns the alignment in bytes of the type. This may include tail padding.
uint32_t Align() const override;
+ /// @returns `true` if this vector is packed, false otherwise
+ bool Packed() const { return packed_; }
+
/// @param width the width of the vector
/// @returns the size in bytes of a vector of the given width.
static uint32_t SizeOf(uint32_t width);
@@ -69,6 +72,7 @@
private:
Type const* const subtype_;
const uint32_t width_;
+ const bool packed_;
};
} // namespace tint::type
diff --git a/src/tint/type/vector_test.cc b/src/tint/type/vector_test.cc
index 7dd5c9d..acc62ed 100644
--- a/src/tint/type/vector_test.cc
+++ b/src/tint/type/vector_test.cc
@@ -34,6 +34,21 @@
EXPECT_NE(a, d);
}
+TEST_F(VectorTest, Creation_Packed) {
+ auto* v = create<Vector>(create<F32>(), 3u);
+ auto* p1 = create<Vector>(create<F32>(), 3u, true);
+ auto* p2 = create<Vector>(create<F32>(), 3u, true);
+
+ EXPECT_FALSE(v->Packed());
+
+ EXPECT_EQ(p1->type(), create<F32>());
+ EXPECT_EQ(p1->Width(), 3u);
+ EXPECT_TRUE(p1->Packed());
+
+ EXPECT_NE(v, p1);
+ EXPECT_EQ(p1, p2);
+}
+
TEST_F(VectorTest, Hash) {
auto* a = create<Vector>(create<I32>(), 2u);
auto* b = create<Vector>(create<I32>(), 2u);
@@ -59,6 +74,12 @@
EXPECT_EQ(v->FriendlyName(Symbols()), "vec3<f32>");
}
+TEST_F(VectorTest, FriendlyName_Packed) {
+ auto* f32 = create<F32>();
+ auto* v = create<Vector>(f32, 3u, true);
+ EXPECT_EQ(v->FriendlyName(Symbols()), "__packed_vec3<f32>");
+}
+
TEST_F(VectorTest, Clone) {
auto* a = create<Vector>(create<I32>(), 2u);
@@ -68,6 +89,19 @@
auto* vec = a->Clone(ctx);
EXPECT_TRUE(vec->type()->Is<I32>());
EXPECT_EQ(vec->Width(), 2u);
+ EXPECT_FALSE(vec->Packed());
+}
+
+TEST_F(VectorTest, Clone_Packed) {
+ auto* a = create<Vector>(create<I32>(), 3u, true);
+
+ type::Manager mgr;
+ type::CloneContext ctx{{nullptr}, {nullptr, &mgr}};
+
+ auto* vec = a->Clone(ctx);
+ EXPECT_TRUE(vec->type()->Is<I32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TRUE(vec->Packed());
}
} // namespace
diff --git a/src/tint/utils/enum_set_test.cc b/src/tint/utils/enum_set_test.cc
index 4cdeb63..a6bb169 100644
--- a/src/tint/utils/enum_set_test.cc
+++ b/src/tint/utils/enum_set_test.cc
@@ -18,6 +18,7 @@
#include <vector>
#include "gmock/gmock.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::utils {
namespace {
@@ -232,7 +233,7 @@
}
TEST(EnumSetTest, Ostream) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << EnumSet<E>(E::A, E::C);
EXPECT_EQ(ss.str(), "{A, C}");
}
diff --git a/src/tint/utils/io/command_windows.cc b/src/tint/utils/io/command_windows.cc
index abe7242..31d0308 100644
--- a/src/tint/utils/io/command_windows.cc
+++ b/src/tint/utils/io/command_windows.cc
@@ -21,6 +21,7 @@
#include <string>
#include "src/tint/utils/defer.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::utils {
@@ -197,7 +198,7 @@
si.hStdError = stderr_pipe.write;
si.hStdInput = stdin_pipe.read;
- std::stringstream args;
+ utils::StringStream args;
args << path_;
for (auto& arg : arguments) {
if (!arg.empty()) {
diff --git a/src/tint/utils/io/tmpfile.h b/src/tint/utils/io/tmpfile.h
index 24e7208..7949a37 100644
--- a/src/tint/utils/io/tmpfile.h
+++ b/src/tint/utils/io/tmpfile.h
@@ -18,6 +18,8 @@
#include <sstream>
#include <string>
+#include "src/tint/utils/string_stream.h"
+
namespace tint::utils {
/// TmpFile constructs a temporary file that can be written to, and is
@@ -55,7 +57,7 @@
/// @return a reference to this TmpFile
template <typename T>
inline TmpFile& operator<<(T&& data) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << data;
std::string str = ss.str();
Append(str.data(), str.size());
diff --git a/src/tint/utils/string.cc b/src/tint/utils/string.cc
index bccd52c..2f28a3e 100644
--- a/src/tint/utils/string.cc
+++ b/src/tint/utils/string.cc
@@ -50,7 +50,7 @@
void SuggestAlternatives(std::string_view got,
Slice<char const* const> strings,
- std::ostringstream& ss) {
+ utils::StringStream& ss) {
// If the string typed was within kSuggestionDistance of one of the possible enum values,
// suggest that. Don't bother with suggestions if the string was extremely long.
constexpr size_t kSuggestionDistance = 5;
diff --git a/src/tint/utils/string.h b/src/tint/utils/string.h
index 08e0be3..e77e637 100644
--- a/src/tint/utils/string.h
+++ b/src/tint/utils/string.h
@@ -20,6 +20,7 @@
#include <variant>
#include "src/tint/utils/slice.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::utils {
@@ -42,7 +43,7 @@
/// @returns value printed as a string via the std::ostream `<<` operator
template <typename T>
std::string ToString(const T& value) {
- std::stringstream s;
+ utils::StringStream s;
s << value;
return s.str();
}
@@ -51,7 +52,7 @@
/// @returns value printed as a string via the std::ostream `<<` operator
template <typename... TYs>
std::string ToString(const std::variant<TYs...>& value) {
- std::stringstream s;
+ utils::StringStream s;
s << std::visit([&](auto& v) { return ToString(v); }, value);
return s.str();
}
@@ -74,7 +75,7 @@
/// @param ss the stream to write the suggest and list of possible values to
void SuggestAlternatives(std::string_view got,
Slice<char const* const> strings,
- std::ostringstream& ss);
+ utils::StringStream& ss);
} // namespace tint::utils
diff --git a/src/tint/utils/string_stream.cc b/src/tint/utils/string_stream.cc
new file mode 100644
index 0000000..2d1ed44
--- /dev/null
+++ b/src/tint/utils/string_stream.cc
@@ -0,0 +1,27 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/utils/string_stream.h"
+
+namespace tint::utils {
+
+StringStream::StringStream() {
+ sstream_.flags(sstream_.flags() | std::ios_base::showpoint | std::ios_base::fixed);
+ sstream_.imbue(std::locale::classic());
+ sstream_.precision(9);
+}
+
+StringStream::~StringStream() = default;
+
+} // namespace tint::utils
diff --git a/src/tint/utils/string_stream.h b/src/tint/utils/string_stream.h
new file mode 100644
index 0000000..893d2b9
--- /dev/null
+++ b/src/tint/utils/string_stream.h
@@ -0,0 +1,123 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_UTILS_STRING_STREAM_H_
+#define SRC_TINT_UTILS_STRING_STREAM_H_
+
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace tint::utils {
+
+/// Stringstream wrapper which automatically resets the locale and sets floating point emission
+/// settings needed for Tint.
+class StringStream {
+ public:
+ /// Constructor
+ StringStream();
+ /// Destructor
+ ~StringStream();
+
+ /// @returns the format flags for the stream
+ std::ios_base::fmtflags flags() const { return sstream_.flags(); }
+
+ /// @param flags the flags to set
+ /// @returns the original format flags
+ std::ios_base::fmtflags flags(std::ios_base::fmtflags flags) { return sstream_.flags(flags); }
+
+ /// Emit `value` to the stream
+ /// @param value the value to emit
+ /// @returns a reference to this
+ template <typename T,
+ typename std::enable_if<!std::is_floating_point<T>::value>::type* = nullptr>
+ StringStream& operator<<(const T& value) {
+ sstream_ << value;
+ return *this;
+ }
+
+ /// Emit `value` to the stream
+ /// @param value the value to emit
+ /// @returns a reference to this
+ template <typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
+ StringStream& operator<<(const T& value) {
+ // Try printing the float in fixed point, with a smallish limit on the precision
+ std::stringstream fixed;
+ fixed.flags(fixed.flags() | std::ios_base::showpoint | std::ios_base::fixed);
+ fixed.imbue(std::locale::classic());
+ fixed.precision(9);
+ fixed << value;
+
+ std::string str = fixed.str();
+
+ // If this string can be parsed without loss of information, use it.
+ // (Use double here to dodge a bug in older libc++ versions which would incorrectly read
+ // back FLT_MAX as INF.)
+ double roundtripped;
+ fixed >> roundtripped;
+
+ auto float_equal_no_warning = std::equal_to<T>();
+ if (float_equal_no_warning(value, static_cast<T>(roundtripped))) {
+ while (str.length() >= 2 && str[str.size() - 1] == '0' && str[str.size() - 2] != '.') {
+ str.pop_back();
+ }
+
+ sstream_ << str;
+ return *this;
+ }
+
+ // Resort to scientific, with the minimum precision needed to preserve the whole float
+ std::stringstream sci;
+ sci.imbue(std::locale::classic());
+ sci.precision(std::numeric_limits<T>::max_digits10);
+ sci << value;
+ sstream_ << sci.str();
+
+ return *this;
+ }
+
+ /// Swaps streams
+ /// @param other stream to swap too
+ void swap(StringStream& other) { sstream_.swap(other.sstream_); }
+
+ /// repeat queues the character c to be written to the printer n times.
+ /// @param c the character to print `n` times
+ /// @param n the number of times to print character `c`
+ void repeat(char c, size_t n) { std::fill_n(std::ostream_iterator<char>(sstream_), n, c); }
+
+ /// The callback to emit a `endl` to the stream
+ using StdEndl = std::ostream& (*)(std::ostream&);
+
+ /// @param manipulator the callback to emit too
+ /// @returns a reference to this
+ StringStream& operator<<(StdEndl manipulator) {
+ // call the function, and return it's value
+ manipulator(sstream_);
+ return *this;
+ }
+
+ /// @returns the string contents of the stream
+ std::string str() const { return sstream_.str(); }
+
+ private:
+ std::stringstream sstream_;
+};
+
+} // namespace tint::utils
+
+#endif // SRC_TINT_UTILS_STRING_STREAM_H_
diff --git a/src/tint/utils/string_stream_test.cc b/src/tint/utils/string_stream_test.cc
new file mode 100644
index 0000000..eebefd6
--- /dev/null
+++ b/src/tint/utils/string_stream_test.cc
@@ -0,0 +1,111 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/utils/string_stream.h"
+
+#include <math.h>
+#include <cstring>
+#include <limits>
+
+#include "gtest/gtest.h"
+
+namespace tint::utils {
+namespace {
+
+using StringStreamTest = testing::Test;
+
+TEST_F(StringStreamTest, Zero) {
+ StringStream s;
+ s << 0.0f;
+ EXPECT_EQ(s.str(), "0.0");
+}
+
+TEST_F(StringStreamTest, One) {
+ StringStream s;
+ s << 1.0f;
+ EXPECT_EQ(s.str(), "1.0");
+}
+
+TEST_F(StringStreamTest, MinusOne) {
+ StringStream s;
+ s << -1.0f;
+ EXPECT_EQ(s.str(), "-1.0");
+}
+
+TEST_F(StringStreamTest, Billion) {
+ StringStream s;
+ s << 1e9f;
+ EXPECT_EQ(s.str(), "1000000000.0");
+}
+
+TEST_F(StringStreamTest, Small) {
+ StringStream s;
+ s << std::numeric_limits<float>::epsilon();
+ EXPECT_NE(s.str(), "0.0");
+}
+
+TEST_F(StringStreamTest, Highest) {
+ const auto highest = std::numeric_limits<float>::max();
+ const auto expected_highest = 340282346638528859811704183484516925440.0f;
+
+ if (highest < expected_highest || highest > expected_highest) {
+ GTEST_SKIP() << "std::numeric_limits<float>::max() is not as expected for "
+ "this target";
+ }
+
+ StringStream s;
+ s << std::numeric_limits<float>::max();
+ EXPECT_EQ(s.str(), "340282346638528859811704183484516925440.0");
+}
+
+TEST_F(StringStreamTest, Lowest) {
+ // Some compilers complain if you test floating point numbers for equality.
+ // So say it via two inequalities.
+ const auto lowest = std::numeric_limits<float>::lowest();
+ const auto expected_lowest = -340282346638528859811704183484516925440.0f;
+ if (lowest < expected_lowest || lowest > expected_lowest) {
+ GTEST_SKIP() << "std::numeric_limits<float>::lowest() is not as expected for "
+ "this target";
+ }
+
+ StringStream s;
+ s << std::numeric_limits<float>::lowest();
+ EXPECT_EQ(s.str(), "-340282346638528859811704183484516925440.0");
+}
+
+TEST_F(StringStreamTest, Precision) {
+ {
+ StringStream s;
+ s << 1e-8f;
+ EXPECT_EQ(s.str(), "0.00000001");
+ }
+ {
+ StringStream s;
+ s << 1e-9f;
+ EXPECT_EQ(s.str(), "0.000000001");
+ }
+ {
+ StringStream s;
+ s << 1e-10f;
+ EXPECT_EQ(s.str(), "1.00000001e-10");
+ }
+ {
+ StringStream s;
+ s << 1e-20f;
+ EXPECT_EQ(s.str(), "9.99999968e-21");
+ }
+}
+
+} // namespace
+} // namespace tint::utils
diff --git a/src/tint/utils/string_test.cc b/src/tint/utils/string_test.cc
index b9e1ebb..0f351cf 100644
--- a/src/tint/utils/string_test.cc
+++ b/src/tint/utils/string_test.cc
@@ -15,6 +15,7 @@
#include "src/tint/utils/string.h"
#include "gtest/gtest.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::utils {
namespace {
@@ -61,14 +62,14 @@
TEST(StringTest, SuggestAlternatives) {
{
const char* alternatives[] = {"hello world", "Hello World"};
- std::ostringstream ss;
+ utils::StringStream ss;
SuggestAlternatives("hello wordl", alternatives, ss);
EXPECT_EQ(ss.str(), R"(Did you mean 'hello world'?
Possible values: 'hello world', 'Hello World')");
}
{
const char* alternatives[] = {"foobar", "something else"};
- std::ostringstream ss;
+ utils::StringStream ss;
SuggestAlternatives("hello world", alternatives, ss);
EXPECT_EQ(ss.str(), R"(Possible values: 'foobar', 'something else')");
}
diff --git a/src/tint/utils/vector_test.cc b/src/tint/utils/vector_test.cc
index 6245476..0604732 100644
--- a/src/tint/utils/vector_test.cc
+++ b/src/tint/utils/vector_test.cc
@@ -20,6 +20,7 @@
#include "gmock/gmock.h"
#include "src/tint/utils/bitcast.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::utils {
namespace {
@@ -1788,7 +1789,7 @@
}
TEST(TintVectorTest, ostream) {
- std::stringstream ss;
+ utils::StringStream ss;
ss << Vector{1, 2, 3};
EXPECT_EQ(ss.str(), "[1, 2, 3]");
}
@@ -2065,7 +2066,7 @@
}
TEST(TintVectorRefTest, ostream) {
- std::stringstream ss;
+ utils::StringStream ss;
Vector vec{1, 2, 3};
const VectorRef<int> vec_ref(vec);
ss << vec_ref;
diff --git a/src/tint/writer/float_to_string.cc b/src/tint/writer/float_to_string.cc
index 3b4260e..0ce4954 100644
--- a/src/tint/writer/float_to_string.cc
+++ b/src/tint/writer/float_to_string.cc
@@ -22,6 +22,7 @@
#include <sstream>
#include "src/tint/debug.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::writer {
@@ -52,35 +53,9 @@
template <typename F>
std::string ToString(F f) {
- // Try printing the float in fixed point, with a smallish limit on the precision
- std::stringstream fixed;
- fixed.flags(fixed.flags() | std::ios_base::showpoint | std::ios_base::fixed);
- fixed.imbue(std::locale::classic());
- fixed.precision(9);
- fixed << f;
- std::string str = fixed.str();
-
- // If this string can be parsed without loss of information, use it.
- // (Use double here to dodge a bug in older libc++ versions which would incorrectly read back
- // FLT_MAX as INF.)
- double roundtripped;
- fixed >> roundtripped;
-
- auto float_equal_no_warning = std::equal_to<F>();
- if (float_equal_no_warning(f, static_cast<F>(roundtripped))) {
- while (str.length() >= 2 && str[str.size() - 1] == '0' && str[str.size() - 2] != '.') {
- str.pop_back();
- }
-
- return str;
- }
-
- // Resort to scientific, with the minimum precision needed to preserve the whole float
- std::stringstream sci;
- sci.imbue(std::locale::classic());
- sci.precision(std::numeric_limits<F>::max_digits10);
- sci << f;
- return sci.str();
+ utils::StringStream s;
+ s << f;
+ return s.str();
}
template <typename F>
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index e8b5b9b..46428b0 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -75,6 +75,7 @@
#include "src/tint/utils/map.h"
#include "src/tint/utils/scoped_assignment.h"
#include "src/tint/utils/string.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/append_vector.h"
#include "src/tint/writer/float_to_string.h"
#include "src/tint/writer/generate_external_texture_bindings.h"
@@ -111,7 +112,7 @@
return IsAnyOf<ast::BreakStatement>(stmts->Last());
}
-void PrintF32(std::ostream& out, float value) {
+void PrintF32(utils::StringStream& out, float value) {
if (std::isinf(value)) {
out << "0.0f " << (value >= 0 ? "/* inf */" : "/* -inf */");
} else if (std::isnan(value)) {
@@ -121,7 +122,7 @@
}
}
-void PrintF16(std::ostream& out, float value) {
+void PrintF16(utils::StringStream& out, float value) {
if (std::isinf(value)) {
out << "0.0hf " << (value >= 0 ? "/* inf */" : "/* -inf */");
} else if (std::isnan(value)) {
@@ -333,7 +334,8 @@
return true;
}
-bool GeneratorImpl::EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr) {
+bool GeneratorImpl::EmitIndexAccessor(utils::StringStream& out,
+ const ast::IndexAccessorExpression* expr) {
if (!EmitExpression(out, expr->object)) {
return false;
}
@@ -347,7 +349,7 @@
return true;
}
-bool GeneratorImpl::EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr) {
+bool GeneratorImpl::EmitBitcast(utils::StringStream& out, const ast::BitcastExpression* expr) {
auto* src_type = TypeOf(expr->expr)->UnwrapRef();
auto* dst_type = TypeOf(expr)->UnwrapRef();
@@ -399,7 +401,8 @@
return true;
}
-bool GeneratorImpl::EmitVectorRelational(std::ostream& out, const ast::BinaryExpression* expr) {
+bool GeneratorImpl::EmitVectorRelational(utils::StringStream& out,
+ const ast::BinaryExpression* expr) {
switch (expr->op) {
case ast::BinaryOp::kEqual:
out << "equal";
@@ -433,7 +436,7 @@
return true;
}
-bool GeneratorImpl::EmitBitwiseBoolOp(std::ostream& out, const ast::BinaryExpression* expr) {
+bool GeneratorImpl::EmitBitwiseBoolOp(utils::StringStream& out, const ast::BinaryExpression* expr) {
auto* bool_type = TypeOf(expr->lhs)->UnwrapRef();
auto* uint_type = BoolTypeToUint(bool_type);
@@ -479,7 +482,7 @@
return true;
}
-bool GeneratorImpl::EmitFloatModulo(std::ostream& out, const ast::BinaryExpression* expr) {
+bool GeneratorImpl::EmitFloatModulo(utils::StringStream& out, const ast::BinaryExpression* expr) {
std::string fn;
auto* ret_ty = TypeOf(expr)->UnwrapRef();
auto* lhs_ty = TypeOf(expr->lhs)->UnwrapRef();
@@ -541,7 +544,7 @@
return true;
}
-bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* expr) {
+bool GeneratorImpl::EmitBinary(utils::StringStream& out, const ast::BinaryExpression* expr) {
if (IsRelational(expr->op) && !TypeOf(expr->lhs)->UnwrapRef()->is_scalar()) {
return EmitVectorRelational(out, expr);
}
@@ -706,7 +709,7 @@
return true;
}
-bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitCall(utils::StringStream& out, const ast::CallExpression* expr) {
auto* call = builder_.Sem().Get<sem::Call>(expr);
return Switch(
call->Target(), //
@@ -721,7 +724,7 @@
});
}
-bool GeneratorImpl::EmitFunctionCall(std::ostream& out,
+bool GeneratorImpl::EmitFunctionCall(utils::StringStream& out,
const sem::Call* call,
const sem::Function* fn) {
const auto& args = call->Arguments();
@@ -745,7 +748,7 @@
return true;
}
-bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
+bool GeneratorImpl::EmitBuiltinCall(utils::StringStream& out,
const sem::Call* call,
const sem::Builtin* builtin) {
auto* expr = call->Declaration();
@@ -827,7 +830,7 @@
return true;
}
-bool GeneratorImpl::EmitValueConversion(std::ostream& out,
+bool GeneratorImpl::EmitValueConversion(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConversion* conv) {
if (!EmitType(out, conv->Target(), builtin::AddressSpace::kUndefined,
@@ -843,7 +846,7 @@
return true;
}
-bool GeneratorImpl::EmitValueConstructor(std::ostream& out,
+bool GeneratorImpl::EmitValueConstructor(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConstructor* ctor) {
auto* type = ctor->ReturnType();
@@ -874,7 +877,7 @@
return true;
}
-bool GeneratorImpl::EmitWorkgroupAtomicCall(std::ostream& out,
+bool GeneratorImpl::EmitWorkgroupAtomicCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
auto call = [&](const char* name) {
@@ -995,7 +998,7 @@
return false;
}
-bool GeneratorImpl::EmitArrayLength(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitArrayLength(utils::StringStream& out, const ast::CallExpression* expr) {
out << "uint(";
if (!EmitExpression(out, expr->args[0])) {
return false;
@@ -1004,7 +1007,7 @@
return true;
}
-bool GeneratorImpl::EmitExtractBits(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitExtractBits(utils::StringStream& out, const ast::CallExpression* expr) {
out << "bitfieldExtract(";
if (!EmitExpression(out, expr->args[0])) {
return false;
@@ -1021,7 +1024,7 @@
return true;
}
-bool GeneratorImpl::EmitInsertBits(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitInsertBits(utils::StringStream& out, const ast::CallExpression* expr) {
out << "bitfieldInsert(";
if (!EmitExpression(out, expr->args[0])) {
return false;
@@ -1042,7 +1045,7 @@
return true;
}
-bool GeneratorImpl::EmitEmulatedFMA(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitEmulatedFMA(utils::StringStream& out, const ast::CallExpression* expr) {
out << "((";
if (!EmitExpression(out, expr->args[0])) {
return false;
@@ -1059,7 +1062,8 @@
return true;
}
-bool GeneratorImpl::EmitCountOneBitsCall(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitCountOneBitsCall(utils::StringStream& out,
+ const ast::CallExpression* expr) {
// GLSL's bitCount returns an integer type, so cast it to the appropriate
// unsigned type.
if (!EmitType(out, TypeOf(expr)->UnwrapRef(), builtin::AddressSpace::kUndefined,
@@ -1075,7 +1079,7 @@
return true;
}
-bool GeneratorImpl::EmitSelectCall(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitSelectCall(utils::StringStream& out, const ast::CallExpression* expr) {
auto* expr_false = expr->args[0];
auto* expr_true = expr->args[1];
auto* expr_cond = expr->args[2];
@@ -1117,7 +1121,7 @@
return true;
}
-bool GeneratorImpl::EmitDotCall(std::ostream& out,
+bool GeneratorImpl::EmitDotCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
auto* vec_ty = builtin->Parameters()[0]->Type()->As<type::Vector>();
@@ -1133,7 +1137,7 @@
std::string v;
{
- std::stringstream s;
+ utils::StringStream s;
if (!EmitType(s, vec_ty->type(), builtin::AddressSpace::kUndefined,
builtin::Access::kRead, "")) {
return "";
@@ -1190,7 +1194,7 @@
return true;
}
-bool GeneratorImpl::EmitModfCall(std::ostream& out,
+bool GeneratorImpl::EmitModfCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
TINT_ASSERT(Writer, expr->args.Length() == 1);
@@ -1216,7 +1220,7 @@
});
}
-bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
+bool GeneratorImpl::EmitFrexpCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
TINT_ASSERT(Writer, expr->args.Length() == 1);
@@ -1242,7 +1246,7 @@
});
}
-bool GeneratorImpl::EmitDegreesCall(std::ostream& out,
+bool GeneratorImpl::EmitDegreesCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
auto* return_elem_type = type::Type::DeepestElementOf(builtin->ReturnType());
@@ -1255,7 +1259,7 @@
});
}
-bool GeneratorImpl::EmitRadiansCall(std::ostream& out,
+bool GeneratorImpl::EmitRadiansCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
auto* return_elem_type = type::Type::DeepestElementOf(builtin->ReturnType());
@@ -1268,7 +1272,7 @@
});
}
-bool GeneratorImpl::EmitQuantizeToF16Call(std::ostream& out,
+bool GeneratorImpl::EmitQuantizeToF16Call(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
// Emulate by casting to f16 and back again.
@@ -1300,7 +1304,7 @@
});
}
-bool GeneratorImpl::EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin) {
+bool GeneratorImpl::EmitBarrierCall(utils::StringStream& out, const sem::Builtin* builtin) {
// TODO(crbug.com/tint/661): Combine sequential barriers to a single
// instruction.
if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
@@ -1325,7 +1329,7 @@
return zero;
}
-bool GeneratorImpl::EmitTextureCall(std::ostream& out,
+bool GeneratorImpl::EmitTextureCall(utils::StringStream& out,
const sem::Call* call,
const sem::Builtin* builtin) {
using Usage = sem::ParameterUsage;
@@ -1818,7 +1822,7 @@
return true;
}
-bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
+bool GeneratorImpl::EmitExpression(utils::StringStream& out, const ast::Expression* expr) {
if (auto* sem = builder_.Sem().GetVal(expr)) {
if (auto* constant = sem->ConstantValue()) {
return EmitConstant(out, constant);
@@ -1841,7 +1845,8 @@
});
}
-bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) {
+bool GeneratorImpl::EmitIdentifier(utils::StringStream& out,
+ const ast::IdentifierExpression* expr) {
out << builder_.Symbols().NameFor(expr->identifier->symbol);
return true;
}
@@ -2187,7 +2192,7 @@
}
void GeneratorImpl::EmitInterpolationQualifiers(
- std::ostream& out,
+ utils::StringStream& out,
utils::VectorRef<const ast::Attribute*> attributes) {
for (auto* attr : attributes) {
if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
@@ -2223,7 +2228,7 @@
}
}
-bool GeneratorImpl::EmitAttributes(std::ostream& out,
+bool GeneratorImpl::EmitAttributes(utils::StringStream& out,
const sem::GlobalVariable* var,
utils::VectorRef<const ast::Attribute*> attributes) {
if (attributes.IsEmpty()) {
@@ -2333,7 +2338,7 @@
return true;
}
-bool GeneratorImpl::EmitConstant(std::ostream& out, const constant::Value* constant) {
+bool GeneratorImpl::EmitConstant(utils::StringStream& out, const constant::Value* constant) {
return Switch(
constant->Type(), //
[&](const type::Bool*) {
@@ -2450,7 +2455,7 @@
});
}
-bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit) {
+bool GeneratorImpl::EmitLiteral(utils::StringStream& out, const ast::LiteralExpression* lit) {
return Switch(
lit,
[&](const ast::BoolLiteralExpression* l) {
@@ -2478,7 +2483,7 @@
});
}
-bool GeneratorImpl::EmitZeroValue(std::ostream& out, const type::Type* type) {
+bool GeneratorImpl::EmitZeroValue(utils::StringStream& out, const type::Type* type) {
if (type->Is<type::Bool>()) {
out << "false";
} else if (type->Is<type::F32>()) {
@@ -2604,7 +2609,7 @@
}
TextBuffer cond_pre;
- std::stringstream cond_buf;
+ utils::StringStream cond_buf;
if (auto* cond = stmt->condition) {
TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
if (!EmitExpression(cond_buf, cond)) {
@@ -2696,7 +2701,7 @@
bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) {
TextBuffer cond_pre;
- std::stringstream cond_buf;
+ utils::StringStream cond_buf;
{
auto* cond = stmt->condition;
TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
@@ -2745,7 +2750,7 @@
return true;
}
-bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
+bool GeneratorImpl::EmitMemberAccessor(utils::StringStream& out,
const ast::MemberAccessorExpression* expr) {
if (!EmitExpression(out, expr->object)) {
return false;
@@ -2857,7 +2862,7 @@
return true;
}
-bool GeneratorImpl::EmitType(std::ostream& out,
+bool GeneratorImpl::EmitType(utils::StringStream& out,
const type::Type* type,
builtin::AddressSpace address_space,
builtin::Access access,
@@ -3038,7 +3043,7 @@
return true;
}
-bool GeneratorImpl::EmitTypeAndName(std::ostream& out,
+bool GeneratorImpl::EmitTypeAndName(utils::StringStream& out,
const type::Type* type,
builtin::AddressSpace address_space,
builtin::Access access,
@@ -3086,7 +3091,7 @@
return true;
}
-bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr) {
+bool GeneratorImpl::EmitUnaryOp(utils::StringStream& out, const ast::UnaryOpExpression* expr) {
switch (expr->op) {
case ast::UnaryOp::kIndirection:
case ast::UnaryOp::kAddressOf:
@@ -3182,7 +3187,7 @@
}
template <typename F>
-bool GeneratorImpl::CallBuiltinHelper(std::ostream& out,
+bool GeneratorImpl::CallBuiltinHelper(utils::StringStream& out,
const ast::CallExpression* call,
const sem::Builtin* builtin,
F&& build) {
diff --git a/src/tint/writer/glsl/generator_impl.h b/src/tint/writer/glsl/generator_impl.h
index d220877..d954921 100644
--- a/src/tint/writer/glsl/generator_impl.h
+++ b/src/tint/writer/glsl/generator_impl.h
@@ -37,6 +37,7 @@
#include "src/tint/scope_stack.h"
#include "src/tint/transform/decompose_memory_access.h"
#include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/glsl/generator.h"
#include "src/tint/writer/glsl/version.h"
#include "src/tint/writer/text_generator.h"
@@ -93,7 +94,7 @@
/// @param out the output of the expression stream
/// @param expr the expression to emit
/// @returns true if the index accessor was emitted
- bool EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr);
+ bool EmitIndexAccessor(utils::StringStream& out, const ast::IndexAccessorExpression* expr);
/// Handles an assignment statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
@@ -102,27 +103,27 @@
/// @param out the output of the expression stream
/// @param expr the binary expression
/// @returns true if the expression was emitted, false otherwise
- bool EmitBitwiseBoolOp(std::ostream& out, const ast::BinaryExpression* expr);
+ bool EmitBitwiseBoolOp(utils::StringStream& out, const ast::BinaryExpression* expr);
/// Handles generating a binary expression
/// @param out the output of the expression stream
/// @param expr the binary expression
/// @returns true if the expression was emitted, false otherwise
- bool EmitFloatModulo(std::ostream& out, const ast::BinaryExpression* expr);
+ bool EmitFloatModulo(utils::StringStream& out, const ast::BinaryExpression* expr);
/// Handles generating the modulo operator on float vector operands
/// @param out the output of the expression stream
/// @param expr the binary expression
/// @returns true if the expression was emitted, false otherwise
- bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
+ bool EmitBinary(utils::StringStream& out, const ast::BinaryExpression* expr);
/// Handles generating a bitcast expression
/// @param out the output of the expression stream
/// @param expr the expression
/// @returns true if the binary expression was emitted
- bool EmitVectorRelational(std::ostream& out, const ast::BinaryExpression* expr);
+ bool EmitVectorRelational(utils::StringStream& out, const ast::BinaryExpression* expr);
/// Handles generating a vector relational expression
/// @param out the output of the expression stream
/// @param expr the expression
/// @returns true if the vector relational expression was emitted
- bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
+ bool EmitBitcast(utils::StringStream& out, const ast::BitcastExpression* expr);
/// Emits a list of statements
/// @param stmts the statement list
/// @returns true if the statements were emitted successfully
@@ -147,25 +148,27 @@
/// @param out the output of the expression stream
/// @param expr the call expression
/// @returns true if the call expression is emitted
- bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
+ bool EmitCall(utils::StringStream& out, const ast::CallExpression* expr);
/// Handles generating a function call expression
/// @param out the output of the expression stream
/// @param call the call expression
/// @param fn the function being called
/// @returns true if the expression is emitted
- bool EmitFunctionCall(std::ostream& out, const sem::Call* call, const sem::Function* fn);
+ bool EmitFunctionCall(utils::StringStream& out, const sem::Call* call, const sem::Function* fn);
/// Handles generating a builtin call expression
/// @param out the output of the expression stream
/// @param call the call expression
/// @param builtin the builtin being called
/// @returns true if the expression is emitted
- bool EmitBuiltinCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+ bool EmitBuiltinCall(utils::StringStream& out,
+ const sem::Call* call,
+ const sem::Builtin* builtin);
/// Handles generating a value conversion expression
/// @param out the output of the expression stream
/// @param call the call expression
/// @param conv the value conversion
/// @returns true if the expression is emitted
- bool EmitValueConversion(std::ostream& out,
+ bool EmitValueConversion(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConversion* conv);
/// Handles generating a value constructor expression
@@ -173,42 +176,42 @@
/// @param call the call expression
/// @param ctor the value constructor
/// @returns true if the expression is emitted
- bool EmitValueConstructor(std::ostream& out,
+ bool EmitValueConstructor(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConstructor* ctor);
/// Handles generating a barrier builtin call
/// @param out the output of the expression stream
/// @param builtin the semantic information for the barrier builtin
/// @returns true if the call expression is emitted
- bool EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin);
+ bool EmitBarrierCall(utils::StringStream& out, const sem::Builtin* builtin);
/// Handles generating an atomic builtin call for a workgroup variable
/// @param out the output of the expression stream
/// @param expr the call expression
/// @param builtin the semantic information for the atomic builtin
/// @returns true if the call expression is emitted
- bool EmitWorkgroupAtomicCall(std::ostream& out,
+ bool EmitWorkgroupAtomicCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating an array.length() call
/// @param out the output of the expression stream
/// @param expr the call expression
/// @returns true if the array length expression is emitted
- bool EmitArrayLength(std::ostream& out, const ast::CallExpression* expr);
+ bool EmitArrayLength(utils::StringStream& out, const ast::CallExpression* expr);
/// Handles generating a call to `bitfieldExtract`
/// @param out the output of the expression stream
/// @param expr the call expression
/// @returns true if the expression is emitted
- bool EmitExtractBits(std::ostream& out, const ast::CallExpression* expr);
+ bool EmitExtractBits(utils::StringStream& out, const ast::CallExpression* expr);
/// Handles generating a call to `bitfieldInsert`
/// @param out the output of the expression stream
/// @param expr the call expression
/// @returns true if the expression is emitted
- bool EmitInsertBits(std::ostream& out, const ast::CallExpression* expr);
+ bool EmitInsertBits(utils::StringStream& out, const ast::CallExpression* expr);
/// Emulates 'fma' on GLSL ES, where it is unsupported.
/// @param out the output of the expression stream
/// @param expr the fma() expression
/// @returns true if the expression is emitted
- bool EmitEmulatedFMA(std::ostream& out, const ast::CallExpression* expr);
+ bool EmitEmulatedFMA(utils::StringStream& out, const ast::CallExpression* expr);
/// Create a float literal zero AST node, and associated semantic nodes.
/// @param stmt the statement which will own the semantic expression node
/// @returns an AST expression representing 0.0f
@@ -220,23 +223,25 @@
/// @param call the call expression
/// @param builtin the semantic information for the texture builtin
/// @returns true if the call expression is emitted
- bool EmitTextureCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+ bool EmitTextureCall(utils::StringStream& out,
+ const sem::Call* call,
+ const sem::Builtin* builtin);
/// Handles generating a call to the `select()` builtin
/// @param out the output of the expression stream
/// @param expr the call expression
/// @returns true if the call expression is emitted
- bool EmitCountOneBitsCall(std::ostream& out, const ast::CallExpression* expr);
+ bool EmitCountOneBitsCall(utils::StringStream& out, const ast::CallExpression* expr);
/// Handles generating a call to the `countOneBits()` builtin
/// @param out the output of the expression stream
/// @param expr the call expression
/// @returns true if the call expression is emitted
- bool EmitSelectCall(std::ostream& out, const ast::CallExpression* expr);
+ bool EmitSelectCall(utils::StringStream& out, const ast::CallExpression* expr);
/// Handles generating a call to the `dot()` builtin
/// @param out the output of the expression stream
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitDotCall(std::ostream& out,
+ bool EmitDotCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `modf()` builtin
@@ -244,7 +249,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitModfCall(std::ostream& out,
+ bool EmitModfCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `frexp()` builtin
@@ -252,7 +257,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitFrexpCall(std::ostream& out,
+ bool EmitFrexpCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `degrees()` builtin
@@ -260,7 +265,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitDegreesCall(std::ostream& out,
+ bool EmitDegreesCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `radians()` builtin
@@ -268,7 +273,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitRadiansCall(std::ostream& out,
+ bool EmitRadiansCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `quantizeToF16()` intrinsic
@@ -276,7 +281,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitQuantizeToF16Call(std::ostream& out,
+ bool EmitQuantizeToF16Call(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles a case statement
@@ -295,7 +300,7 @@
/// @param out the output of the expression stream
/// @param expr the expression
/// @returns true if the expression was emitted
- bool EmitExpression(std::ostream& out, const ast::Expression* expr);
+ bool EmitExpression(utils::StringStream& out, const ast::Expression* expr);
/// Handles generating a function
/// @param func the function to generate
/// @returns true if the function was emitted
@@ -342,14 +347,14 @@
/// Handles emitting interpolation qualifiers
/// @param out the output of the expression stream
/// @param attrs the attributes
- void EmitInterpolationQualifiers(std::ostream& out,
+ void EmitInterpolationQualifiers(utils::StringStream& out,
utils::VectorRef<const ast::Attribute*> attrs);
/// Handles emitting attributes
/// @param out the output of the expression stream
/// @param var the global variable semantics
/// @param attrs the attributes
/// @returns true if the attributes were emitted
- bool EmitAttributes(std::ostream& out,
+ bool EmitAttributes(utils::StringStream& out,
const sem::GlobalVariable* var,
utils::VectorRef<const ast::Attribute*> attrs);
/// Handles emitting the entry point function
@@ -364,12 +369,12 @@
/// @param out the output stream
/// @param constant the constant value to emit
/// @returns true if the constant value was successfully emitted
- bool EmitConstant(std::ostream& out, const constant::Value* constant);
+ bool EmitConstant(utils::StringStream& out, const constant::Value* constant);
/// Handles a literal
/// @param out the output stream
/// @param lit the literal to emit
/// @returns true if the literal was successfully emitted
- bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit);
+ bool EmitLiteral(utils::StringStream& out, const ast::LiteralExpression* lit);
/// Handles a loop statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
@@ -386,12 +391,12 @@
/// @param out the output of the expression stream
/// @param expr the identifier expression
/// @returns true if the identifier was emitted
- bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
+ bool EmitIdentifier(utils::StringStream& out, const ast::IdentifierExpression* expr);
/// Handles a member accessor expression
/// @param out the output of the expression stream
/// @param expr the member accessor expression
/// @returns true if the member accessor was emitted
- bool EmitMemberAccessor(std::ostream& out, const ast::MemberAccessorExpression* expr);
+ bool EmitMemberAccessor(utils::StringStream& out, const ast::MemberAccessorExpression* expr);
/// Handles return statements
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted
@@ -413,7 +418,7 @@
/// @param name_printed (optional) if not nullptr and an array was printed
/// then the boolean is set to true.
/// @returns true if the type is emitted
- bool EmitType(std::ostream& out,
+ bool EmitType(utils::StringStream& out,
const type::Type* type,
builtin::AddressSpace address_space,
builtin::Access access,
@@ -426,7 +431,7 @@
/// @param access the access control type of the variable
/// @param name the name to emit
/// @returns true if the type is emitted
- bool EmitTypeAndName(std::ostream& out,
+ bool EmitTypeAndName(utils::StringStream& out,
const type::Type* type,
builtin::AddressSpace address_space,
builtin::Access access,
@@ -446,12 +451,12 @@
/// @param out the output of the expression stream
/// @param expr the expression to emit
/// @returns true if the expression was emitted
- bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
+ bool EmitUnaryOp(utils::StringStream& out, const ast::UnaryOpExpression* expr);
/// Emits the zero value for the given type
/// @param out the output stream
/// @param type the type to emit the value for
/// @returns true if the zero value was successfully emitted.
- bool EmitZeroValue(std::ostream& out, const type::Type* type);
+ bool EmitZeroValue(utils::StringStream& out, const type::Type* type);
/// Handles generating a 'var' declaration
/// @param var the variable to generate
/// @returns true if the variable was emitted
@@ -504,7 +509,7 @@
/// `params` is the name of all the generated function parameters
/// @returns true if the call expression is emitted
template <typename F>
- bool CallBuiltinHelper(std::ostream& out,
+ bool CallBuiltinHelper(utils::StringStream& out,
const ast::CallExpression* call,
const sem::Builtin* builtin,
F&& build);
diff --git a/src/tint/writer/glsl/generator_impl_array_accessor_test.cc b/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
index bd405d3..453af22 100644
--- a/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
@@ -14,6 +14,8 @@
#include "src/tint/writer/glsl/test_helper.h"
+#include "src/tint/utils/string_stream.h"
+
using namespace tint::number_suffixes; // NOLINT
namespace tint::writer::glsl {
@@ -28,7 +30,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "ary[5]");
}
diff --git a/src/tint/writer/glsl/generator_impl_binary_test.cc b/src/tint/writer/glsl/generator_impl_binary_test.cc
index f90a428..475ae46 100644
--- a/src/tint/writer/glsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/glsl/generator_impl_binary_test.cc
@@ -14,6 +14,7 @@
#include "src/tint/ast/call_statement.h"
#include "src/tint/ast/variable_decl_statement.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/glsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -55,7 +56,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -83,7 +84,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -102,7 +103,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -126,7 +127,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -161,7 +162,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(a * 1.0f)");
}
@@ -179,7 +180,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(a * 1.0hf)");
}
@@ -195,7 +196,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(1.0f * a)");
}
@@ -213,7 +214,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(1.0hf * a)");
}
@@ -228,7 +229,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(mat * 1.0f)");
}
@@ -245,7 +246,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(mat * 1.0hf)");
}
@@ -260,7 +261,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(1.0f * mat)");
}
@@ -277,7 +278,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(1.0hf * mat)");
}
@@ -292,7 +293,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(mat * vec3(1.0f))");
}
@@ -309,7 +310,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(mat * f16vec3(1.0hf))");
}
@@ -324,7 +325,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(vec3(1.0f) * mat)");
}
@@ -341,7 +342,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(f16vec3(1.0hf) * mat)");
}
@@ -355,7 +356,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(lhs * rhs)");
}
@@ -371,7 +372,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(lhs * rhs)");
}
@@ -385,7 +386,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
}
@@ -401,7 +402,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
}
@@ -415,7 +416,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
}
@@ -431,7 +432,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
}
@@ -445,7 +446,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
}
@@ -461,7 +462,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
}
@@ -475,7 +476,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
}
@@ -491,7 +492,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
}
@@ -592,7 +593,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(tint_tmp)");
EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
@@ -617,7 +618,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(tint_tmp)");
EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = a;
@@ -644,7 +645,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(tint_tmp)");
EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
diff --git a/src/tint/writer/glsl/generator_impl_bitcast_test.cc b/src/tint/writer/glsl/generator_impl_bitcast_test.cc
index a7d2f66..b6e4f92 100644
--- a/src/tint/writer/glsl/generator_impl_bitcast_test.cc
+++ b/src/tint/writer/glsl/generator_impl_bitcast_test.cc
@@ -14,6 +14,8 @@
#include "src/tint/writer/glsl/test_helper.h"
+#include "src/tint/utils/string_stream.h"
+
using namespace tint::number_suffixes; // NOLINT
namespace tint::writer::glsl {
@@ -28,7 +30,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
EXPECT_EQ(out.str(), "intBitsToFloat(a)");
}
@@ -40,7 +42,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
EXPECT_EQ(out.str(), "int(a)");
}
@@ -52,7 +54,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
EXPECT_EQ(out.str(), "uint(a)");
}
diff --git a/src/tint/writer/glsl/generator_impl_builtin_test.cc b/src/tint/writer/glsl/generator_impl_builtin_test.cc
index fa0781b..3d14a68 100644
--- a/src/tint/writer/glsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/glsl/generator_impl_builtin_test.cc
@@ -16,6 +16,7 @@
#include "src/tint/ast/call_statement.h"
#include "src/tint/ast/stage_attribute.h"
#include "src/tint/sem/call.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/glsl/test_helper.h"
using ::testing::HasSubstr;
@@ -65,8 +66,8 @@
CallParamType type,
ProgramBuilder* builder) {
std::string name;
- std::ostringstream str(name);
- str << builtin;
+ utils::StringStream str;
+ str << name << builtin;
switch (builtin) {
case BuiltinType::kAcos:
case BuiltinType::kAsin:
@@ -350,7 +351,7 @@
GeneratorImpl& gen = Build();
gen.increment_indent();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "dot(param1, param2)");
}
@@ -363,7 +364,7 @@
GeneratorImpl& gen = Build();
gen.increment_indent();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "(true ? b : a)");
}
@@ -376,7 +377,7 @@
GeneratorImpl& gen = Build();
gen.increment_indent();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "mix(a, b, bvec2(true, false))");
}
@@ -393,7 +394,7 @@
GeneratorImpl& gen = Build();
gen.increment_indent();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "((a) * (b) + (c))");
}
@@ -411,7 +412,7 @@
GeneratorImpl& gen = Build();
gen.increment_indent();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "((a) * (b) + (c))");
}
@@ -931,7 +932,7 @@
EXPECT_EQ(gen.result(), R"(#version 310 es
float tint_degrees(float param_0) {
- return param_0 * 57.295779513082322865f;
+ return param_0 * 57.295779513082323f;
}
@@ -959,7 +960,7 @@
EXPECT_EQ(gen.result(), R"(#version 310 es
vec3 tint_degrees(vec3 param_0) {
- return param_0 * 57.295779513082322865f;
+ return param_0 * 57.295779513082323f;
}
@@ -990,7 +991,7 @@
#extension GL_AMD_gpu_shader_half_float : require
float16_t tint_degrees(float16_t param_0) {
- return param_0 * 57.295779513082322865hf;
+ return param_0 * 57.295779513082323hf;
}
@@ -1021,7 +1022,7 @@
#extension GL_AMD_gpu_shader_half_float : require
f16vec3 tint_degrees(f16vec3 param_0) {
- return param_0 * 57.295779513082322865hf;
+ return param_0 * 57.295779513082323hf;
}
@@ -1049,7 +1050,7 @@
EXPECT_EQ(gen.result(), R"(#version 310 es
float tint_radians(float param_0) {
- return param_0 * 0.017453292519943295474f;
+ return param_0 * 0.017453292519943295f;
}
@@ -1077,7 +1078,7 @@
EXPECT_EQ(gen.result(), R"(#version 310 es
vec3 tint_radians(vec3 param_0) {
- return param_0 * 0.017453292519943295474f;
+ return param_0 * 0.017453292519943295f;
}
@@ -1108,7 +1109,7 @@
#extension GL_AMD_gpu_shader_half_float : require
float16_t tint_radians(float16_t param_0) {
- return param_0 * 0.017453292519943295474hf;
+ return param_0 * 0.017453292519943295hf;
}
@@ -1139,7 +1140,7 @@
#extension GL_AMD_gpu_shader_half_float : require
f16vec3 tint_radians(f16vec3 param_0) {
- return param_0 * 0.017453292519943295474hf;
+ return param_0 * 0.017453292519943295hf;
}
diff --git a/src/tint/writer/glsl/generator_impl_call_test.cc b/src/tint/writer/glsl/generator_impl_call_test.cc
index 2f81463..69a78f4 100644
--- a/src/tint/writer/glsl/generator_impl_call_test.cc
+++ b/src/tint/writer/glsl/generator_impl_call_test.cc
@@ -13,6 +13,7 @@
// limitations under the License.
#include "src/tint/ast/call_statement.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/glsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -30,7 +31,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "my_func()");
}
@@ -50,7 +51,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "my_func(param1, param2)");
}
diff --git a/src/tint/writer/glsl/generator_impl_cast_test.cc b/src/tint/writer/glsl/generator_impl_cast_test.cc
index 4954dee..41ee6f0 100644
--- a/src/tint/writer/glsl/generator_impl_cast_test.cc
+++ b/src/tint/writer/glsl/generator_impl_cast_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/glsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -27,7 +28,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
EXPECT_EQ(out.str(), "1.0f");
}
@@ -38,7 +39,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
EXPECT_EQ(out.str(), "vec3(1.0f, 2.0f, 3.0f)");
}
diff --git a/src/tint/writer/glsl/generator_impl_identifier_test.cc b/src/tint/writer/glsl/generator_impl_identifier_test.cc
index cd0b109..64b9fb3 100644
--- a/src/tint/writer/glsl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/glsl/generator_impl_identifier_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/glsl/test_helper.h"
namespace tint::writer::glsl {
@@ -27,7 +28,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
EXPECT_EQ(out.str(), "foo");
}
diff --git a/src/tint/writer/glsl/generator_impl_import_test.cc b/src/tint/writer/glsl/generator_impl_import_test.cc
index 10da8aa..3201712 100644
--- a/src/tint/writer/glsl/generator_impl_import_test.cc
+++ b/src/tint/writer/glsl/generator_impl_import_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/glsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -39,7 +40,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f)");
}
@@ -78,7 +79,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1)");
}
@@ -95,7 +96,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(),
std::string(param.glsl_name) + "(vec3(0.100000001f, 0.200000003f, 0.300000012f))");
@@ -136,7 +137,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f, 2.0f)");
}
@@ -158,7 +159,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(),
std::string(param.glsl_name) + "(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f))");
@@ -183,7 +184,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1, 2)");
}
@@ -201,7 +202,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f, 2.0f, 3.0f)");
}
@@ -221,7 +222,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(),
std::string(param.glsl_name) +
@@ -242,7 +243,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1, 2, 3)");
}
@@ -258,7 +259,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string("determinant(var)"));
}
diff --git a/src/tint/writer/glsl/generator_impl_member_accessor_test.cc b/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
index e551c75..2eb1b8e 100644
--- a/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
@@ -241,13 +241,22 @@
TypeCase{ty_vec4<f32>, "data.inner.b = value"},
TypeCase{ty_vec4<i32>, "data.inner.b = value"},
TypeCase{ty_mat2x2<f32>, "data.inner.b = value"},
- TypeCase{ty_mat2x3<f32>, "data.inner.b = value"},
+ TypeCase{ty_mat2x3<f32>, R"(
+ data.inner.b[0] = value[0u];
+ data.inner.b[1] = value[1u];)"},
TypeCase{ty_mat2x4<f32>, "data.inner.b = value"},
TypeCase{ty_mat3x2<f32>, "data.inner.b = value"},
- TypeCase{ty_mat3x3<f32>, "data.inner.b = value"},
+ TypeCase{ty_mat3x3<f32>, R"(
+ data.inner.b[0] = value[0u];
+ data.inner.b[1] = value[1u];
+ data.inner.b[2] = value[2u];)"},
TypeCase{ty_mat3x4<f32>, "data.inner.b = value"},
TypeCase{ty_mat4x2<f32>, "data.inner.b = value"},
- TypeCase{ty_mat4x3<f32>, "data.inner.b = value"},
+ TypeCase{ty_mat4x3<f32>, R"(
+ data.inner.b[0] = value[0u];
+ data.inner.b[1] = value[1u];
+ data.inner.b[2] = value[2u];
+ data.inner.b[3] = value[3u];)"},
TypeCase{ty_mat4x4<f32>, "data.inner.b = value"}));
TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_Matrix_Empty) {
@@ -286,8 +295,13 @@
Data inner;
} data;
+void assign_and_preserve_padding_data_b(mat2x3 value) {
+ data.inner.b[0] = value[0u];
+ data.inner.b[1] = value[1u];
+}
+
void tint_symbol() {
- data.inner.b = mat2x3(vec3(0.0f), vec3(0.0f));
+ assign_and_preserve_padding_data_b(mat2x3(vec3(0.0f), vec3(0.0f)));
}
void main() {
diff --git a/src/tint/writer/glsl/generator_impl_type_test.cc b/src/tint/writer/glsl/generator_impl_type_test.cc
index 492910d..2cc13f6 100644
--- a/src/tint/writer/glsl/generator_impl_type_test.cc
+++ b/src/tint/writer/glsl/generator_impl_type_test.cc
@@ -21,6 +21,7 @@
#include "src/tint/type/sampler.h"
#include "src/tint/type/storage_texture.h"
#include "src/tint/type/texture_dimension.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/glsl/test_helper.h"
using ::testing::HasSubstr;
@@ -38,7 +39,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, "ary"))
<< gen.error();
@@ -51,7 +52,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, "ary"))
<< gen.error();
@@ -64,7 +65,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, "ary"))
<< gen.error();
@@ -77,7 +78,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -89,7 +90,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, bool_, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -101,7 +102,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, f32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -115,7 +116,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, f16, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -127,7 +128,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, i32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -141,7 +142,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, mat2x3, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -157,7 +158,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, mat2x3, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -194,7 +195,7 @@
GeneratorImpl& gen = Build();
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, sem_s, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -243,7 +244,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, u32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -256,7 +257,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, vec3, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -271,7 +272,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, vec3, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -283,7 +284,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, void_, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -295,7 +296,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_FALSE(gen.EmitType(out, sampler, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -306,7 +307,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_FALSE(gen.EmitType(out, sampler, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -513,7 +514,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, s, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
diff --git a/src/tint/writer/glsl/generator_impl_unary_op_test.cc b/src/tint/writer/glsl/generator_impl_unary_op_test.cc
index 18f180e..b7c5fd1 100644
--- a/src/tint/writer/glsl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/glsl/generator_impl_unary_op_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/glsl/test_helper.h"
namespace tint::writer::glsl {
@@ -26,7 +27,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "expr");
}
@@ -38,7 +39,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "~(expr)");
}
@@ -51,7 +52,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "expr");
}
@@ -63,7 +64,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "!(expr)");
}
@@ -75,7 +76,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "-(expr)");
}
diff --git a/src/tint/writer/hlsl/generator.h b/src/tint/writer/hlsl/generator.h
index c624943..80dd518 100644
--- a/src/tint/writer/hlsl/generator.h
+++ b/src/tint/writer/hlsl/generator.h
@@ -61,6 +61,8 @@
/// Interstage locations actually used as inputs in the next stage of the pipeline.
/// This is potentially used for truncating unused interstage outputs at current shader stage.
std::bitset<16> interstage_locations;
+ /// Set to `true` to generate polyfill for `reflect` builtin for vec2<f32>
+ bool polyfill_reflect_vec2_f32 = false;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(root_constant_binding_point,
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 787962b..2bb4a9f 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -75,6 +75,7 @@
#include "src/tint/utils/map.h"
#include "src/tint/utils/scoped_assignment.h"
#include "src/tint/utils/string.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/append_vector.h"
#include "src/tint/writer/check_supported_extensions.h"
#include "src/tint/writer/float_to_string.h"
@@ -114,7 +115,7 @@
}
}
-void PrintF32(std::ostream& out, float value) {
+void PrintF32(utils::StringStream& out, float value) {
if (std::isinf(value)) {
out << "0.0f " << (value >= 0 ? "/* inf */" : "/* -inf */");
} else if (std::isnan(value)) {
@@ -124,7 +125,7 @@
}
}
-void PrintF16(std::ostream& out, float value) {
+void PrintF16(utils::StringStream& out, float value) {
if (std::isinf(value)) {
out << "0.0h " << (value >= 0 ? "/* inf */" : "/* -inf */");
} else if (std::isnan(value)) {
@@ -143,7 +144,7 @@
sem::BindingPoint const binding_point;
};
-std::ostream& operator<<(std::ostream& s, const RegisterAndSpace& rs) {
+utils::StringStream& operator<<(utils::StringStream& s, const RegisterAndSpace& rs) {
s << " : register(" << rs.reg << rs.binding_point.binding << ", space" << rs.binding_point.group
<< ")";
return s;
@@ -181,6 +182,7 @@
polyfills.insert_bits = transform::BuiltinPolyfill::Level::kFull;
polyfills.int_div_mod = true;
polyfills.precise_float_mod = true;
+ polyfills.reflect_vec2_f32 = options.polyfill_reflect_vec2_f32;
polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
polyfills.workgroup_uniform_load = true;
data.Add<transform::BuiltinPolyfill::Config>(polyfills);
@@ -376,7 +378,7 @@
auto name = utils::GetOrCreate(dynamic_vector_write_, vec, [&]() -> std::string {
std::string fn;
{
- std::ostringstream ss;
+ utils::StringStream ss;
if (!EmitType(ss, vec, tint::builtin::AddressSpace::kUndefined,
builtin::Access::kUndefined, "")) {
return "";
@@ -450,7 +452,7 @@
auto name = utils::GetOrCreate(dynamic_matrix_vector_write_, mat, [&]() -> std::string {
std::string fn;
{
- std::ostringstream ss;
+ utils::StringStream ss;
if (!EmitType(ss, mat, tint::builtin::AddressSpace::kUndefined,
builtin::Access::kUndefined, "")) {
return "";
@@ -519,7 +521,7 @@
auto name = utils::GetOrCreate(dynamic_matrix_scalar_write_, mat, [&]() -> std::string {
std::string fn;
{
- std::ostringstream ss;
+ utils::StringStream ss;
if (!EmitType(ss, mat, tint::builtin::AddressSpace::kUndefined,
builtin::Access::kUndefined, "")) {
return "";
@@ -615,7 +617,8 @@
return true;
}
-bool GeneratorImpl::EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr) {
+bool GeneratorImpl::EmitIndexAccessor(utils::StringStream& out,
+ const ast::IndexAccessorExpression* expr) {
if (!EmitExpression(out, expr->object)) {
return false;
}
@@ -629,7 +632,7 @@
return true;
}
-bool GeneratorImpl::EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr) {
+bool GeneratorImpl::EmitBitcast(utils::StringStream& out, const ast::BitcastExpression* expr) {
auto* type = TypeOf(expr);
if (auto* vec = type->UnwrapRef()->As<type::Vector>()) {
type = vec->type();
@@ -697,7 +700,7 @@
return true;
}
-bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* expr) {
+bool GeneratorImpl::EmitBinary(utils::StringStream& out, const ast::BinaryExpression* expr) {
if (expr->op == ast::BinaryOp::kLogicalAnd || expr->op == ast::BinaryOp::kLogicalOr) {
auto name = UniqueIdentifier(kTempNamePrefix);
@@ -872,7 +875,7 @@
return true;
}
-bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitCall(utils::StringStream& out, const ast::CallExpression* expr) {
auto* call = builder_.Sem().Get<sem::Call>(expr);
auto* target = call->Target();
return Switch(
@@ -887,7 +890,7 @@
});
}
-bool GeneratorImpl::EmitFunctionCall(std::ostream& out,
+bool GeneratorImpl::EmitFunctionCall(utils::StringStream& out,
const sem::Call* call,
const sem::Function* func) {
auto* expr = call->Declaration();
@@ -943,7 +946,7 @@
return true;
}
-bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
+bool GeneratorImpl::EmitBuiltinCall(utils::StringStream& out,
const sem::Call* call,
const sem::Builtin* builtin) {
const auto type = builtin->Type();
@@ -1028,7 +1031,7 @@
return true;
}
-bool GeneratorImpl::EmitValueConversion(std::ostream& out,
+bool GeneratorImpl::EmitValueConversion(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConversion* conv) {
if (!EmitType(out, conv->Target(), builtin::AddressSpace::kUndefined,
@@ -1045,7 +1048,7 @@
return true;
}
-bool GeneratorImpl::EmitValueConstructor(std::ostream& out,
+bool GeneratorImpl::EmitValueConstructor(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConstructor* ctor) {
auto* type = call->Type();
@@ -1109,7 +1112,7 @@
}
bool GeneratorImpl::EmitUniformBufferAccess(
- std::ostream& out,
+ utils::StringStream& out,
const ast::CallExpression* expr,
const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
auto const buffer = program_->Symbols().NameFor(intrinsic->buffer);
@@ -1181,7 +1184,7 @@
out << ")";
return result;
};
- auto load_u32_to = [&](std::ostream& target) {
+ auto load_u32_to = [&](utils::StringStream& target) {
target << buffer;
if (scalar_offset_constant) {
target << "[" << (scalar_offset_index / 4) << "]."
@@ -1194,7 +1197,7 @@
};
auto load_u32 = [&] { return load_u32_to(out); };
// Has a minimum alignment of 8 bytes, so is either .xy or .zw
- auto load_vec2_u32_to = [&](std::ostream& target) {
+ auto load_vec2_u32_to = [&](utils::StringStream& target) {
if (scalar_offset_constant) {
target << buffer << "[" << (scalar_offset_index / 4) << "]"
<< ((scalar_offset_index & 2) == 0 ? ".xy" : ".zw");
@@ -1397,7 +1400,7 @@
}
bool GeneratorImpl::EmitStorageBufferAccess(
- std::ostream& out,
+ utils::StringStream& out,
const ast::CallExpression* expr,
const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
auto const buffer = program_->Symbols().NameFor(intrinsic->buffer);
@@ -1762,7 +1765,7 @@
return false;
}
-bool GeneratorImpl::EmitWorkgroupAtomicCall(std::ostream& out,
+bool GeneratorImpl::EmitWorkgroupAtomicCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
std::string result = UniqueIdentifier("atomic_result");
@@ -1937,7 +1940,7 @@
return false;
}
-bool GeneratorImpl::EmitSelectCall(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitSelectCall(utils::StringStream& out, const ast::CallExpression* expr) {
auto* expr_false = expr->args[0];
auto* expr_true = expr->args[1];
auto* expr_cond = expr->args[2];
@@ -1961,7 +1964,7 @@
return true;
}
-bool GeneratorImpl::EmitModfCall(std::ostream& out,
+bool GeneratorImpl::EmitModfCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
return CallBuiltinHelper(
@@ -1994,7 +1997,7 @@
});
}
-bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
+bool GeneratorImpl::EmitFrexpCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
return CallBuiltinHelper(
@@ -2035,7 +2038,7 @@
});
}
-bool GeneratorImpl::EmitDegreesCall(std::ostream& out,
+bool GeneratorImpl::EmitDegreesCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
return CallBuiltinHelper(out, expr, builtin,
@@ -2046,7 +2049,7 @@
});
}
-bool GeneratorImpl::EmitRadiansCall(std::ostream& out,
+bool GeneratorImpl::EmitRadiansCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
return CallBuiltinHelper(out, expr, builtin,
@@ -2060,7 +2063,9 @@
// The HLSL `sign` method always returns an `int` result (scalar or vector). In WGSL the result is
// expected to be the same type as the argument. This injects a cast to the expected WGSL result
// type after the call to `sign`.
-bool GeneratorImpl::EmitSignCall(std::ostream& out, const sem::Call* call, const sem::Builtin*) {
+bool GeneratorImpl::EmitSignCall(utils::StringStream& out,
+ const sem::Call* call,
+ const sem::Builtin*) {
auto* arg = call->Arguments()[0];
if (!EmitType(out, arg->Type(), builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
"")) {
@@ -2074,7 +2079,7 @@
return true;
}
-bool GeneratorImpl::EmitQuantizeToF16Call(std::ostream& out,
+bool GeneratorImpl::EmitQuantizeToF16Call(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
// Emulate by casting to min16float and back again.
@@ -2090,7 +2095,7 @@
return true;
}
-bool GeneratorImpl::EmitDataPackingCall(std::ostream& out,
+bool GeneratorImpl::EmitDataPackingCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
return CallBuiltinHelper(
@@ -2153,7 +2158,7 @@
});
}
-bool GeneratorImpl::EmitDataUnpackingCall(std::ostream& out,
+bool GeneratorImpl::EmitDataUnpackingCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
return CallBuiltinHelper(
@@ -2220,7 +2225,7 @@
});
}
-bool GeneratorImpl::EmitDP4aCall(std::ostream& out,
+bool GeneratorImpl::EmitDP4aCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
// TODO(crbug.com/tint/1497): support the polyfill version of DP4a functions.
@@ -2248,7 +2253,7 @@
});
}
-bool GeneratorImpl::EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin) {
+bool GeneratorImpl::EmitBarrierCall(utils::StringStream& out, const sem::Builtin* builtin) {
// TODO(crbug.com/tint/661): Combine sequential barriers to a single
// instruction.
if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
@@ -2263,7 +2268,7 @@
return true;
}
-bool GeneratorImpl::EmitTextureCall(std::ostream& out,
+bool GeneratorImpl::EmitTextureCall(utils::StringStream& out,
const sem::Call* call,
const sem::Builtin* builtin) {
using Usage = sem::ParameterUsage;
@@ -2772,7 +2777,7 @@
return true;
}
-bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
+bool GeneratorImpl::EmitExpression(utils::StringStream& out, const ast::Expression* expr) {
if (auto* sem = builder_.Sem().GetVal(expr)) {
if (auto* constant = sem->ConstantValue()) {
bool is_variable_initializer = false;
@@ -2801,7 +2806,8 @@
});
}
-bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) {
+bool GeneratorImpl::EmitIdentifier(utils::StringStream& out,
+ const ast::IdentifierExpression* expr) {
out << builder_.Symbols().NameFor(expr->identifier->symbol);
return true;
}
@@ -3275,7 +3281,7 @@
return true;
}
-bool GeneratorImpl::EmitConstant(std::ostream& out,
+bool GeneratorImpl::EmitConstant(utils::StringStream& out,
const constant::Value* constant,
bool is_variable_initializer) {
return Switch(
@@ -3395,7 +3401,7 @@
return true;
}
- auto emit_member_values = [&](std::ostream& o) {
+ auto emit_member_values = [&](utils::StringStream& o) {
o << "{";
for (size_t i = 0; i < s->Members().Length(); i++) {
if (i > 0) {
@@ -3437,7 +3443,7 @@
});
}
-bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit) {
+bool GeneratorImpl::EmitLiteral(utils::StringStream& out, const ast::LiteralExpression* lit) {
return Switch(
lit,
[&](const ast::BoolLiteralExpression* l) {
@@ -3473,7 +3479,7 @@
});
}
-bool GeneratorImpl::EmitValue(std::ostream& out, const type::Type* type, int value) {
+bool GeneratorImpl::EmitValue(utils::StringStream& out, const type::Type* type, int value) {
return Switch(
type,
[&](const type::Bool*) {
@@ -3548,7 +3554,7 @@
});
}
-bool GeneratorImpl::EmitZeroValue(std::ostream& out, const type::Type* type) {
+bool GeneratorImpl::EmitZeroValue(utils::StringStream& out, const type::Type* type) {
return EmitValue(out, type, 0);
}
@@ -3597,7 +3603,7 @@
}
TextBuffer cond_pre;
- std::stringstream cond_buf;
+ utils::StringStream cond_buf;
if (auto* cond = stmt->condition) {
TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
if (!EmitExpression(cond_buf, cond)) {
@@ -3689,7 +3695,7 @@
bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) {
TextBuffer cond_pre;
- std::stringstream cond_buf;
+ utils::StringStream cond_buf;
{
auto* cond = stmt->condition;
TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
@@ -3737,7 +3743,7 @@
return true;
}
-bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
+bool GeneratorImpl::EmitMemberAccessor(utils::StringStream& out,
const ast::MemberAccessorExpression* expr) {
if (!EmitExpression(out, expr->object)) {
return false;
@@ -3910,7 +3916,7 @@
return true;
}
-bool GeneratorImpl::EmitType(std::ostream& out,
+bool GeneratorImpl::EmitType(utils::StringStream& out,
const type::Type* type,
builtin::AddressSpace address_space,
builtin::Access access,
@@ -4137,7 +4143,7 @@
});
}
-bool GeneratorImpl::EmitTypeAndName(std::ostream& out,
+bool GeneratorImpl::EmitTypeAndName(utils::StringStream& out,
const type::Type* type,
builtin::AddressSpace address_space,
builtin::Access access,
@@ -4248,7 +4254,7 @@
return true;
}
-bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr) {
+bool GeneratorImpl::EmitUnaryOp(utils::StringStream& out, const ast::UnaryOpExpression* expr) {
switch (expr->op) {
case ast::UnaryOp::kIndirection:
case ast::UnaryOp::kAddressOf:
@@ -4320,7 +4326,7 @@
}
template <typename F>
-bool GeneratorImpl::CallBuiltinHelper(std::ostream& out,
+bool GeneratorImpl::CallBuiltinHelper(utils::StringStream& out,
const ast::CallExpression* call,
const sem::Builtin* builtin,
F&& build) {
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index 6db120c..f7adc9f 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -88,7 +88,7 @@
/// @param out the output of the expression stream
/// @param expr the expression to emit
/// @returns true if the index accessor was emitted
- bool EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr);
+ bool EmitIndexAccessor(utils::StringStream& out, const ast::IndexAccessorExpression* expr);
/// Handles an assignment statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
@@ -97,12 +97,12 @@
/// @param out the output of the expression stream
/// @param expr the binary expression
/// @returns true if the expression was emitted, false otherwise
- bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
+ bool EmitBinary(utils::StringStream& out, const ast::BinaryExpression* expr);
/// Handles generating a bitcast expression
/// @param out the output of the expression stream
/// @param expr the as expression
/// @returns true if the bitcast was emitted
- bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
+ bool EmitBitcast(utils::StringStream& out, const ast::BitcastExpression* expr);
/// Emits a list of statements
/// @param stmts the statement list
/// @returns true if the statements were emitted successfully
@@ -127,25 +127,29 @@
/// @param out the output of the expression stream
/// @param expr the call expression
/// @returns true if the call expression is emitted
- bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
+ bool EmitCall(utils::StringStream& out, const ast::CallExpression* expr);
/// Handles generating a function call expression
/// @param out the output of the expression stream
/// @param call the call expression
/// @param function the function being called
/// @returns true if the expression is emitted
- bool EmitFunctionCall(std::ostream& out, const sem::Call* call, const sem::Function* function);
+ bool EmitFunctionCall(utils::StringStream& out,
+ const sem::Call* call,
+ const sem::Function* function);
/// Handles generating a builtin call expression
/// @param out the output of the expression stream
/// @param call the call expression
/// @param builtin the builtin being called
/// @returns true if the expression is emitted
- bool EmitBuiltinCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+ bool EmitBuiltinCall(utils::StringStream& out,
+ const sem::Call* call,
+ const sem::Builtin* builtin);
/// Handles generating a value conversion expression
/// @param out the output of the expression stream
/// @param call the call expression
/// @param conv the value conversion
/// @returns true if the expression is emitted
- bool EmitValueConversion(std::ostream& out,
+ bool EmitValueConversion(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConversion* conv);
/// Handles generating a value constructor expression
@@ -153,7 +157,7 @@
/// @param call the call expression
/// @param ctor the value constructor
/// @returns true if the expression is emitted
- bool EmitValueConstructor(std::ostream& out,
+ bool EmitValueConstructor(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConstructor* ctor);
/// Handles generating a call expression to a
@@ -162,7 +166,7 @@
/// @param expr the call expression
/// @param intrinsic the transform::DecomposeMemoryAccess::Intrinsic
/// @returns true if the call expression is emitted
- bool EmitUniformBufferAccess(std::ostream& out,
+ bool EmitUniformBufferAccess(utils::StringStream& out,
const ast::CallExpression* expr,
const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
/// Handles generating a call expression to a
@@ -171,20 +175,20 @@
/// @param expr the call expression
/// @param intrinsic the transform::DecomposeMemoryAccess::Intrinsic
/// @returns true if the call expression is emitted
- bool EmitStorageBufferAccess(std::ostream& out,
+ bool EmitStorageBufferAccess(utils::StringStream& out,
const ast::CallExpression* expr,
const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
/// Handles generating a barrier intrinsic call
/// @param out the output of the expression stream
/// @param builtin the semantic information for the barrier builtin
/// @returns true if the call expression is emitted
- bool EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin);
+ bool EmitBarrierCall(utils::StringStream& out, const sem::Builtin* builtin);
/// Handles generating an atomic intrinsic call for a storage buffer variable
/// @param out the output of the expression stream
/// @param expr the call expression
/// @param intrinsic the atomic intrinsic
/// @returns true if the call expression is emitted
- bool EmitStorageAtomicCall(std::ostream& out,
+ bool EmitStorageAtomicCall(utils::StringStream& out,
const ast::CallExpression* expr,
const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
/// Handles generating the helper function for the atomic intrinsic function
@@ -198,7 +202,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the atomic builtin
/// @returns true if the call expression is emitted
- bool EmitWorkgroupAtomicCall(std::ostream& out,
+ bool EmitWorkgroupAtomicCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to a texture function (`textureSample`,
@@ -207,18 +211,20 @@
/// @param call the call expression
/// @param builtin the semantic information for the texture builtin
/// @returns true if the call expression is emitted
- bool EmitTextureCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+ bool EmitTextureCall(utils::StringStream& out,
+ const sem::Call* call,
+ const sem::Builtin* builtin);
/// Handles generating a call to the `select()` builtin
/// @param out the output of the expression stream
/// @param expr the call expression
/// @returns true if the call expression is emitted
- bool EmitSelectCall(std::ostream& out, const ast::CallExpression* expr);
+ bool EmitSelectCall(utils::StringStream& out, const ast::CallExpression* expr);
/// Handles generating a call to the `modf()` builtin
/// @param out the output of the expression stream
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitModfCall(std::ostream& out,
+ bool EmitModfCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `frexp()` builtin
@@ -226,7 +232,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitFrexpCall(std::ostream& out,
+ bool EmitFrexpCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `degrees()` builtin
@@ -234,7 +240,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitDegreesCall(std::ostream& out,
+ bool EmitDegreesCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `radians()` builtin
@@ -242,7 +248,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitRadiansCall(std::ostream& out,
+ bool EmitRadiansCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `sign()` builtin
@@ -250,13 +256,13 @@
/// @param call the call semantic node
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitSignCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+ bool EmitSignCall(utils::StringStream& out, const sem::Call* call, const sem::Builtin* builtin);
/// Handles generating a call to data packing builtin
/// @param out the output of the expression stream
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitDataPackingCall(std::ostream& out,
+ bool EmitDataPackingCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to data unpacking builtin
@@ -264,7 +270,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitDataUnpackingCall(std::ostream& out,
+ bool EmitDataUnpackingCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `quantizeToF16()` intrinsic
@@ -272,7 +278,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitQuantizeToF16Call(std::ostream& out,
+ bool EmitQuantizeToF16Call(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to DP4a builtins (dot4I8Packed and dot4U8Packed)
@@ -280,7 +286,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitDP4aCall(std::ostream& out,
+ bool EmitDP4aCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles a case statement
@@ -300,7 +306,7 @@
/// @param out the output of the expression stream
/// @param expr the expression
/// @returns true if the expression was emitted
- bool EmitExpression(std::ostream& out, const ast::Expression* expr);
+ bool EmitExpression(utils::StringStream& out, const ast::Expression* expr);
/// Handles generating a function
/// @param func the function to generate
/// @returns true if the function was emitted
@@ -357,14 +363,14 @@
/// @param is_variable_initializer true if the constant is used as the RHS of a variable
/// initializer
/// @returns true if the constant value was successfully emitted
- bool EmitConstant(std::ostream& out,
+ bool EmitConstant(utils::StringStream& out,
const constant::Value* constant,
bool is_variable_initializer);
/// Handles a literal
/// @param out the output stream
/// @param lit the literal to emit
/// @returns true if the literal was successfully emitted
- bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit);
+ bool EmitLiteral(utils::StringStream& out, const ast::LiteralExpression* lit);
/// Handles a loop statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
@@ -381,12 +387,12 @@
/// @param out the output of the expression stream
/// @param expr the identifier expression
/// @returns true if the identifeir was emitted
- bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
+ bool EmitIdentifier(utils::StringStream& out, const ast::IdentifierExpression* expr);
/// Handles a member accessor expression
/// @param out the output of the expression stream
/// @param expr the member accessor expression
/// @returns true if the member accessor was emitted
- bool EmitMemberAccessor(std::ostream& out, const ast::MemberAccessorExpression* expr);
+ bool EmitMemberAccessor(utils::StringStream& out, const ast::MemberAccessorExpression* expr);
/// Handles return statements
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted
@@ -412,7 +418,7 @@
/// @param name_printed (optional) if not nullptr and an array was printed
/// then the boolean is set to true.
/// @returns true if the type is emitted
- bool EmitType(std::ostream& out,
+ bool EmitType(utils::StringStream& out,
const type::Type* type,
builtin::AddressSpace address_space,
builtin::Access access,
@@ -425,7 +431,7 @@
/// @param access the access control type of the variable
/// @param name the name to emit
/// @returns true if the type is emitted
- bool EmitTypeAndName(std::ostream& out,
+ bool EmitTypeAndName(utils::StringStream& out,
const type::Type* type,
builtin::AddressSpace address_space,
builtin::Access access,
@@ -440,18 +446,18 @@
/// @param out the output of the expression stream
/// @param expr the expression to emit
/// @returns true if the expression was emitted
- bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
+ bool EmitUnaryOp(utils::StringStream& out, const ast::UnaryOpExpression* expr);
/// Emits `value` for the given type
/// @param out the output stream
/// @param type the type to emit the value for
/// @param value the value to emit
/// @returns true if the value was successfully emitted.
- bool EmitValue(std::ostream& out, const type::Type* type, int value);
+ bool EmitValue(utils::StringStream& out, const type::Type* type, int value);
/// Emits the zero value for the given type
/// @param out the output stream
/// @param type the type to emit the value for
/// @returns true if the zero value was successfully emitted.
- bool EmitZeroValue(std::ostream& out, const type::Type* type);
+ bool EmitZeroValue(utils::StringStream& out, const type::Type* type);
/// Handles generating a 'var' declaration
/// @param var the variable to generate
/// @returns true if the variable was emitted
@@ -541,7 +547,7 @@
/// `params` is the name of all the generated function parameters
/// @returns true if the call expression is emitted
template <typename F>
- bool CallBuiltinHelper(std::ostream& out,
+ bool CallBuiltinHelper(utils::StringStream& out,
const ast::CallExpression* call,
const sem::Builtin* builtin,
F&& build);
diff --git a/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc b/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
index 73eea96..df68694 100644
--- a/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/hlsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -28,7 +29,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "ary[5]");
}
diff --git a/src/tint/writer/hlsl/generator_impl_binary_test.cc b/src/tint/writer/hlsl/generator_impl_binary_test.cc
index c99ae54..630fc09 100644
--- a/src/tint/writer/hlsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_binary_test.cc
@@ -14,6 +14,7 @@
#include "src/tint/ast/call_statement.h"
#include "src/tint/ast/variable_decl_statement.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/hlsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -62,7 +63,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -94,7 +95,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -117,7 +118,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -145,7 +146,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -182,7 +183,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(1.0f).xxx");
}
@@ -199,7 +200,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(float16_t(1.0h)).xxx");
}
@@ -214,7 +215,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(1.0f).xxx");
}
@@ -231,7 +232,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(float16_t(1.0h)).xxx");
}
@@ -246,7 +247,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(mat * 1.0f)");
}
@@ -263,7 +264,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(mat * float16_t(1.0h))");
}
@@ -278,7 +279,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(1.0f * mat)");
}
@@ -295,7 +296,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(float16_t(1.0h) * mat)");
}
@@ -310,7 +311,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "mul((1.0f).xxx, mat)");
}
@@ -327,7 +328,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "mul((float16_t(1.0h)).xxx, mat)");
}
@@ -342,7 +343,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "mul(mat, (1.0f).xxx)");
}
@@ -359,7 +360,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "mul(mat, (float16_t(1.0h)).xxx)");
}
@@ -373,7 +374,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "mul(rhs, lhs)");
}
@@ -389,7 +390,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "mul(rhs, lhs)");
}
@@ -403,7 +404,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(tint_tmp)");
EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
@@ -428,7 +429,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(tint_tmp)");
EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = a;
@@ -455,7 +456,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(tint_tmp)");
EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
diff --git a/src/tint/writer/hlsl/generator_impl_bitcast_test.cc b/src/tint/writer/hlsl/generator_impl_bitcast_test.cc
index 5c4b9cc..3061fbe 100644
--- a/src/tint/writer/hlsl/generator_impl_bitcast_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_bitcast_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/hlsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -28,7 +29,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
EXPECT_EQ(out.str(), "asfloat(a)");
}
@@ -40,7 +41,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
EXPECT_EQ(out.str(), "asint(a)");
}
@@ -52,7 +53,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
EXPECT_EQ(out.str(), "asuint(a)");
}
diff --git a/src/tint/writer/hlsl/generator_impl_builtin_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
index 7cd3de3..229213b 100644
--- a/src/tint/writer/hlsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
@@ -16,6 +16,7 @@
#include "src/tint/ast/call_statement.h"
#include "src/tint/ast/stage_attribute.h"
#include "src/tint/sem/call.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/hlsl/test_helper.h"
using ::testing::HasSubstr;
@@ -64,8 +65,8 @@
CallParamType type,
ProgramBuilder* builder) {
std::string name;
- std::ostringstream str(name);
- str << builtin;
+ utils::StringStream str;
+ str << name << builtin;
switch (builtin) {
case BuiltinType::kAcos:
case BuiltinType::kAsin:
@@ -347,7 +348,7 @@
GeneratorImpl& gen = Build();
gen.increment_indent();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "dot(param1, param2)");
}
@@ -360,7 +361,7 @@
GeneratorImpl& gen = Build();
gen.increment_indent();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "(true ? b : a)");
}
@@ -373,7 +374,7 @@
GeneratorImpl& gen = Build();
gen.increment_indent();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "(bool2(true, false) ? b : a)");
}
@@ -811,7 +812,7 @@
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(float tint_degrees(float param_0) {
- return param_0 * 57.295779513082322865;
+ return param_0 * 57.295779513082323;
}
[numthreads(1, 1, 1)]
@@ -832,7 +833,7 @@
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(float3 tint_degrees(float3 param_0) {
- return param_0 * 57.295779513082322865;
+ return param_0 * 57.295779513082323;
}
[numthreads(1, 1, 1)]
@@ -855,7 +856,7 @@
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(float16_t tint_degrees(float16_t param_0) {
- return param_0 * 57.295779513082322865;
+ return param_0 * 57.295779513082323;
}
[numthreads(1, 1, 1)]
@@ -878,7 +879,7 @@
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(vector<float16_t, 3> tint_degrees(vector<float16_t, 3> param_0) {
- return param_0 * 57.295779513082322865;
+ return param_0 * 57.295779513082323;
}
[numthreads(1, 1, 1)]
@@ -899,7 +900,7 @@
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(float tint_radians(float param_0) {
- return param_0 * 0.017453292519943295474;
+ return param_0 * 0.017453292519943295;
}
[numthreads(1, 1, 1)]
@@ -920,7 +921,7 @@
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(float3 tint_radians(float3 param_0) {
- return param_0 * 0.017453292519943295474;
+ return param_0 * 0.017453292519943295;
}
[numthreads(1, 1, 1)]
@@ -943,7 +944,7 @@
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(float16_t tint_radians(float16_t param_0) {
- return param_0 * 0.017453292519943295474;
+ return param_0 * 0.017453292519943295;
}
[numthreads(1, 1, 1)]
@@ -966,7 +967,7 @@
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(vector<float16_t, 3> tint_radians(vector<float16_t, 3> param_0) {
- return param_0 * 0.017453292519943295474;
+ return param_0 * 0.017453292519943295;
}
[numthreads(1, 1, 1)]
diff --git a/src/tint/writer/hlsl/generator_impl_call_test.cc b/src/tint/writer/hlsl/generator_impl_call_test.cc
index 9947a08..50909bb 100644
--- a/src/tint/writer/hlsl/generator_impl_call_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_call_test.cc
@@ -13,6 +13,7 @@
// limitations under the License.
#include "src/tint/ast/call_statement.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/hlsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -30,7 +31,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "my_func()");
}
@@ -50,7 +51,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "my_func(param1, param2)");
}
diff --git a/src/tint/writer/hlsl/generator_impl_cast_test.cc b/src/tint/writer/hlsl/generator_impl_cast_test.cc
index 4c522a3..7bb77da 100644
--- a/src/tint/writer/hlsl/generator_impl_cast_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_cast_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/hlsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -27,7 +28,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
EXPECT_EQ(out.str(), "1.0f");
}
@@ -38,7 +39,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
EXPECT_EQ(out.str(), "float3(1.0f, 2.0f, 3.0f)");
}
diff --git a/src/tint/writer/hlsl/generator_impl_identifier_test.cc b/src/tint/writer/hlsl/generator_impl_identifier_test.cc
index 1e2b47b..db09c45 100644
--- a/src/tint/writer/hlsl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_identifier_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/hlsl/test_helper.h"
namespace tint::writer::hlsl {
@@ -27,7 +28,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
EXPECT_EQ(out.str(), "foo");
}
diff --git a/src/tint/writer/hlsl/generator_impl_import_test.cc b/src/tint/writer/hlsl/generator_impl_import_test.cc
index 425c663..28b72dc 100644
--- a/src/tint/writer/hlsl/generator_impl_import_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_import_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/hlsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -39,7 +40,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f)");
}
@@ -77,7 +78,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1)");
}
@@ -94,7 +95,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(),
std::string(param.hlsl_name) + "(float3(0.100000001f, 0.200000003f, 0.300000012f))");
@@ -134,7 +135,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f, 2.0f)");
}
@@ -156,7 +157,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.hlsl_name) +
"(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f))");
@@ -181,7 +182,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1, 2)");
}
@@ -199,7 +200,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f, 2.0f, 3.0f)");
}
@@ -220,7 +221,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(
out.str(),
@@ -243,7 +244,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1, 2, 3)");
}
@@ -259,7 +260,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string("determinant(var)"));
}
@@ -272,7 +273,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string("float(min16float(v))"));
}
@@ -285,7 +286,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string("float3(min16float3(v))"));
}
diff --git a/src/tint/writer/hlsl/generator_impl_type_test.cc b/src/tint/writer/hlsl/generator_impl_type_test.cc
index 71fe338..4ee8a22 100644
--- a/src/tint/writer/hlsl/generator_impl_type_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_type_test.cc
@@ -21,6 +21,7 @@
#include "src/tint/type/sampler.h"
#include "src/tint/type/storage_texture.h"
#include "src/tint/type/texture_dimension.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/hlsl/test_helper.h"
using ::testing::HasSubstr;
@@ -38,7 +39,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, "ary"))
<< gen.error();
@@ -51,7 +52,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, "ary"))
<< gen.error();
@@ -64,7 +65,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, "ary"))
<< gen.error();
@@ -77,7 +78,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -89,7 +90,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, bool_, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -101,7 +102,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, f16, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -113,7 +114,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, f32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -125,7 +126,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, i32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -139,7 +140,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, mat2x3, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -153,7 +154,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, mat2x3, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -203,7 +204,7 @@
GeneratorImpl& gen = Build();
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, sem_s, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -251,7 +252,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, u32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -264,7 +265,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, vec3, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -276,7 +277,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, void_, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -288,7 +289,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, sampler, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -300,7 +301,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, sampler, builtin::AddressSpace::kUndefined,
builtin::Access::kReadWrite, ""))
<< gen.error();
@@ -511,7 +512,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(
gen.EmitType(out, s, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.error();
diff --git a/src/tint/writer/hlsl/generator_impl_unary_op_test.cc b/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
index 4bf4329..1ac6851 100644
--- a/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/hlsl/test_helper.h"
namespace tint::writer::hlsl {
@@ -26,7 +27,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "expr");
}
@@ -38,7 +39,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "~(expr)");
}
@@ -51,7 +52,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "expr");
}
@@ -63,7 +64,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "!(expr)");
}
@@ -75,7 +76,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "-(expr)");
}
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index c433207..81b32c0 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -78,6 +78,7 @@
#include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h"
#include "src/tint/utils/scoped_assignment.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/check_supported_extensions.h"
#include "src/tint/writer/float_to_string.h"
#include "src/tint/writer/generate_external_texture_bindings.h"
@@ -89,7 +90,7 @@
return IsAnyOf<ast::BreakStatement>(stmts->Last());
}
-void PrintF32(std::ostream& out, float value) {
+void PrintF32(utils::StringStream& out, float value) {
// Note: Currently inf and nan should not be constructable, but this is implemented for the day
// we support them.
if (std::isinf(value)) {
@@ -101,7 +102,7 @@
}
}
-void PrintF16(std::ostream& out, float value) {
+void PrintF16(utils::StringStream& out, float value) {
// Note: Currently inf and nan should not be constructable, but this is implemented for the day
// we support them.
if (std::isinf(value)) {
@@ -115,7 +116,7 @@
}
}
-void PrintI32(std::ostream& out, int32_t value) {
+void PrintI32(utils::StringStream& out, int32_t value) {
// MSL (and C++) parse `-2147483648` as a `long` because it parses unary minus and `2147483648`
// as separate tokens, and the latter doesn't fit into an (32-bit) `int`.
// WGSL, on the other hand, parses this as an `i32`.
@@ -131,7 +132,7 @@
class ScopedBitCast {
public:
ScopedBitCast(GeneratorImpl* generator,
- std::ostream& stream,
+ utils::StringStream& stream,
const type::Type* curr_type,
const type::Type* target_type)
: s(stream) {
@@ -152,7 +153,7 @@
~ScopedBitCast() { s << ")"; }
private:
- std::ostream& s;
+ utils::StringStream& s;
};
} // namespace
@@ -245,8 +246,9 @@
// ArrayLengthFromUniform must come after SimplifyPointers, as
// it assumes that the form of the array length argument is &var.array.
manager.Add<transform::ArrayLengthFromUniform>();
- manager.Add<transform::ModuleScopeVarToEntryPointParam>();
+ // PackedVec3 must come after ExpandCompoundAssignment.
manager.Add<transform::PackedVec3>();
+ manager.Add<transform::ModuleScopeVarToEntryPointParam>();
data.Add<transform::ArrayLengthFromUniform::Config>(std::move(array_length_from_uniform_cfg));
data.Add<transform::CanonicalizeEntryPointIO::Config>(std::move(entry_point_io_cfg));
auto out = manager.Run(in, data);
@@ -273,6 +275,7 @@
builtin::Extension::kChromiumDisableUniformityAnalysis,
builtin::Extension::kChromiumExperimentalFullPtrParameters,
builtin::Extension::kChromiumExperimentalPushConstant,
+ builtin::Extension::kChromiumInternalRelaxedUniformLayout,
builtin::Extension::kF16,
})) {
return false;
@@ -367,7 +370,8 @@
return true;
}
-bool GeneratorImpl::EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr) {
+bool GeneratorImpl::EmitIndexAccessor(utils::StringStream& out,
+ const ast::IndexAccessorExpression* expr) {
bool paren_lhs =
!expr->object
->IsAnyOf<ast::AccessorExpression, ast::CallExpression, ast::IdentifierExpression>();
@@ -392,7 +396,7 @@
return true;
}
-bool GeneratorImpl::EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr) {
+bool GeneratorImpl::EmitBitcast(utils::StringStream& out, const ast::BitcastExpression* expr) {
out << "as_type<";
if (!EmitType(out, TypeOf(expr)->UnwrapRef(), "")) {
return false;
@@ -425,7 +429,7 @@
return true;
}
-bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* expr) {
+bool GeneratorImpl::EmitBinary(utils::StringStream& out, const ast::BinaryExpression* expr) {
auto emit_op = [&] {
out << " ";
@@ -634,7 +638,7 @@
return true;
}
-bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitCall(utils::StringStream& out, const ast::CallExpression* expr) {
auto* call = program_->Sem().Get<sem::Call>(expr);
auto* target = call->Target();
return Switch(
@@ -648,7 +652,7 @@
});
}
-bool GeneratorImpl::EmitFunctionCall(std::ostream& out,
+bool GeneratorImpl::EmitFunctionCall(utils::StringStream& out,
const sem::Call* call,
const sem::Function* fn) {
out << program_->Symbols().NameFor(fn->Declaration()->name->symbol) << "(";
@@ -669,7 +673,7 @@
return true;
}
-bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
+bool GeneratorImpl::EmitBuiltinCall(utils::StringStream& out,
const sem::Call* call,
const sem::Builtin* builtin) {
auto* expr = call->Declaration();
@@ -783,7 +787,7 @@
return true;
}
-bool GeneratorImpl::EmitTypeConversion(std::ostream& out,
+bool GeneratorImpl::EmitTypeConversion(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConversion* conv) {
if (!EmitType(out, conv->Target(), "")) {
@@ -799,7 +803,7 @@
return true;
}
-bool GeneratorImpl::EmitTypeInitializer(std::ostream& out,
+bool GeneratorImpl::EmitTypeInitializer(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConstructor* ctor) {
auto* type = ctor->ReturnType();
@@ -856,7 +860,7 @@
return true;
}
-bool GeneratorImpl::EmitAtomicCall(std::ostream& out,
+bool GeneratorImpl::EmitAtomicCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
auto call = [&](const std::string& name, bool append_memory_order_relaxed) {
@@ -980,7 +984,7 @@
return false;
}
-bool GeneratorImpl::EmitTextureCall(std::ostream& out,
+bool GeneratorImpl::EmitTextureCall(utils::StringStream& out,
const sem::Call* call,
const sem::Builtin* builtin) {
using Usage = sem::ParameterUsage;
@@ -1229,7 +1233,7 @@
out << "gradientcube(";
break;
default: {
- std::stringstream err;
+ utils::StringStream err;
err << "MSL does not support gradients for " << dim << " textures";
diagnostics_.add_error(diag::System::Writer, err.str());
return false;
@@ -1292,7 +1296,7 @@
return true;
}
-bool GeneratorImpl::EmitDotCall(std::ostream& out,
+bool GeneratorImpl::EmitDotCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
auto* vec_ty = builtin->Parameters()[0]->Type()->As<type::Vector>();
@@ -1337,7 +1341,7 @@
return true;
}
-bool GeneratorImpl::EmitModfCall(std::ostream& out,
+bool GeneratorImpl::EmitModfCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
return CallBuiltinHelper(
@@ -1363,7 +1367,7 @@
});
}
-bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
+bool GeneratorImpl::EmitFrexpCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
return CallBuiltinHelper(
@@ -1389,7 +1393,7 @@
});
}
-bool GeneratorImpl::EmitDegreesCall(std::ostream& out,
+bool GeneratorImpl::EmitDegreesCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
return CallBuiltinHelper(out, expr, builtin,
@@ -1400,7 +1404,7 @@
});
}
-bool GeneratorImpl::EmitRadiansCall(std::ostream& out,
+bool GeneratorImpl::EmitRadiansCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
return CallBuiltinHelper(out, expr, builtin,
@@ -1612,7 +1616,7 @@
return true;
}
-bool GeneratorImpl::EmitZeroValue(std::ostream& out, const type::Type* type) {
+bool GeneratorImpl::EmitZeroValue(utils::StringStream& out, const type::Type* type) {
return Switch(
type,
[&](const type::Bool*) {
@@ -1661,7 +1665,7 @@
});
}
-bool GeneratorImpl::EmitConstant(std::ostream& out, const constant::Value* constant) {
+bool GeneratorImpl::EmitConstant(utils::StringStream& out, const constant::Value* constant) {
return Switch(
constant->Type(), //
[&](const type::Bool*) {
@@ -1788,7 +1792,7 @@
});
}
-bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit) {
+bool GeneratorImpl::EmitLiteral(utils::StringStream& out, const ast::LiteralExpression* lit) {
return Switch(
lit,
[&](const ast::BoolLiteralExpression* l) {
@@ -1824,7 +1828,7 @@
});
}
-bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
+bool GeneratorImpl::EmitExpression(utils::StringStream& out, const ast::Expression* expr) {
if (auto* sem = builder_.Sem().GetVal(expr)) {
if (auto* constant = sem->ConstantValue()) {
return EmitConstant(out, constant);
@@ -1847,7 +1851,7 @@
});
}
-void GeneratorImpl::EmitStage(std::ostream& out, ast::PipelineStage stage) {
+void GeneratorImpl::EmitStage(utils::StringStream& out, ast::PipelineStage stage) {
switch (stage) {
case ast::PipelineStage::kFragment:
out << "fragment";
@@ -2124,7 +2128,8 @@
return true;
}
-bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) {
+bool GeneratorImpl::EmitIdentifier(utils::StringStream& out,
+ const ast::IdentifierExpression* expr) {
out << program_->Symbols().NameFor(expr->identifier->symbol);
return true;
}
@@ -2165,7 +2170,7 @@
}
TextBuffer cond_pre;
- std::stringstream cond_buf;
+ utils::StringStream cond_buf;
if (auto* cond = stmt->condition) {
TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
if (!EmitExpression(cond_buf, cond)) {
@@ -2266,7 +2271,7 @@
bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) {
TextBuffer cond_pre;
- std::stringstream cond_buf;
+ utils::StringStream cond_buf;
{
auto* cond = stmt->condition;
@@ -2352,7 +2357,7 @@
return true;
}
-bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
+bool GeneratorImpl::EmitMemberAccessor(utils::StringStream& out,
const ast::MemberAccessorExpression* expr) {
auto write_lhs = [&] {
bool paren_lhs = !expr->object->IsAnyOf<ast::AccessorExpression, ast::CallExpression,
@@ -2374,25 +2379,20 @@
return Switch(
sem,
[&](const sem::Swizzle* swizzle) {
- // Metal 1.x does not support swizzling of packed vector types.
- // For single element swizzles, we can use the index operator.
- // For multi-element swizzles, we need to cast to a regular vector type
- // first. Note that we do not currently allow assignments to swizzles, so
- // the casting which will convert the l-value to r-value is fine.
+ // Metal did not add support for swizzle syntax with packed vector types until
+ // Metal 2.1, so we need to use the index operator for single-element selection instead.
+ // For multi-component swizzles, the PackedVec3 transform will have inserted casts to
+ // the non-packed types, so we can safely use swizzle syntax here.
if (swizzle->Indices().Length() == 1) {
if (!write_lhs()) {
return false;
}
out << "[" << swizzle->Indices()[0] << "]";
} else {
- if (!EmitType(out, swizzle->Object()->Type()->UnwrapRef(), "")) {
- return false;
- }
- out << "(";
if (!write_lhs()) {
return false;
}
- out << ")." << program_->Symbols().NameFor(expr->member->symbol);
+ out << "." << program_->Symbols().NameFor(expr->member->symbol);
}
return true;
},
@@ -2544,7 +2544,7 @@
return true;
}
-bool GeneratorImpl::EmitType(std::ostream& out,
+bool GeneratorImpl::EmitType(utils::StringStream& out,
const type::Type* type,
const std::string& name,
bool* name_printed /* = nullptr */) {
@@ -2731,6 +2731,9 @@
return true;
},
[&](const type::Vector* vec) {
+ if (vec->Packed()) {
+ out << "packed_";
+ }
if (!EmitType(out, vec->type(), "")) {
return false;
}
@@ -2749,7 +2752,7 @@
});
}
-bool GeneratorImpl::EmitTypeAndName(std::ostream& out,
+bool GeneratorImpl::EmitTypeAndName(utils::StringStream& out,
const type::Type* type,
const std::string& name) {
bool name_printed = false;
@@ -2762,7 +2765,7 @@
return true;
}
-bool GeneratorImpl::EmitAddressSpace(std::ostream& out, builtin::AddressSpace sc) {
+bool GeneratorImpl::EmitAddressSpace(utils::StringStream& out, builtin::AddressSpace sc) {
switch (sc) {
case builtin::AddressSpace::kFunction:
case builtin::AddressSpace::kPrivate:
@@ -2796,7 +2799,7 @@
bool is_host_shareable = str->IsHostShareable();
// Emits a `/* 0xnnnn */` byte offset comment for a struct member.
- auto add_byte_offset_comment = [&](std::ostream& out, uint32_t offset) {
+ auto add_byte_offset_comment = [&](utils::StringStream& out, uint32_t offset) {
std::ios_base::fmtflags saved_flag_state(out.flags());
out << "/* 0x" << std::hex << std::setfill('0') << std::setw(4) << offset << " */ ";
out.flags(saved_flag_state);
@@ -2838,11 +2841,6 @@
add_byte_offset_comment(out, msl_offset);
}
- if (auto* decl = mem->Declaration()) {
- if (ast::HasAttribute<transform::PackedVec3::Attribute>(decl->attributes)) {
- out << "packed_";
- }
- }
if (!EmitType(out, mem->Type(), mem_name)) {
return false;
}
@@ -2924,7 +2922,6 @@
[&](const ast::StructMemberOffsetAttribute*) { return true; },
[&](const ast::StructMemberAlignAttribute*) { return true; },
[&](const ast::StructMemberSizeAttribute*) { return true; },
- [&](const transform::PackedVec3::Attribute*) { return true; },
[&](Default) {
TINT_ICE(Writer, diagnostics_)
<< "unhandled struct member attribute: " << attr->Name();
@@ -2961,7 +2958,7 @@
return true;
}
-bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr) {
+bool GeneratorImpl::EmitUnaryOp(utils::StringStream& out, const ast::UnaryOpExpression* expr) {
// Handle `-e` when `e` is signed, so that we ensure that if `e` is the
// largest negative value, it returns `e`.
auto* expr_type = TypeOf(expr->expr)->UnwrapRef();
@@ -3240,7 +3237,7 @@
}
template <typename F>
-bool GeneratorImpl::CallBuiltinHelper(std::ostream& out,
+bool GeneratorImpl::CallBuiltinHelper(utils::StringStream& out,
const ast::CallExpression* call,
const sem::Builtin* builtin,
F&& build) {
diff --git a/src/tint/writer/msl/generator_impl.h b/src/tint/writer/msl/generator_impl.h
index 9c7c0d4..5699242 100644
--- a/src/tint/writer/msl/generator_impl.h
+++ b/src/tint/writer/msl/generator_impl.h
@@ -40,6 +40,7 @@
#include "src/tint/program.h"
#include "src/tint/scope_stack.h"
#include "src/tint/sem/struct.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/array_length_from_uniform_options.h"
#include "src/tint/writer/msl/generator.h"
#include "src/tint/writer/text_generator.h"
@@ -106,7 +107,7 @@
/// @param out the output of the expression stream
/// @param expr the expression to emit
/// @returns true if the index accessor was emitted
- bool EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr);
+ bool EmitIndexAccessor(utils::StringStream& out, const ast::IndexAccessorExpression* expr);
/// Handles an assignment statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
@@ -115,12 +116,12 @@
/// @param out the output of the expression stream
/// @param expr the binary expression
/// @returns true if the expression was emitted, false otherwise
- bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
+ bool EmitBinary(utils::StringStream& out, const ast::BinaryExpression* expr);
/// Handles generating a bitcast expression
/// @param out the output of the expression stream
/// @param expr the bitcast expression
/// @returns true if the bitcast was emitted
- bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
+ bool EmitBitcast(utils::StringStream& out, const ast::BitcastExpression* expr);
/// Handles a block statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
@@ -137,19 +138,21 @@
/// @param out the output of the expression stream
/// @param expr the call expression
/// @returns true if the call expression is emitted
- bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
+ bool EmitCall(utils::StringStream& out, const ast::CallExpression* expr);
/// Handles generating a builtin call expression
/// @param out the output of the expression stream
/// @param call the call expression
/// @param builtin the builtin being called
/// @returns true if the call expression is emitted
- bool EmitBuiltinCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+ bool EmitBuiltinCall(utils::StringStream& out,
+ const sem::Call* call,
+ const sem::Builtin* builtin);
/// Handles generating a value conversion expression
/// @param out the output of the expression stream
/// @param call the call expression
/// @param conv the value conversion
/// @returns true if the expression is emitted
- bool EmitTypeConversion(std::ostream& out,
+ bool EmitTypeConversion(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConversion* conv);
/// Handles generating a value constructor
@@ -157,7 +160,7 @@
/// @param call the call expression
/// @param ctor the value constructor
/// @returns true if the initializer is emitted
- bool EmitTypeInitializer(std::ostream& out,
+ bool EmitTypeInitializer(utils::StringStream& out,
const sem::Call* call,
const sem::ValueConstructor* ctor);
/// Handles generating a function call
@@ -165,14 +168,16 @@
/// @param call the call expression
/// @param func the target function
/// @returns true if the call is emitted
- bool EmitFunctionCall(std::ostream& out, const sem::Call* call, const sem::Function* func);
+ bool EmitFunctionCall(utils::StringStream& out,
+ const sem::Call* call,
+ const sem::Function* func);
/// Handles generating a call to an atomic function (`atomicAdd`,
/// `atomicMax`, etc)
/// @param out the output of the expression stream
/// @param expr the call expression
/// @param builtin the semantic information for the atomic builtin
/// @returns true if the call expression is emitted
- bool EmitAtomicCall(std::ostream& out,
+ bool EmitAtomicCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to a texture function (`textureSample`,
@@ -181,13 +186,15 @@
/// @param call the call expression
/// @param builtin the semantic information for the texture builtin
/// @returns true if the call expression is emitted
- bool EmitTextureCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+ bool EmitTextureCall(utils::StringStream& out,
+ const sem::Call* call,
+ const sem::Builtin* builtin);
/// Handles generating a call to the `dot()` builtin
/// @param out the output of the expression stream
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitDotCall(std::ostream& out,
+ bool EmitDotCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `modf()` builtin
@@ -195,7 +202,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitModfCall(std::ostream& out,
+ bool EmitModfCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `frexp()` builtin
@@ -203,7 +210,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitFrexpCall(std::ostream& out,
+ bool EmitFrexpCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `degrees()` builtin
@@ -211,7 +218,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitDegreesCall(std::ostream& out,
+ bool EmitDegreesCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `radians()` builtin
@@ -219,7 +226,7 @@
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
- bool EmitRadiansCall(std::ostream& out,
+ bool EmitRadiansCall(utils::StringStream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles a case statement
@@ -242,7 +249,7 @@
/// @param out the output of the expression stream
/// @param expr the expression
/// @returns true if the expression was emitted
- bool EmitExpression(std::ostream& out, const ast::Expression* expr);
+ bool EmitExpression(utils::StringStream& out, const ast::Expression* expr);
/// Handles generating a function
/// @param func the function to generate
/// @returns true if the function was emitted
@@ -251,7 +258,7 @@
/// @param out the output of the expression stream
/// @param expr the identifier expression
/// @returns true if the identifier was emitted
- bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
+ bool EmitIdentifier(utils::StringStream& out, const ast::IdentifierExpression* expr);
/// Handles an if statement
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted
@@ -260,12 +267,12 @@
/// @param out the output stream
/// @param constant the constant value to emit
/// @returns true if the constant value was successfully emitted
- bool EmitConstant(std::ostream& out, const constant::Value* constant);
+ bool EmitConstant(utils::StringStream& out, const constant::Value* constant);
/// Handles a literal
/// @param out the output of the expression stream
/// @param lit the literal to emit
/// @returns true if the literal was successfully emitted
- bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit);
+ bool EmitLiteral(utils::StringStream& out, const ast::LiteralExpression* lit);
/// Handles a loop statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
@@ -282,7 +289,7 @@
/// @param out the output of the expression stream
/// @param expr the member accessor expression
/// @returns true if the member accessor was emitted
- bool EmitMemberAccessor(std::ostream& out, const ast::MemberAccessorExpression* expr);
+ bool EmitMemberAccessor(utils::StringStream& out, const ast::MemberAccessorExpression* expr);
/// Handles return statements
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted
@@ -290,7 +297,7 @@
/// Handles emitting a pipeline stage name
/// @param out the output of the expression stream
/// @param stage the stage to emit
- void EmitStage(std::ostream& out, ast::PipelineStage stage);
+ void EmitStage(utils::StringStream& out, ast::PipelineStage stage);
/// Handles statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
@@ -313,7 +320,7 @@
/// @param name the name of the variable, only used for array emission
/// @param name_printed (optional) if not nullptr and an array was printed
/// @returns true if the type is emitted
- bool EmitType(std::ostream& out,
+ bool EmitType(utils::StringStream& out,
const type::Type* type,
const std::string& name,
bool* name_printed = nullptr);
@@ -322,12 +329,12 @@
/// @param type the type to generate
/// @param name the name to emit
/// @returns true if the type is emitted
- bool EmitTypeAndName(std::ostream& out, const type::Type* type, const std::string& name);
+ bool EmitTypeAndName(utils::StringStream& out, const type::Type* type, const std::string& name);
/// Handles generating a address space
/// @param out the output of the type stream
/// @param sc the address space to generate
/// @returns true if the address space is emitted
- bool EmitAddressSpace(std::ostream& out, builtin::AddressSpace sc);
+ bool EmitAddressSpace(utils::StringStream& out, builtin::AddressSpace sc);
/// Handles generating a struct declaration. If the structure has already been emitted, then
/// this function will simply return `true` without emitting anything.
/// @param buffer the text buffer that the type declaration will be written to
@@ -338,7 +345,7 @@
/// @param out the output of the expression stream
/// @param expr the expression to emit
/// @returns true if the expression was emitted
- bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
+ bool EmitUnaryOp(utils::StringStream& out, const ast::UnaryOpExpression* expr);
/// Handles generating a 'var' declaration
/// @param var the variable to generate
/// @returns true if the variable was emitted
@@ -351,7 +358,7 @@
/// @param out the output of the expression stream
/// @param type the type to emit the value for
/// @returns true if the zero value was successfully emitted.
- bool EmitZeroValue(std::ostream& out, const type::Type* type);
+ bool EmitZeroValue(utils::StringStream& out, const type::Type* type);
/// Handles generating a builtin name
/// @param builtin the semantic info for the builtin
@@ -391,7 +398,7 @@
/// `params` is the name of all the generated function parameters
/// @returns true if the call expression is emitted
template <typename F>
- bool CallBuiltinHelper(std::ostream& out,
+ bool CallBuiltinHelper(utils::StringStream& out,
const ast::CallExpression* call,
const sem::Builtin* builtin,
F&& build);
diff --git a/src/tint/writer/msl/generator_impl_array_accessor_test.cc b/src/tint/writer/msl/generator_impl_array_accessor_test.cc
index 47145d1..f721416 100644
--- a/src/tint/writer/msl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/msl/generator_impl_array_accessor_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -28,7 +29,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "ary[5]");
}
@@ -42,7 +43,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(*(p))[5]");
}
diff --git a/src/tint/writer/msl/generator_impl_binary_test.cc b/src/tint/writer/msl/generator_impl_binary_test.cc
index 7519b61..8b7e4b5 100644
--- a/src/tint/writer/msl/generator_impl_binary_test.cc
+++ b/src/tint/writer/msl/generator_impl_binary_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
namespace tint::writer::msl {
@@ -44,7 +45,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -88,7 +89,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -122,7 +123,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr2)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -149,7 +150,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "fmod(left, right)");
}
@@ -164,7 +165,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "fmod(left, right)");
}
@@ -177,7 +178,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "fmod(left, right)");
}
@@ -192,7 +193,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "fmod(left, right)");
}
@@ -205,7 +206,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "bool(left & right)");
}
@@ -218,7 +219,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "bool(left | right)");
}
diff --git a/src/tint/writer/msl/generator_impl_bitcast_test.cc b/src/tint/writer/msl/generator_impl_bitcast_test.cc
index 31aa79a..a4aa870 100644
--- a/src/tint/writer/msl/generator_impl_bitcast_test.cc
+++ b/src/tint/writer/msl/generator_impl_bitcast_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -28,7 +29,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
EXPECT_EQ(out.str(), "as_type<float>(a)");
}
diff --git a/src/tint/writer/msl/generator_impl_builtin_test.cc b/src/tint/writer/msl/generator_impl_builtin_test.cc
index 84fb7d5..0c6ba28 100644
--- a/src/tint/writer/msl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/msl/generator_impl_builtin_test.cc
@@ -14,6 +14,7 @@
#include "src/tint/ast/call_statement.h"
#include "src/tint/sem/call.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -61,8 +62,8 @@
CallParamType type,
ProgramBuilder* builder) {
std::string name;
- std::ostringstream str(name);
- str << builtin;
+ utils::StringStream str;
+ str << name << builtin;
switch (builtin) {
case BuiltinType::kAcos:
case BuiltinType::kAsin:
@@ -378,7 +379,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "dot(param1, param2)");
}
@@ -389,7 +390,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "threadgroup_barrier(mem_flags::mem_device)");
}
@@ -400,7 +401,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "threadgroup_barrier(mem_flags::mem_threadgroup)");
}
@@ -850,7 +851,7 @@
using namespace metal;
float tint_degrees(float param_0) {
- return param_0 * 57.295779513082322865;
+ return param_0 * 57.295779513082323;
}
kernel void test_function() {
@@ -875,7 +876,7 @@
using namespace metal;
float3 tint_degrees(float3 param_0) {
- return param_0 * 57.295779513082322865;
+ return param_0 * 57.295779513082323;
}
kernel void test_function() {
@@ -902,7 +903,7 @@
using namespace metal;
half tint_degrees(half param_0) {
- return param_0 * 57.295779513082322865;
+ return param_0 * 57.295779513082323;
}
kernel void test_function() {
@@ -929,7 +930,7 @@
using namespace metal;
half3 tint_degrees(half3 param_0) {
- return param_0 * 57.295779513082322865;
+ return param_0 * 57.295779513082323;
}
kernel void test_function() {
@@ -954,7 +955,7 @@
using namespace metal;
float tint_radians(float param_0) {
- return param_0 * 0.017453292519943295474;
+ return param_0 * 0.017453292519943295;
}
kernel void test_function() {
@@ -979,7 +980,7 @@
using namespace metal;
float3 tint_radians(float3 param_0) {
- return param_0 * 0.017453292519943295474;
+ return param_0 * 0.017453292519943295;
}
kernel void test_function() {
@@ -1006,7 +1007,7 @@
using namespace metal;
half tint_radians(half param_0) {
- return param_0 * 0.017453292519943295474;
+ return param_0 * 0.017453292519943295;
}
kernel void test_function() {
@@ -1033,7 +1034,7 @@
using namespace metal;
half3 tint_radians(half3 param_0) {
- return param_0 * 0.017453292519943295474;
+ return param_0 * 0.017453292519943295;
}
kernel void test_function() {
@@ -1052,7 +1053,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "as_type<uint>(half2(p1))");
}
@@ -1064,7 +1065,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "float2(as_type<half2>(p1))");
}
diff --git a/src/tint/writer/msl/generator_impl_builtin_texture_test.cc b/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
index f3d65b1..730fe99 100644
--- a/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
+++ b/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
@@ -14,6 +14,7 @@
#include "src/tint/ast/builtin_texture_helper_test.h"
#include "src/tint/ast/call_statement.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
namespace tint::writer::msl {
@@ -285,7 +286,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
auto expected = expected_texture_overload(param.overload);
diff --git a/src/tint/writer/msl/generator_impl_call_test.cc b/src/tint/writer/msl/generator_impl_call_test.cc
index 26da4e4..95fbe91 100644
--- a/src/tint/writer/msl/generator_impl_call_test.cc
+++ b/src/tint/writer/msl/generator_impl_call_test.cc
@@ -13,6 +13,7 @@
// limitations under the License.
#include "src/tint/ast/call_statement.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -30,7 +31,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "my_func()");
}
@@ -53,7 +54,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "my_func(param1, param2)");
}
diff --git a/src/tint/writer/msl/generator_impl_cast_test.cc b/src/tint/writer/msl/generator_impl_cast_test.cc
index ec1fe7c..51fc0ab 100644
--- a/src/tint/writer/msl/generator_impl_cast_test.cc
+++ b/src/tint/writer/msl/generator_impl_cast_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -27,7 +28,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
EXPECT_EQ(out.str(), "1.0f");
}
@@ -38,7 +39,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
EXPECT_EQ(out.str(), "float3(1.0f, 2.0f, 3.0f)");
}
@@ -49,7 +50,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
EXPECT_EQ(out.str(), "2147483648u");
}
diff --git a/src/tint/writer/msl/generator_impl_identifier_test.cc b/src/tint/writer/msl/generator_impl_identifier_test.cc
index a625776..a1e6260 100644
--- a/src/tint/writer/msl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/msl/generator_impl_identifier_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
namespace tint::writer::msl {
@@ -27,7 +28,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
EXPECT_EQ(out.str(), "foo");
}
diff --git a/src/tint/writer/msl/generator_impl_import_test.cc b/src/tint/writer/msl/generator_impl_import_test.cc
index d00acd5..841e7dc 100644
--- a/src/tint/writer/msl/generator_impl_import_test.cc
+++ b/src/tint/writer/msl/generator_impl_import_test.cc
@@ -13,6 +13,7 @@
// limitations under the License.
#include "src/tint/sem/call.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -81,7 +82,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), R"(abs(1))");
}
@@ -92,7 +93,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), R"(fabs(2.0f))");
}
@@ -106,7 +107,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1.0f, 2.0f)");
}
@@ -124,7 +125,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), R"(fabs(2.0f - 3.0f))");
}
@@ -138,7 +139,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.msl_name) +
R"((float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f)))");
@@ -163,7 +164,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1, 2)");
}
@@ -180,7 +181,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1.0f, 2.0f, 3.0f)");
}
@@ -201,7 +202,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(
out.str(),
@@ -224,7 +225,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1, 2, 3)");
}
@@ -242,7 +243,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), std::string("determinant(var)"));
}
@@ -255,7 +256,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "float(half(v))");
}
@@ -268,7 +269,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "float3(half3(v))");
}
diff --git a/src/tint/writer/msl/generator_impl_member_accessor_test.cc b/src/tint/writer/msl/generator_impl_member_accessor_test.cc
index 1e1136e..38a222c 100644
--- a/src/tint/writer/msl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/msl/generator_impl_member_accessor_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
namespace tint::writer::msl {
@@ -27,7 +28,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "str.mem");
}
@@ -39,9 +40,9 @@
WrapInFunction(expr);
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
- EXPECT_EQ(out.str(), "float4(my_vec).xyz");
+ EXPECT_EQ(out.str(), "my_vec.xyz");
}
TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor_Swizzle_gbr) {
@@ -51,9 +52,9 @@
WrapInFunction(expr);
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
- EXPECT_EQ(out.str(), "float4(my_vec).gbr");
+ EXPECT_EQ(out.str(), "my_vec.gbr");
}
} // namespace
diff --git a/src/tint/writer/msl/generator_impl_type_test.cc b/src/tint/writer/msl/generator_impl_type_test.cc
index 9775cf9..e1e18a3 100644
--- a/src/tint/writer/msl/generator_impl_type_test.cc
+++ b/src/tint/writer/msl/generator_impl_type_test.cc
@@ -23,6 +23,7 @@
#include "src/tint/type/sampler.h"
#include "src/tint/type/storage_texture.h"
#include "src/tint/type/texture_dimension.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
using ::testing::HasSubstr;
@@ -32,7 +33,7 @@
namespace tint::writer::msl {
namespace {
-void FormatMSLField(std::stringstream& out,
+void FormatMSLField(utils::StringStream& out,
const char* addr,
const char* type,
size_t array_count,
@@ -94,7 +95,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(type), "ary")) << gen.error();
EXPECT_EQ(out.str(), "tint_array<bool, 4>");
}
@@ -106,7 +107,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(type), "ary")) << gen.error();
EXPECT_EQ(out.str(), "tint_array<tint_array<bool, 4>, 5>");
}
@@ -119,7 +120,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(type), "ary")) << gen.error();
EXPECT_EQ(out.str(), "tint_array<tint_array<tint_array<bool, 4>, 5>, 6>");
}
@@ -130,7 +131,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(type), "")) << gen.error();
EXPECT_EQ(out.str(), "tint_array<bool, 4>");
}
@@ -141,7 +142,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(type), "ary")) << gen.error();
EXPECT_EQ(out.str(), "tint_array<bool, 1>");
}
@@ -151,7 +152,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, bool_, "")) << gen.error();
EXPECT_EQ(out.str(), "bool");
}
@@ -161,7 +162,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, f32, "")) << gen.error();
EXPECT_EQ(out.str(), "float");
}
@@ -171,7 +172,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, f16, "")) << gen.error();
EXPECT_EQ(out.str(), "half");
}
@@ -181,7 +182,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, i32, "")) << gen.error();
EXPECT_EQ(out.str(), "int");
}
@@ -193,7 +194,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, mat2x3, "")) << gen.error();
EXPECT_EQ(out.str(), "float2x3");
}
@@ -205,7 +206,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, mat2x3, "")) << gen.error();
EXPECT_EQ(out.str(), "half2x3");
}
@@ -217,7 +218,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, p, "")) << gen.error();
EXPECT_EQ(out.str(), "threadgroup float* ");
}
@@ -230,7 +231,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(s), "")) << gen.error();
EXPECT_EQ(out.str(), "S");
}
@@ -338,7 +339,7 @@
FIELD(0x0304, int8_t, 124, tint_pad_12)
// Check that the generated string is as expected.
- std::stringstream expect;
+ utils::StringStream expect;
expect << "struct S {\n";
#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) \
FormatMSLField(expect, #ADDR, #TYPE, ARRAY_COUNT, #NAME);
@@ -415,7 +416,7 @@
FIELD(0x080c, int8_t, 500, tint_pad_1)
// Check that the generated string is as expected.
- std::stringstream expect;
+ utils::StringStream expect;
expect << "struct S {\n";
#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) \
FormatMSLField(expect, #ADDR, #TYPE, ARRAY_COUNT, #NAME);
@@ -508,7 +509,7 @@
FIELD(0x1208, int8_t, 504, tint_pad_1)
// Check that the generated string is as expected.
- std::stringstream expect;
+ utils::StringStream expect;
expect << "struct S {\n";
#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) \
FormatMSLField(expect, #ADDR, #TYPE, ARRAY_COUNT, #NAME);
@@ -589,7 +590,7 @@
FIELD(0x0054, int8_t, 12, tint_pad_1)
// Check that the generated string is as expected.
- std::stringstream expect;
+ utils::StringStream expect;
expect << "struct S {\n";
#define FIELD(ADDR, TYPE, ARRAY_COUNT, NAME) \
FormatMSLField(expect, #ADDR, #TYPE, ARRAY_COUNT, #NAME);
@@ -711,7 +712,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, u32, "")) << gen.error();
EXPECT_EQ(out.str(), "uint");
}
@@ -722,7 +723,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, vec3, "")) << gen.error();
EXPECT_EQ(out.str(), "float3");
}
@@ -732,7 +733,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, void_, "")) << gen.error();
EXPECT_EQ(out.str(), "void");
}
@@ -742,7 +743,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, sampler, "")) << gen.error();
EXPECT_EQ(out.str(), "sampler");
}
@@ -752,7 +753,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, sampler, "")) << gen.error();
EXPECT_EQ(out.str(), "sampler");
}
@@ -773,7 +774,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, &s, "")) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -794,7 +795,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, &s, "")) << gen.error();
EXPECT_EQ(out.str(), "depth2d_ms<float, access::read>");
}
@@ -816,7 +817,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, s, "")) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
@@ -838,7 +839,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, ms, "")) << gen.error();
EXPECT_EQ(out.str(), "texture2d_ms<uint, access::read>");
}
@@ -860,7 +861,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(type), "")) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
diff --git a/src/tint/writer/msl/generator_impl_unary_op_test.cc b/src/tint/writer/msl/generator_impl_unary_op_test.cc
index 95801a8..d92a9cb 100644
--- a/src/tint/writer/msl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/msl/generator_impl_unary_op_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/msl/test_helper.h"
namespace tint::writer::msl {
@@ -26,7 +27,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "&(expr)");
}
@@ -38,7 +39,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "~(expr)");
}
@@ -51,7 +52,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "*(expr)");
}
@@ -63,7 +64,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "!(expr)");
}
@@ -75,7 +76,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "tint_unary_minus(expr)");
}
@@ -86,7 +87,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "(-2147483647 - 1)");
}
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index ad0d746..40f98d8 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -49,6 +49,7 @@
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/append_vector.h"
#include "src/tint/writer/check_supported_extensions.h"
@@ -4138,7 +4139,7 @@
bool Builder::push_function_inst(spv::Op op, const OperandList& operands) {
if (functions_.empty()) {
- std::ostringstream ss;
+ utils::StringStream ss;
ss << "Internal error: trying to add SPIR-V instruction " << int(op)
<< " outside a function";
error_ = ss.str();
diff --git a/src/tint/writer/text_generator.cc b/src/tint/writer/text_generator.cc
index 6d29844..20c5fe7 100644
--- a/src/tint/writer/text_generator.cc
+++ b/src/tint/writer/text_generator.cc
@@ -114,7 +114,7 @@
}
std::string TextGenerator::TextBuffer::String(uint32_t indent /* = 0 */) const {
- std::stringstream ss;
+ utils::StringStream ss;
for (auto& line : lines) {
if (!line.content.empty()) {
for (uint32_t i = 0; i < indent + line.indent; i++) {
@@ -127,9 +127,10 @@
return ss.str();
}
-TextGenerator::ScopedParen::ScopedParen(std::ostream& stream) : s(stream) {
+TextGenerator::ScopedParen::ScopedParen(utils::StringStream& stream) : s(stream) {
s << "(";
}
+
TextGenerator::ScopedParen::~ScopedParen() {
s << ")";
}
diff --git a/src/tint/writer/text_generator.h b/src/tint/writer/text_generator.h
index 1c22522..74e3ecb 100644
--- a/src/tint/writer/text_generator.h
+++ b/src/tint/writer/text_generator.h
@@ -23,6 +23,7 @@
#include "src/tint/diagnostic/diagnostic.h"
#include "src/tint/program_builder.h"
+#include "src/tint/utils/string_stream.h"
namespace tint::writer {
@@ -139,13 +140,13 @@
/// Destructor
~LineWriter();
- /// @returns the ostringstream
- operator std::ostream&() { return os; }
+ /// @returns the utils::StringStream
+ operator utils::StringStream&() { return os; }
/// @param rhs the value to write to the line
- /// @returns the ostream so calls can be chained
+ /// @returns the utils::StringStream so calls can be chained
template <typename T>
- std::ostream& operator<<(T&& rhs) {
+ utils::StringStream& operator<<(T&& rhs) {
return os << std::forward<T>(rhs);
}
@@ -153,15 +154,15 @@
LineWriter(const LineWriter&) = delete;
LineWriter& operator=(const LineWriter&) = delete;
- std::ostringstream os;
+ utils::StringStream os;
TextBuffer* buffer;
};
/// Helper for writing a '(' on construction and a ')' destruction.
struct ScopedParen {
/// Constructor
- /// @param stream the std::ostream that will be written to
- explicit ScopedParen(std::ostream& stream);
+ /// @param stream the utils::StringStream that will be written to
+ explicit ScopedParen(utils::StringStream& stream);
/// Destructor
~ScopedParen();
@@ -169,7 +170,7 @@
ScopedParen(ScopedParen&& rhs) = delete;
ScopedParen(const ScopedParen&) = delete;
ScopedParen& operator=(const ScopedParen&) = delete;
- std::ostream& s;
+ utils::StringStream& s;
};
/// Helper for incrementing indentation on construction and decrementing
diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc
index 4363b62..c052075 100644
--- a/src/tint/writer/wgsl/generator_impl.cc
+++ b/src/tint/writer/wgsl/generator_impl.cc
@@ -89,7 +89,7 @@
return true;
}
-bool GeneratorImpl::EmitDiagnosticControl(std::ostream& out,
+bool GeneratorImpl::EmitDiagnosticControl(utils::StringStream& out,
const ast::DiagnosticControl& diagnostic) {
out << "diagnostic(" << diagnostic.severity << ", "
<< program_->Symbols().NameFor(diagnostic.rule_name->symbol) << ")";
@@ -124,7 +124,7 @@
});
}
-bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
+bool GeneratorImpl::EmitExpression(utils::StringStream& out, const ast::Expression* expr) {
return Switch(
expr,
[&](const ast::IndexAccessorExpression* a) { //
@@ -161,7 +161,8 @@
});
}
-bool GeneratorImpl::EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr) {
+bool GeneratorImpl::EmitIndexAccessor(utils::StringStream& out,
+ const ast::IndexAccessorExpression* expr) {
bool paren_lhs =
!expr->object
->IsAnyOf<ast::AccessorExpression, ast::CallExpression, ast::IdentifierExpression>();
@@ -184,7 +185,7 @@
return true;
}
-bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
+bool GeneratorImpl::EmitMemberAccessor(utils::StringStream& out,
const ast::MemberAccessorExpression* expr) {
bool paren_lhs =
!expr->object
@@ -203,7 +204,7 @@
return true;
}
-bool GeneratorImpl::EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr) {
+bool GeneratorImpl::EmitBitcast(utils::StringStream& out, const ast::BitcastExpression* expr) {
out << "bitcast<";
if (!EmitExpression(out, expr->type)) {
return false;
@@ -218,7 +219,7 @@
return true;
}
-bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitCall(utils::StringStream& out, const ast::CallExpression* expr) {
if (!EmitExpression(out, expr->target)) {
return false;
}
@@ -242,7 +243,7 @@
return true;
}
-bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit) {
+bool GeneratorImpl::EmitLiteral(utils::StringStream& out, const ast::LiteralExpression* lit) {
return Switch(
lit,
[&](const ast::BoolLiteralExpression* l) { //
@@ -271,11 +272,12 @@
});
}
-bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) {
+bool GeneratorImpl::EmitIdentifier(utils::StringStream& out,
+ const ast::IdentifierExpression* expr) {
return EmitIdentifier(out, expr->identifier);
}
-bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::Identifier* ident) {
+bool GeneratorImpl::EmitIdentifier(utils::StringStream& out, const ast::Identifier* ident) {
if (auto* tmpl_ident = ident->As<ast::TemplatedIdentifier>()) {
if (!tmpl_ident->attributes.IsEmpty()) {
EmitAttributes(out, tmpl_ident->attributes);
@@ -363,7 +365,7 @@
return true;
}
-bool GeneratorImpl::EmitImageFormat(std::ostream& out, const builtin::TexelFormat fmt) {
+bool GeneratorImpl::EmitImageFormat(utils::StringStream& out, const builtin::TexelFormat fmt) {
switch (fmt) {
case builtin::TexelFormat::kUndefined:
diagnostics_.add_error(diag::System::Writer, "unknown image format");
@@ -441,7 +443,7 @@
return true;
}
-bool GeneratorImpl::EmitVariable(std::ostream& out, const ast::Variable* v) {
+bool GeneratorImpl::EmitVariable(utils::StringStream& out, const ast::Variable* v) {
if (!v->attributes.IsEmpty()) {
if (!EmitAttributes(out, v->attributes)) {
return false;
@@ -508,7 +510,7 @@
return true;
}
-bool GeneratorImpl::EmitAttributes(std::ostream& out,
+bool GeneratorImpl::EmitAttributes(utils::StringStream& out,
utils::VectorRef<const ast::Attribute*> attrs) {
bool first = true;
for (auto* attr : attrs) {
@@ -650,7 +652,7 @@
return true;
}
-bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* expr) {
+bool GeneratorImpl::EmitBinary(utils::StringStream& out, const ast::BinaryExpression* expr) {
out << "(";
if (!EmitExpression(out, expr->lhs)) {
@@ -670,7 +672,7 @@
return true;
}
-bool GeneratorImpl::EmitBinaryOp(std::ostream& out, const ast::BinaryOp op) {
+bool GeneratorImpl::EmitBinaryOp(utils::StringStream& out, const ast::BinaryOp op) {
switch (op) {
case ast::BinaryOp::kAnd:
out << "&";
@@ -733,7 +735,7 @@
return true;
}
-bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr) {
+bool GeneratorImpl::EmitUnaryOp(utils::StringStream& out, const ast::UnaryOpExpression* expr) {
switch (expr->op) {
case ast::UnaryOp::kAddressOf:
out << "&";
@@ -777,7 +779,7 @@
return true;
}
-bool GeneratorImpl::EmitBlockHeader(std::ostream& out, const ast::BlockStatement* stmt) {
+bool GeneratorImpl::EmitBlockHeader(utils::StringStream& out, const ast::BlockStatement* stmt) {
if (!stmt->attributes.IsEmpty()) {
if (!EmitAttributes(out, stmt->attributes)) {
return false;
diff --git a/src/tint/writer/wgsl/generator_impl.h b/src/tint/writer/wgsl/generator_impl.h
index abfee1d..c72d95e 100644
--- a/src/tint/writer/wgsl/generator_impl.h
+++ b/src/tint/writer/wgsl/generator_impl.h
@@ -35,6 +35,7 @@
#include "src/tint/ast/unary_op_expression.h"
#include "src/tint/program.h"
#include "src/tint/sem/struct.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/text_generator.h"
namespace tint::writer::wgsl {
@@ -55,7 +56,7 @@
/// @param out the output stream
/// @param diagnostic the diagnostic control node
/// @returns true if the diagnostic control was emitted
- bool EmitDiagnosticControl(std::ostream& out, const ast::DiagnosticControl& diagnostic);
+ bool EmitDiagnosticControl(utils::StringStream& out, const ast::DiagnosticControl& diagnostic);
/// Handles generating an enable directive
/// @param enable the enable node
/// @returns true if the enable directive was emitted
@@ -68,7 +69,7 @@
/// @param out the output stream
/// @param expr the expression to emit
/// @returns true if the index accessor was emitted
- bool EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr);
+ bool EmitIndexAccessor(utils::StringStream& out, const ast::IndexAccessorExpression* expr);
/// Handles an assignment statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
@@ -77,17 +78,17 @@
/// @param out the output stream
/// @param expr the binary expression
/// @returns true if the expression was emitted, false otherwise
- bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
+ bool EmitBinary(utils::StringStream& out, const ast::BinaryExpression* expr);
/// Handles generating a binary operator
/// @param out the output stream
/// @param op the binary operator
/// @returns true if the operator was emitted, false otherwise
- bool EmitBinaryOp(std::ostream& out, const ast::BinaryOp op);
+ bool EmitBinaryOp(utils::StringStream& out, const ast::BinaryOp op);
/// Handles generating a bitcast expression
/// @param out the output stream
/// @param expr the bitcast expression
/// @returns true if the bitcast was emitted
- bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
+ bool EmitBitcast(utils::StringStream& out, const ast::BitcastExpression* expr);
/// Handles a block statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
@@ -96,7 +97,7 @@
/// @param out the output stream to write the header to
/// @param stmt the block statement to emit the header for
/// @returns true if the statement was emitted successfully
- bool EmitBlockHeader(std::ostream& out, const ast::BlockStatement* stmt);
+ bool EmitBlockHeader(utils::StringStream& out, const ast::BlockStatement* stmt);
/// Handles a break statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
@@ -109,7 +110,7 @@
/// @param out the output stream
/// @param expr the call expression
/// @returns true if the call expression is emitted
- bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
+ bool EmitCall(utils::StringStream& out, const ast::CallExpression* expr);
/// Handles a case statement
/// @param stmt the statement
/// @returns true if the statment was emitted successfully
@@ -122,7 +123,7 @@
/// @param out the output stream
/// @param expr the literal expression expression
/// @returns true if the literal expression is emitted
- bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* expr);
+ bool EmitLiteral(utils::StringStream& out, const ast::LiteralExpression* expr);
/// Handles a continue statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
@@ -131,7 +132,7 @@
/// @param out the output stream
/// @param expr the expression
/// @returns true if the expression was emitted
- bool EmitExpression(std::ostream& out, const ast::Expression* expr);
+ bool EmitExpression(utils::StringStream& out, const ast::Expression* expr);
/// Handles generating a function
/// @param func the function to generate
/// @returns true if the function was emitted
@@ -140,12 +141,12 @@
/// @param out the output stream
/// @param expr the identifier expression
/// @returns true if the identifier was emitted
- bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
+ bool EmitIdentifier(utils::StringStream& out, const ast::IdentifierExpression* expr);
/// Handles generating an identifier
/// @param out the output of the expression stream
/// @param ident the identifier
/// @returns true if the identifier was emitted
- bool EmitIdentifier(std::ostream& out, const ast::Identifier* ident);
+ bool EmitIdentifier(utils::StringStream& out, const ast::Identifier* ident);
/// Handles an if statement
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted
@@ -174,7 +175,7 @@
/// @param out the output stream
/// @param expr the member accessor expression
/// @returns true if the member accessor was emitted
- bool EmitMemberAccessor(std::ostream& out, const ast::MemberAccessorExpression* expr);
+ bool EmitMemberAccessor(utils::StringStream& out, const ast::MemberAccessorExpression* expr);
/// Handles return statements
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted
@@ -207,22 +208,22 @@
/// @param out the output stream
/// @param fmt the format to generate
/// @returns true if the format is emitted
- bool EmitImageFormat(std::ostream& out, const builtin::TexelFormat fmt);
+ bool EmitImageFormat(utils::StringStream& out, const builtin::TexelFormat fmt);
/// Handles a unary op expression
/// @param out the output stream
/// @param expr the expression to emit
/// @returns true if the expression was emitted
- bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
+ bool EmitUnaryOp(utils::StringStream& out, const ast::UnaryOpExpression* expr);
/// Handles generating a variable
/// @param out the output stream
/// @param var the variable to generate
/// @returns true if the variable was emitted
- bool EmitVariable(std::ostream& out, const ast::Variable* var);
+ bool EmitVariable(utils::StringStream& out, const ast::Variable* var);
/// Handles generating a attribute list
/// @param out the output stream
/// @param attrs the attribute list
/// @returns true if the attributes were emitted
- bool EmitAttributes(std::ostream& out, utils::VectorRef<const ast::Attribute*> attrs);
+ bool EmitAttributes(utils::StringStream& out, utils::VectorRef<const ast::Attribute*> attrs);
};
} // namespace tint::writer::wgsl
diff --git a/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc b/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
index 31e7e6b..0cf7cf4 100644
--- a/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -28,7 +29,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "ary[5i]");
}
@@ -42,7 +43,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(*(p))[5i]");
}
diff --git a/src/tint/writer/wgsl/generator_impl_binary_test.cc b/src/tint/writer/wgsl/generator_impl_binary_test.cc
index d86b1c4..88bf9f5 100644
--- a/src/tint/writer/wgsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_binary_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/test_helper.h"
namespace tint::writer::wgsl {
@@ -47,7 +48,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), params.result);
}
diff --git a/src/tint/writer/wgsl/generator_impl_bitcast_test.cc b/src/tint/writer/wgsl/generator_impl_bitcast_test.cc
index 6d2de3a..df2a9aa 100644
--- a/src/tint/writer/wgsl/generator_impl_bitcast_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_bitcast_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -27,7 +28,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
EXPECT_EQ(out.str(), "bitcast<f32>(1i)");
}
diff --git a/src/tint/writer/wgsl/generator_impl_call_test.cc b/src/tint/writer/wgsl/generator_impl_call_test.cc
index 4492628..f484cb6 100644
--- a/src/tint/writer/wgsl/generator_impl_call_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_call_test.cc
@@ -13,6 +13,7 @@
// limitations under the License.
#include "src/tint/ast/call_statement.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -33,7 +34,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "my_func()");
}
@@ -56,7 +57,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
EXPECT_EQ(out.str(), "my_func(param1, param2)");
}
diff --git a/src/tint/writer/wgsl/generator_impl_cast_test.cc b/src/tint/writer/wgsl/generator_impl_cast_test.cc
index 66b7a2e..31e3ad0 100644
--- a/src/tint/writer/wgsl/generator_impl_cast_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_cast_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -27,7 +28,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
EXPECT_EQ(out.str(), "f32(1i)");
}
@@ -40,7 +41,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
EXPECT_EQ(out.str(), "f16(1i)");
}
@@ -51,7 +52,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
EXPECT_EQ(out.str(), "vec3<f32>(vec3<i32>(1i, 2i, 3i))");
}
@@ -64,7 +65,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
EXPECT_EQ(out.str(), "vec3<f16>(vec3<i32>(1i, 2i, 3i))");
}
diff --git a/src/tint/writer/wgsl/generator_impl_identifier_test.cc b/src/tint/writer/wgsl/generator_impl_identifier_test.cc
index 7b60b63..f270ede 100644
--- a/src/tint/writer/wgsl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_identifier_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/test_helper.h"
namespace tint::writer::wgsl {
@@ -26,7 +27,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
EXPECT_EQ(out.str(), "glsl");
}
diff --git a/src/tint/writer/wgsl/generator_impl_literal_test.cc b/src/tint/writer/wgsl/generator_impl_literal_test.cc
index c660198..e947778 100644
--- a/src/tint/writer/wgsl/generator_impl_literal_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_literal_test.cc
@@ -14,6 +14,7 @@
#include <cstring>
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -114,7 +115,7 @@
SetResolveOnBuild(false);
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitLiteral(out, v)) << gen.error();
EXPECT_EQ(out.str(), GetParam().expected);
}
@@ -162,7 +163,7 @@
SetResolveOnBuild(false);
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitLiteral(out, v)) << gen.error();
EXPECT_EQ(out.str(), GetParam().expected);
}
diff --git a/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc b/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
index 208be35..8317305 100644
--- a/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/test_helper.h"
namespace tint::writer::wgsl {
@@ -28,7 +29,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "str.mem");
}
@@ -43,7 +44,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
EXPECT_EQ(out.str(), "(*(p)).mem");
}
diff --git a/src/tint/writer/wgsl/generator_impl_type_test.cc b/src/tint/writer/wgsl/generator_impl_type_test.cc
index 422b711..aa22d73 100644
--- a/src/tint/writer/wgsl/generator_impl_type_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_type_test.cc
@@ -17,6 +17,7 @@
#include "src/tint/type/multisampled_texture.h"
#include "src/tint/type/sampled_texture.h"
#include "src/tint/type/texture_dimension.h"
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -32,7 +33,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "alias");
}
@@ -42,7 +43,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "array<bool, 4u>");
}
@@ -53,7 +54,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "@stride(16) array<bool, 4u>");
}
@@ -63,7 +64,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "array<bool>");
}
@@ -73,7 +74,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "bool");
}
@@ -83,7 +84,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "f32");
}
@@ -95,7 +96,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "f16");
}
@@ -105,7 +106,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "i32");
}
@@ -115,7 +116,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "mat2x3<f32>");
}
@@ -127,7 +128,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "mat2x3<f16>");
}
@@ -138,7 +139,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "ptr<workgroup, f32>");
}
@@ -150,7 +151,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "ptr<storage, f32, read_write>");
}
@@ -164,7 +165,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "S");
}
@@ -291,7 +292,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "u32");
}
@@ -301,7 +302,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "vec3<f32>");
}
@@ -313,7 +314,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "vec3<f16>");
}
@@ -335,7 +336,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), param.name);
}
@@ -356,7 +357,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<f32>");
}
@@ -369,7 +370,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<i32>");
}
@@ -382,7 +383,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<u32>");
}
@@ -405,7 +406,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<f32>");
}
@@ -418,7 +419,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<i32>");
}
@@ -431,7 +432,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<u32>");
}
@@ -459,7 +460,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), param.name);
}
@@ -490,7 +491,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitImageFormat(out, param.fmt)) << gen.error();
EXPECT_EQ(out.str(), param.name);
}
@@ -521,7 +522,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "sampler");
}
@@ -532,7 +533,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, type)) << gen.error();
EXPECT_EQ(out.str(), "sampler_comparison");
}
diff --git a/src/tint/writer/wgsl/generator_impl_unary_op_test.cc b/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
index a9cd10c..537f5d4 100644
--- a/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/test_helper.h"
namespace tint::writer::wgsl {
@@ -26,7 +27,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "&(expr)");
}
@@ -38,7 +39,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "~(expr)");
}
@@ -51,7 +52,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "*(expr)");
}
@@ -63,7 +64,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "!(expr)");
}
@@ -75,7 +76,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
EXPECT_EQ(out.str(), "-(expr)");
}
diff --git a/src/tint/writer/wgsl/generator_impl_variable_test.cc b/src/tint/writer/wgsl/generator_impl_variable_test.cc
index 5c9506f..2706c30 100644
--- a/src/tint/writer/wgsl/generator_impl_variable_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_variable_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/wgsl/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -26,7 +27,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
EXPECT_EQ(out.str(), R"(var<private> a : f32;)");
}
@@ -36,7 +37,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
EXPECT_EQ(out.str(), R"(var<private> a : f32;)");
}
@@ -48,7 +49,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
EXPECT_EQ(out.str(), R"(@binding(0) @group(0) var<storage, read> a : S;)");
}
@@ -60,7 +61,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
EXPECT_EQ(out.str(), R"(@binding(0) @group(0) var<storage, read_write> a : S;)");
}
@@ -70,7 +71,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
EXPECT_EQ(out.str(), R"(@group(1) @binding(2) var a : sampler;)");
}
@@ -80,7 +81,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
EXPECT_EQ(out.str(), R"(var<private> a : f32 = 1.0f;)");
}
@@ -91,7 +92,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
EXPECT_EQ(out.str(), R"(let a : f32 = 1.0f;)");
}
@@ -102,7 +103,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
EXPECT_EQ(out.str(), R"(let a = 1.0f;)");
}
@@ -113,7 +114,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
EXPECT_EQ(out.str(), R"(const a : f32 = 1.0f;)");
}
@@ -124,7 +125,7 @@
GeneratorImpl& gen = Build();
- std::stringstream out;
+ utils::StringStream out;
ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
EXPECT_EQ(out.str(), R"(const a = 1.0f;)");
}