Import Tint changes from Dawn
Changes:
- c970e806dbe9fe921cad7716199e1e6fa2b9be6e [ir] Emit `var` and `let` into the IR by dan sinclair <dsinclair@chromium.org>
- 642a4f1d8c94e684c21a7fc47b75cfeee8ff656d [ir] Make dump output more consistent. by dan sinclair <dsinclair@chromium.org>
- f26b1269bdc7a450c02aa7d198028d2501fe3678 [ir] Move `ir::Bitcast` to inherit `ir::Call`. by dan sinclair <dsinclair@chromium.org>
- 4a2e0ad36b0ed0738a1c32fd1ddf5268231e749b [ir] Make `ir::Discard` a child of `ir::Call`. by dan sinclair <dsinclair@chromium.org>
- bc6720b9f6554c4ee4800adeb818cc007729103c tint/type: Remove Source from Struct & StructMember by Ben Clayton <bclayton@google.com>
- bc9e422728eb3c8d4d5b27d8394262066ba40cd4 tint: Use type::Struct where possible by Ben Clayton <bclayton@google.com>
- 576ba1c4939288fdc1ae723f173d155a63c7c8e7 tint: Add StructMember attributes to sem. by Ben Clayton <bclayton@google.com>
- 333cea405c5e41a7ee2cca852eee914fd724113a tint/resolver: Clean up attribute resolving by Ben Clayton <bclayton@google.com>
- fe8a76cbbc447db0ebbe7da4818accca70900b13 [ir] Use the const eval results for expressions. by dan sinclair <dsinclair@chromium.org>
- f00679fd72baa267cb780e2065a988b2115890bc [ir] Make ir::Instruction a ir::Value. by dan sinclair <dsinclair@chromium.org>
- 5e344a338fcfe0737ad3933953a6dbc7164cd15c [ir] Split AST and SEM sources out of core ir. by dan sinclair <dsinclair@chromium.org>
- 9d3af6521bf1be1bda98477d7db5c124883e1dab tint/ir: Add GN option for building the IR by James Price <jrprice@google.com>
- 47dd30117d7d1bc425a189409f0d85ab804a36a2 tint/resolver: Resolve builtin structs by Ben Clayton <bclayton@google.com>
- d3b09b90e31e468746d5ec643a6a6c30e4554123 tint/resolver: Add builtin_structs.h / .cc by Ben Clayton <bclayton@google.com>
- 72d1ea4ac2b5640d9490cca6243be48da171a2bf tint/resolver: Remove duplicate nullptr check by James Price <jrprice@google.com>
- 135ab2b39f178a2ecefd2911e82fc79eb385a43b [ir] Rename instr. by dan sinclair <dsinclair@chromium.org>
GitOrigin-RevId: c970e806dbe9fe921cad7716199e1e6fa2b9be6e
Change-Id: Ifa429a18a4655d1fe7ddae825bbcb2b0bbbf04f1
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/129760
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 492e355..c6affb1 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -85,6 +85,12 @@
defines += [ "TINT_BUILD_SYNTAX_TREE_WRITER=0" ]
}
+ if (tint_build_ir) {
+ defines += [ "TINT_BUILD_IR=1" ]
+ } else {
+ defines += [ "TINT_BUILD_IR=0" ]
+ }
+
include_dirs = [
"${tint_root_dir}/",
"${tint_root_dir}/include/",
@@ -281,6 +287,8 @@
"clone_context.cc",
"program.cc",
"program_builder.cc",
+ "resolver/builtin_structs.cc",
+ "resolver/builtin_structs.h",
"resolver/const_eval.cc",
"resolver/const_eval.h",
"resolver/ctor_conv_intrinsic.cc",
@@ -739,6 +747,7 @@
"builtin/extension.h",
"builtin/function.cc",
"builtin/function.h",
+ "builtin/interpolation.h",
"builtin/interpolation_sampling.cc",
"builtin/interpolation_sampling.h",
"builtin/interpolation_type.cc",
@@ -1096,6 +1105,87 @@
]
}
+libtint_source_set("libtint_ir_builder_src") {
+ sources = [
+ "ir/builder_impl.cc",
+ "ir/builder_impl.h",
+ "ir/converter.cc",
+ "ir/converter.h",
+ ]
+ deps = [
+ ":libtint_ast_src",
+ ":libtint_constant_src",
+ ":libtint_ir_src",
+ ":libtint_program_src",
+ ":libtint_sem_src",
+ ":libtint_type_src",
+ ":libtint_utils_src",
+ ]
+}
+
+libtint_source_set("libtint_ir_src") {
+ sources = [
+ "ir/binary.cc",
+ "ir/binary.h",
+ "ir/bitcast.cc",
+ "ir/bitcast.h",
+ "ir/block.cc",
+ "ir/block.h",
+ "ir/builder.cc",
+ "ir/builder.h",
+ "ir/builtin.cc",
+ "ir/builtin.h",
+ "ir/call.cc",
+ "ir/call.h",
+ "ir/constant.cc",
+ "ir/constant.h",
+ "ir/construct.cc",
+ "ir/construct.h",
+ "ir/convert.cc",
+ "ir/convert.h",
+ "ir/debug.cc",
+ "ir/debug.h",
+ "ir/disassembler.cc",
+ "ir/disassembler.h",
+ "ir/discard.cc",
+ "ir/discard.h",
+ "ir/flow_node.cc",
+ "ir/flow_node.h",
+ "ir/function.cc",
+ "ir/function.h",
+ "ir/if.cc",
+ "ir/if.h",
+ "ir/instruction.cc",
+ "ir/instruction.h",
+ "ir/loop.cc",
+ "ir/loop.h",
+ "ir/module.cc",
+ "ir/module.h",
+ "ir/store.cc",
+ "ir/store.h",
+ "ir/switch.cc",
+ "ir/switch.h",
+ "ir/terminator.cc",
+ "ir/terminator.h",
+ "ir/unary.cc",
+ "ir/unary.h",
+ "ir/user_call.cc",
+ "ir/user_call.h",
+ "ir/value.cc",
+ "ir/value.h",
+ "ir/var.cc",
+ "ir/var.h",
+ ]
+
+ deps = [
+ ":libtint_builtins_src",
+ ":libtint_constant_src",
+ ":libtint_symbols_src",
+ ":libtint_type_src",
+ ":libtint_utils_src",
+ ]
+}
+
source_set("libtint") {
public_deps = [
":libtint_ast_src",
@@ -1143,6 +1233,15 @@
public_deps += [ ":libtint_syntax_tree_writer_src" ]
}
+ if (tint_build_ir) {
+ assert(!build_with_chromium,
+ "tint_build_ir cannot be used when building Chromium")
+ public_deps += [
+ ":libtint_ir_builder_src",
+ ":libtint_ir_src",
+ ]
+ }
+
configs += [ ":tint_common_config" ]
public_configs = [ ":tint_public_config" ]
@@ -1414,6 +1513,7 @@
"resolver/attribute_validation_test.cc",
"resolver/bitcast_validation_test.cc",
"resolver/builtin_enum_test.cc",
+ "resolver/builtin_structs_test.cc",
"resolver/builtin_test.cc",
"resolver/builtin_validation_test.cc",
"resolver/builtins_validation_test.cc",
@@ -2016,6 +2116,24 @@
]
}
+ tint_unittests_source_set("tint_unittests_ir_src") {
+ sources = [
+ "ir/binary_test.cc",
+ "ir/bitcast_test.cc",
+ "ir/builder_impl_test.cc",
+ "ir/constant_test.cc",
+ "ir/discard_test.cc",
+ "ir/store_test.cc",
+ "ir/test_helper.h",
+ "ir/unary_test.cc",
+ ]
+
+ deps = [
+ ":libtint_ir_builder_src",
+ ":libtint_ir_src",
+ ]
+ }
+
if (build_with_chromium) {
tint_unittests_source_set("tint_unittests_fuzzer_src") {
sources = [ "fuzzers/random_generator_test.cc" ]
@@ -2077,6 +2195,10 @@
deps += [ ":tint_unittests_glsl_writer_src" ]
}
+ if (tint_build_ir) {
+ deps += [ ":tint_unittests_ir_src" ]
+ }
+
if (build_with_chromium) {
deps += [ ":tint_unittests_fuzzer_src" ]
}
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index f715428..2e1ded8 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -264,6 +264,8 @@
reflection.h
reader/reader.cc
reader/reader.h
+ resolver/builtin_structs.cc
+ resolver/builtin_structs.h
resolver/const_eval.cc
resolver/const_eval.h
resolver/dependency_graph.cc
@@ -716,6 +718,8 @@
ir/construct.h
ir/convert.cc
ir/convert.h
+ ir/converter.cc
+ ir/converter.h
ir/debug.cc
ir/debug.h
ir/disassembler.cc
@@ -734,8 +738,6 @@
ir/loop.h
ir/module.cc
ir/module.h
- ir/runtime.cc
- ir/runtime.h
ir/store.cc
ir/store.h
ir/switch.cc
@@ -748,6 +750,8 @@
ir/user_call.h
ir/value.cc
ir/value.h
+ ir/var.cc
+ ir/var.h
)
endif()
@@ -911,6 +915,7 @@
resolver/attribute_validation_test.cc
resolver/bitcast_validation_test.cc
resolver/builtin_enum_test.cc
+ resolver/builtin_structs_test.cc
resolver/builtin_test.cc
resolver/builtin_validation_test.cc
resolver/builtins_validation_test.cc
@@ -1420,7 +1425,6 @@
ir/builder_impl_test.cc
ir/constant_test.cc
ir/discard_test.cc
- ir/runtime_test.cc
ir/store_test.cc
ir/test_helper.h
ir/unary_test.cc
diff --git a/src/tint/builtin/access_bench.cc b/src/tint/builtin/access_bench.cc
index 91f808f..58a5f47 100644
--- a/src/tint/builtin/access_bench.cc
+++ b/src/tint/builtin/access_bench.cc
@@ -43,7 +43,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(AccessParser);
diff --git a/src/tint/builtin/address_space_bench.cc b/src/tint/builtin/address_space_bench.cc
index 18cc9d2..81b27eb 100644
--- a/src/tint/builtin/address_space_bench.cc
+++ b/src/tint/builtin/address_space_bench.cc
@@ -94,7 +94,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(AddressSpaceParser);
diff --git a/src/tint/builtin/attribute_bench.cc b/src/tint/builtin/attribute_bench.cc
index 5d12ab3..a25fbf1 100644
--- a/src/tint/builtin/attribute_bench.cc
+++ b/src/tint/builtin/attribute_bench.cc
@@ -143,7 +143,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(AttributeParser);
diff --git a/src/tint/builtin/builtin.cc b/src/tint/builtin/builtin.cc
index 085a266..8f26436 100644
--- a/src/tint/builtin/builtin.cc
+++ b/src/tint/builtin/builtin.cc
@@ -28,6 +28,84 @@
/// @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 == "__atomic_compare_exchange_result_i32") {
+ return Builtin::kAtomicCompareExchangeResultI32;
+ }
+ if (str == "__atomic_compare_exchange_result_u32") {
+ return Builtin::kAtomicCompareExchangeResultU32;
+ }
+ if (str == "__frexp_result_abstract") {
+ return Builtin::kFrexpResultAbstract;
+ }
+ if (str == "__frexp_result_f16") {
+ return Builtin::kFrexpResultF16;
+ }
+ if (str == "__frexp_result_f32") {
+ return Builtin::kFrexpResultF32;
+ }
+ if (str == "__frexp_result_vec2_abstract") {
+ return Builtin::kFrexpResultVec2Abstract;
+ }
+ if (str == "__frexp_result_vec2_f16") {
+ return Builtin::kFrexpResultVec2F16;
+ }
+ if (str == "__frexp_result_vec2_f32") {
+ return Builtin::kFrexpResultVec2F32;
+ }
+ if (str == "__frexp_result_vec3_abstract") {
+ return Builtin::kFrexpResultVec3Abstract;
+ }
+ if (str == "__frexp_result_vec3_f16") {
+ return Builtin::kFrexpResultVec3F16;
+ }
+ if (str == "__frexp_result_vec3_f32") {
+ return Builtin::kFrexpResultVec3F32;
+ }
+ if (str == "__frexp_result_vec4_abstract") {
+ return Builtin::kFrexpResultVec4Abstract;
+ }
+ if (str == "__frexp_result_vec4_f16") {
+ return Builtin::kFrexpResultVec4F16;
+ }
+ if (str == "__frexp_result_vec4_f32") {
+ return Builtin::kFrexpResultVec4F32;
+ }
+ if (str == "__modf_result_abstract") {
+ return Builtin::kModfResultAbstract;
+ }
+ if (str == "__modf_result_f16") {
+ return Builtin::kModfResultF16;
+ }
+ if (str == "__modf_result_f32") {
+ return Builtin::kModfResultF32;
+ }
+ if (str == "__modf_result_vec2_abstract") {
+ return Builtin::kModfResultVec2Abstract;
+ }
+ if (str == "__modf_result_vec2_f16") {
+ return Builtin::kModfResultVec2F16;
+ }
+ if (str == "__modf_result_vec2_f32") {
+ return Builtin::kModfResultVec2F32;
+ }
+ if (str == "__modf_result_vec3_abstract") {
+ return Builtin::kModfResultVec3Abstract;
+ }
+ if (str == "__modf_result_vec3_f16") {
+ return Builtin::kModfResultVec3F16;
+ }
+ if (str == "__modf_result_vec3_f32") {
+ return Builtin::kModfResultVec3F32;
+ }
+ if (str == "__modf_result_vec4_abstract") {
+ return Builtin::kModfResultVec4Abstract;
+ }
+ if (str == "__modf_result_vec4_f16") {
+ return Builtin::kModfResultVec4F16;
+ }
+ if (str == "__modf_result_vec4_f32") {
+ return Builtin::kModfResultVec4F32;
+ }
if (str == "__packed_vec3") {
return Builtin::kPackedVec3;
}
@@ -245,6 +323,58 @@
switch (value) {
case Builtin::kUndefined:
return out << "undefined";
+ case Builtin::kAtomicCompareExchangeResultI32:
+ return out << "__atomic_compare_exchange_result_i32";
+ case Builtin::kAtomicCompareExchangeResultU32:
+ return out << "__atomic_compare_exchange_result_u32";
+ case Builtin::kFrexpResultAbstract:
+ return out << "__frexp_result_abstract";
+ case Builtin::kFrexpResultF16:
+ return out << "__frexp_result_f16";
+ case Builtin::kFrexpResultF32:
+ return out << "__frexp_result_f32";
+ case Builtin::kFrexpResultVec2Abstract:
+ return out << "__frexp_result_vec2_abstract";
+ case Builtin::kFrexpResultVec2F16:
+ return out << "__frexp_result_vec2_f16";
+ case Builtin::kFrexpResultVec2F32:
+ return out << "__frexp_result_vec2_f32";
+ case Builtin::kFrexpResultVec3Abstract:
+ return out << "__frexp_result_vec3_abstract";
+ case Builtin::kFrexpResultVec3F16:
+ return out << "__frexp_result_vec3_f16";
+ case Builtin::kFrexpResultVec3F32:
+ return out << "__frexp_result_vec3_f32";
+ case Builtin::kFrexpResultVec4Abstract:
+ return out << "__frexp_result_vec4_abstract";
+ case Builtin::kFrexpResultVec4F16:
+ return out << "__frexp_result_vec4_f16";
+ case Builtin::kFrexpResultVec4F32:
+ return out << "__frexp_result_vec4_f32";
+ case Builtin::kModfResultAbstract:
+ return out << "__modf_result_abstract";
+ case Builtin::kModfResultF16:
+ return out << "__modf_result_f16";
+ case Builtin::kModfResultF32:
+ return out << "__modf_result_f32";
+ case Builtin::kModfResultVec2Abstract:
+ return out << "__modf_result_vec2_abstract";
+ case Builtin::kModfResultVec2F16:
+ return out << "__modf_result_vec2_f16";
+ case Builtin::kModfResultVec2F32:
+ return out << "__modf_result_vec2_f32";
+ case Builtin::kModfResultVec3Abstract:
+ return out << "__modf_result_vec3_abstract";
+ case Builtin::kModfResultVec3F16:
+ return out << "__modf_result_vec3_f16";
+ case Builtin::kModfResultVec3F32:
+ return out << "__modf_result_vec3_f32";
+ case Builtin::kModfResultVec4Abstract:
+ return out << "__modf_result_vec4_abstract";
+ case Builtin::kModfResultVec4F16:
+ return out << "__modf_result_vec4_f16";
+ case Builtin::kModfResultVec4F32:
+ return out << "__modf_result_vec4_f32";
case Builtin::kPackedVec3:
return out << "__packed_vec3";
case Builtin::kArray:
diff --git a/src/tint/builtin/builtin.h b/src/tint/builtin/builtin.h
index da5226d..d891294 100644
--- a/src/tint/builtin/builtin.h
+++ b/src/tint/builtin/builtin.h
@@ -30,6 +30,32 @@
/// An enumerator of builtin builtin.
enum class Builtin {
kUndefined,
+ kAtomicCompareExchangeResultI32,
+ kAtomicCompareExchangeResultU32,
+ kFrexpResultAbstract,
+ kFrexpResultF16,
+ kFrexpResultF32,
+ kFrexpResultVec2Abstract,
+ kFrexpResultVec2F16,
+ kFrexpResultVec2F32,
+ kFrexpResultVec3Abstract,
+ kFrexpResultVec3F16,
+ kFrexpResultVec3F32,
+ kFrexpResultVec4Abstract,
+ kFrexpResultVec4F16,
+ kFrexpResultVec4F32,
+ kModfResultAbstract,
+ kModfResultF16,
+ kModfResultF32,
+ kModfResultVec2Abstract,
+ kModfResultVec2F16,
+ kModfResultVec2F32,
+ kModfResultVec3Abstract,
+ kModfResultVec3F16,
+ kModfResultVec3F32,
+ kModfResultVec4Abstract,
+ kModfResultVec4F16,
+ kModfResultVec4F32,
kPackedVec3,
kArray,
kAtomic,
@@ -113,6 +139,32 @@
Builtin ParseBuiltin(std::string_view str);
constexpr const char* kBuiltinStrings[] = {
+ "__atomic_compare_exchange_result_i32",
+ "__atomic_compare_exchange_result_u32",
+ "__frexp_result_abstract",
+ "__frexp_result_f16",
+ "__frexp_result_f32",
+ "__frexp_result_vec2_abstract",
+ "__frexp_result_vec2_f16",
+ "__frexp_result_vec2_f32",
+ "__frexp_result_vec3_abstract",
+ "__frexp_result_vec3_f16",
+ "__frexp_result_vec3_f32",
+ "__frexp_result_vec4_abstract",
+ "__frexp_result_vec4_f16",
+ "__frexp_result_vec4_f32",
+ "__modf_result_abstract",
+ "__modf_result_f16",
+ "__modf_result_f32",
+ "__modf_result_vec2_abstract",
+ "__modf_result_vec2_f16",
+ "__modf_result_vec2_f32",
+ "__modf_result_vec3_abstract",
+ "__modf_result_vec3_f16",
+ "__modf_result_vec3_f32",
+ "__modf_result_vec4_abstract",
+ "__modf_result_vec4_f16",
+ "__modf_result_vec4_f32",
"__packed_vec3",
"array",
"atomic",
diff --git a/src/tint/builtin/builtin_bench.cc b/src/tint/builtin/builtin_bench.cc
index 1f309f5..4804ff7 100644
--- a/src/tint/builtin/builtin_bench.cc
+++ b/src/tint/builtin/builtin_bench.cc
@@ -31,496 +31,678 @@
void BuiltinParser(::benchmark::State& state) {
const char* kStrings[] = {
- "__acked_veccc",
- "_pac3ed_v3",
- "__packeV_vec3",
+ "__atomic_compareexchangeccresult_i32",
+ "__atoml3_compare_exchane_resulti2",
+ "__atomic_compare_Vxchange_result_i32",
+ "__atomic_compare_exchange_result_i32",
+ "__atomic_com1are_exchange_result_i32",
+ "__atomic_qqompare_exchage_resulJ_i32",
+ "__atllmic_compare_exchange_result_i377",
+ "__atomicppcompareqqexchange_reslt_uHH2",
+ "__atomi_compare_exchavge_cesult_3",
+ "__atomic_copare_eGbhange_result_u32",
+ "__atomic_compare_exchange_result_u32",
+ "__atomic_coiipare_exvhange_result_u32",
+ "__atomic_compaWWe_excha8ge_result_u32",
+ "__atomic_comparxxMexchage_result_u32",
+ "__fXexp_resgglt_bstract",
+ "V_frexp_resul_abuXrct",
+ "__frexp_result_abstra3t",
+ "__frexp_result_abstract",
+ "__frexp_resElt_abstract",
+ "__frexTT_Pesult_abstract",
+ "__frexp_resulxxddabstrct",
+ "44_frexp_result_f16",
+ "_VVfrexp_resulSS_f16",
+ "__frexp_reRult_fR6",
+ "__frexp_result_f16",
+ "__frFxp_re9ut_f16",
+ "__frep_result_f16",
+ "__frRRVH_rOOsultf16",
+ "__frepyresult_f32",
+ "_nrr77rexp_result_fGll",
+ "__4rex00_result_f32",
+ "__frexp_result_f32",
+ "__oorep_reult_f2",
+ "__fzzexp_result_3",
+ "__iir11x_respplt_f3",
+ "__frexp_resuXXt_vec2_abstract",
+ "55n99frexp_result_vec2_abstraIIt",
+ "__fHHexpSSaresrrlt_Yec2_abstract",
+ "__frexp_result_vec2_abstract",
+ "__freHp_resutve2_abstkkact",
+ "jfrexpgresult_veRR2_abstrac",
+ "__frexp_resul_vec2_absbrac",
+ "_jfrexp_result_vec2_f16",
+ "__frexp_resultvec2_f16",
+ "__freqpresultvec2_f16",
+ "__frexp_result_vec2_f16",
+ "__frexNN_result_vec_f16",
+ "__frexp_resvvlt_vc2_f1",
+ "__frexp_esult_vec2_f1QQ",
+ "__rerp_result_ffec2_f2",
+ "__frexp_result_vjc2_f32",
+ "__frewwp_reul2_vec2_NN82",
+ "__frexp_result_vec2_f32",
+ "__frexpresult_vec2_f32",
+ "__frexp_result_vec2_frr2",
+ "_Gfrexp_result_vec2_f32",
+ "__frexp_resulFF_vec3_abstract",
+ "_frexp_resultvec3_Estract",
+ "__fexp_result_vec3_abstrract",
+ "__frexp_result_vec3_abstract",
+ "frexp_result_vec3_abstract",
+ "D_rexp_resXlt_veJJ3_abstract",
+ "_frexp_resut_v8c_abstract",
+ "_frexp_rsl1k_vec3_f16",
+ "__frexp_reslt_vec3_f16",
+ "__frexJ_reult_vec3_f16",
+ "__frexp_result_vec3_f16",
+ "c_frexp_result_vec3_f16",
+ "__frexp_result_vec3Of16",
+ "___frexp_reKKultvvvec3_f1tt",
+ "8_frexp_reult_vxxc3_f32",
+ "_frexp_resul___veFqqf32",
+ "_qqfrexp_result_vec_f32",
+ "__frexp_result_vec3_f32",
+ "33_fOexp_result_ve3_6632",
+ "__oorexQQ_rttsult_ve639f32",
+ "__rexp_result_vec3_f662",
+ "__frexp_reszzlt_Oc4xabstrac66",
+ "__frexp_resyylt_vec4_abstract",
+ "__frexp_resut_vecHH_aZsracZ",
+ "__frexp_result_vec4_abstract",
+ "_WWfrex44_resulq_vec4_astract",
+ "__frexp_rsult_veOO4_abstract",
+ "__frexp_resultoovc4_abstYct",
+ "_frexp_esultvec4_f16",
+ "__Frexp_result_ec4_f16",
+ "__frewp_resut_vec4_f16",
+ "__frexp_result_vec4_f16",
+ "__frexp_reslt_veK4fG16",
+ "__fqexp_result_veKK4_f16",
+ "_F3rexp_result_vec4_f1mm",
+ "__frexp_result_ec4_f32",
+ "__frexp_result_qe4_f32",
+ "__frbbxp_result_vec4_b2",
+ "__frexp_result_vec4_f32",
+ "__frexp_reslt_iiec4_f2",
+ "__frexO_resulq_vec4_f32",
+ "__frexp_resulTT_vec4vvf32",
+ "__modf_resulFF_abstract",
+ "fm00df_rePult_abstraQt",
+ "__modf_result_abstPact",
+ "__modf_result_abstract",
+ "_modf_result_abstssac77",
+ "__modf_resulC_bbRbstract",
+ "__modf_result_abstracXX",
+ "__OOofCCresuOOt_f16",
+ "_smodf_resuutfL6",
+ "__modX_result_f16",
+ "__modf_result_f16",
+ "__modf_reult_f16",
+ "__modf_resqqO16",
+ "__modf22result_f16",
+ "__modf_X0eszzlt_fy",
+ "_VVmPf_result_f3i",
+ "__monnfCresultf32",
+ "__modf_result_f32",
+ "_HHAmodf_resqltf32",
+ "__modf_resut_f32",
+ "__modresuft_f3KK",
+ "__modlPrsultggvec2_astract",
+ "__odf_result_vec2_abstract",
+ "__mocTf_result_vNc2_abstra4t",
+ "__modf_result_vec2_abstract",
+ "__modf77result_vec2_plbtract",
+ "__mdf_resultNNvec2zabstgact",
+ "_modf_bbesult_vuuc2_abtraXXt",
+ "__modf_esult_vec2_f16",
+ "__mQdf_esuKt_vec_8816",
+ "q_m9dfresult_vec2_f16",
+ "__modf_result_vec2_f16",
+ "__11odf_result_vec2_f16",
+ "_iimodf_result_vF222f16",
+ "_77modf_result_vec2f16",
+ "__odfNNr2sult_vec2_f32",
+ "__modf_rVVsult_vec2_f32",
+ "__modf_Fesult_vewW2_f311",
+ "__modf_result_vec2_f32",
+ "__modf_rwwsult_vec_f32",
+ "__modf_result_Dec2_f32",
+ "__modf_result_ec2_f3K",
+ "__modf_resul1PP_vech_abstfact",
+ "__modf_result_vec_abstract",
+ "__YYodf_result_vec3_abstract",
+ "__modf_result_vec3_abstract",
+ "__mHHdfresult_kkec3_abstract",
+ "__modf_result_vec3rrabstract",
+ "__modf_ssesulWW_vec_abstract",
+ "__mYdf_reslt_vec3_f16",
+ "q_modLrfsult_vec3_f16",
+ "uu_vvo22f_rfsult_ec3_f16",
+ "__modf_result_vec3_f16",
+ "__mdf_reslt_vec3_f16",
+ "__modfYYresult_ve3f16",
+ "__modfEr77sult_vec3_yY16",
+ "__odf_desuMot_vec3_f32",
+ "__mMMf_result_vec3_f32",
+ "__modf_result_vec3_f355",
+ "__modf_result_vec3_f32",
+ "__modf_rest_vec3Nf32",
+ "_m33df_result_Oec3_f32",
+ "__modf_re3ult_vec3_f32",
+ "__momf_esult_Iec4_abstract",
+ "__modf_resultrvec4_absnnracK",
+ "__modf_eslt_ve4_absXXact",
+ "__modf_result_vec4_abstract",
+ "__modf_rsult_pLLI4_abstract",
+ "_modf_resflt_vec4_bstract",
+ "_Ymodf_resultURDec4_abtract",
+ "__hodf_result_vec4_f16",
+ "__moquu_rslt_vec4_f1II",
+ "__modf_result_vecH_f16",
+ "__modf_result_vec4_f16",
+ "__oQQf_resultvvvc4_f16",
+ "__modf_eeult66ec4_f16",
+ "_Omodf_r7sut_vec4_W16",
+ "__modf_DDes0lt_v55c4_f32",
+ "__modf_rIIsult_Hec4_f32",
+ "_modf_result_vec4_f32",
+ "__modf_result_vec4_f32",
+ "_modf_result_vrc4_f32",
+ "_lmodf_result_vec4_f32",
+ "tt_modfGeslt_vec4_fJJ2",
+ "__paked_vyc3",
+ "_packed_vec3",
+ "__pIIckedBBvec3",
"__packed_vec3",
- "__pa1ked_vec3",
- "_qqJcked_vec3",
- "__pack77d_vllc3",
- "arqHapp",
- "vy",
- "Grby",
+ "__8aTTked_v33c3",
+ "dnnUUpackeSSY_vec3",
+ "xC_5ackedZvec3",
+ "kkrraq",
+ "a005iy",
+ "anIIray",
"array",
- "arviay",
- "ar8WWy",
- "Mxxra",
- "atXggi",
- "Xoic",
- "ato3ic",
+ "ccrW",
+ "rKK",
+ "arr66y",
+ "aKKoPi",
+ "atxxmc",
+ "atoqic",
"atomic",
- "aEomic",
- "toTTiPP",
- "ddtoxxi",
- "44ool",
- "VVSSol",
- "RoRl",
+ "rMoyyiSS",
+ "utom",
+ "oic",
+ "5oFFl",
+ "borz4l",
+ "WW",
"bool",
- "oFl",
- "boo",
- "ORVHl",
- "y1",
- "l77rrn6",
- "4016",
+ "ZJJCoX",
+ "boPP",
+ "bocl",
+ "fll66",
+ "91yy",
+ "f1KK",
"f16",
- "5",
- "u16",
- "f",
- "f3kk",
- "fi",
- "f3XX",
+ "x_",
+ "K",
+ "kVz",
+ "K3S",
+ "f2",
+ "fVV",
"f32",
- "55399II",
- "frSSHHa",
- "U",
- "jV3",
- "",
- "GG",
+ "IAU2",
+ "j",
+ "Y4",
+ "i2",
+ "1xx",
+ "ccm",
"i32",
- "2",
- "",
- "jj",
- "a2xrf",
- "mat2j2",
- "m82wNN2",
- "mat2x2",
+ "iJJ",
+ "UfCDD",
+ "i3g",
+ "CCtx",
"mt2x2",
- "rrat2x2",
- "mGt2x2",
- "mat2x2FF",
- "at2f",
- "marrx2f",
+ "mat2x__",
+ "mat2x2",
+ "attxPP",
+ "mdd32x2",
+ "yyK2x2",
+ "m2uu",
+ "ma0nnx2i",
+ "KanuuCC2f",
"mat2x2f",
- "t2x2f",
- "Da2xJJf",
- "ma82",
- "m11k2",
- "matx2h",
- "maJx2h",
+ "mlX2x2f",
+ "oat2pp2f",
+ "wwat22f",
+ "matguum",
+ "mt2ma2",
+ "Tat2xZRRh",
"mat2x2h",
- "mat2c2h",
- "mat2x2O",
- "KK_atvvtt2h",
- "5txxx8",
- "a__xqq",
- "maqq2x",
+ "ma8T2xOh",
+ "m0at2x2h",
+ "mBBt2x2h",
+ "Matpp",
+ "Oat2x3",
+ "GGG2x3",
"mat2x3",
- "ma32x66",
- "mttQQo2x3",
- "mat66x",
- "mtOxzz66",
- "mat2yy3f",
- "ZaHH3Z",
- "mat2x3f",
- "4WWt2q3f",
- "mOO2x3f",
- "oatY3f",
+ "mHHt2113",
+ "mateF63",
"matx",
- "ma2xFh",
- "at2x3w",
+ "mat2ii3l",
+ "mt2x3f",
+ "IIvvt2x39",
+ "mat2x3f",
+ "mat23f",
+ "mat2h3f",
+ "mllt2xPzz",
+ "t3h",
+ "mtffxqqh",
+ "mtJJx3dd",
"mat2x3h",
- "fGtxKh",
- "matqKx3h",
- "matmmxFh",
- "at2x4",
- "matxq",
- "mb2bb4",
+ "mzz2X3h",
+ "matx32",
+ "maN2yy3h",
+ "atxO",
+ "rauExP",
+ "meet22dd",
"mat2x4",
- "it2x4",
- "mOO2xq",
- "mat2Tvv4",
- "maFF2x4f",
- "Pa00xQf",
- "mPt2x4f",
+ "maV92",
+ "maI2x1",
+ "mab2x4",
+ "matzf",
+ "mao2ii4f",
+ "mat45",
"mat2x4f",
- "ma772xss",
- "RRCbb2x4f",
- "mXXt2x4f",
- "qaCC2xOOh",
- "ma2s4L",
- "mXt2x4h",
+ "at2xSf",
+ "mat22f",
+ "maG1C4f",
+ "maff284h",
+ "t2x4h",
+ "SSatJJx4h",
"mat2x4h",
- "mat24h",
- "qa2O4",
- "mat2x22h",
- "mzzyt3x",
- "atiVP2",
- "mt3Cnn",
+ "atx9h",
+ "maJJbbTT4h",
+ "66a2xh",
+ "ma663u",
+ "Wa3x2",
+ "ma32",
"mat3x2",
- "AtqqHH2",
- "at3x2",
- "mafKK",
- "ltgg2f",
- "mat3xf",
- "NTTtcx4f",
+ "ma3x2",
+ "rat3x2",
+ "m2t3xB",
+ "matxBBf",
+ "maRR3xf",
+ "maVV0Lf",
"mat3x2f",
- "ma7ppl2f",
- "mNNt3xg",
- "uub3XX2f",
- "matx2h",
- "Qt882h",
- "mt9q2h",
+ "a3OOK2f",
+ "magw3xf",
+ "hht3L2f",
+ "aKii3xh",
+ "ma3x2h",
+ "UUa3882",
"mat3x2h",
- "m11t3x2h",
- "22at3iih",
- "at3x277",
- "NNa323",
- "VVat3x3",
- "ma11F3w3",
+ "rrvvt3x2h",
+ "m3xwmm",
+ "j443x2h",
+ "matXx3",
+ "m8t3x3",
+ "mat3vEE",
"mat3x3",
- "matww3",
- "mat3D3",
- "maKx3",
- "mat31PPhf",
- "mat33f",
- "mYYt3x3f",
- "mat3x3f",
- "mttHH3kk",
- "mat3rr3f",
- "WWas3x3f",
- "Yt3x3h",
- "mt3qfh",
- "mav223xuh",
- "mat3x3h",
- "t3x3h",
- "YYat3h",
- "may3x3EYY",
- "Moatd4",
- "mt3xMM",
- "m55t3x4",
- "mat3x4",
- "maN4",
- "ma33x4",
+ "mzzi3x",
+ "maGGQ3JJ3",
+ "mat3ss3",
+ "matKxPf",
+ "mat3ttf",
"mt3x3",
- "mm66Issf",
- "mat3x1f",
- "Xt3x4",
+ "mat3x3f",
+ "mMMt3x3f",
+ "maJ03x3f",
+ "V8x3",
+ "maKggx3hh",
+ "maf3x3h",
+ "matQ7x3h",
+ "mat3x3h",
+ "mat3YYh",
+ "mak3x3",
+ "man3x2",
+ "mFFx4",
+ "GGatPPuUU",
+ "mEEFa4",
+ "mat3x4",
+ "mBet3dd4",
+ "55atExcc",
+ "txKK",
+ "mat3x4R",
+ "maDx49",
+ "mt3x4f",
"mat3x4f",
- "LatIx4f",
- "at3ff",
- "mYtURD4",
- "mah3x4h",
- "uuIqt3x",
- "maH3x4h",
+ "aaat3I",
+ "m77t3x4f",
+ "matIx4f",
+ "md3x4h",
+ "mat34h",
+ "mtt4h",
"mat3x4h",
- "at3QQvv",
- "at66eh",
- "ma7O4h",
- "m0t55DD2",
- "IIaH4x2",
- "mat4x",
+ "ma3XX3x4h",
+ "Eat34h",
+ "maXX3x4",
+ "mxBt4x2",
+ "Wt4x",
+ "mat66x2",
"mat4x2",
- "mt4r2",
- "mat4xl",
- "mGttx2",
- "mat4y2",
- "mt4x2f",
- "IIaBB4x2f",
+ "atTv0",
+ "kt",
+ "mpt4x",
+ "at112f",
+ "EaJ4yBBf",
+ "mqIm4x2f",
"mat4x2f",
- "TTat4x833",
- "ddUUnntYYx2f",
- "m5CCxxdZ",
- "matkkq2h",
- "005itpxh",
- "maIInnx2h",
+ "ma4xFf",
+ "Yt4x2f",
+ "mHHtDh2f",
+ "Ht22h",
+ "matx2",
+ "matx2h",
"mat4x2h",
- "Ka4Wcc",
- "m42KK",
- "mat66x2h",
- "mKKtPx",
- "maxx43",
- "matqx3",
+ "matx2h",
+ "matddx2h",
+ "Oat4x2h",
+ "bbtB3",
+ "m00tx3",
+ "hat4x3",
"mat4x3",
- "rMtyyxSS",
- "uat4",
- "tx3",
- "ma5F4x3f",
- "rra444z3f",
- "matWW",
+ "matgYx",
+ "Oat4x3",
+ "mhx3",
+ "fpaEEx3f",
+ "mavx3f",
+ "mzztx3f",
"mat4x3f",
- "CatZJXx3f",
- "maPPx3f",
- "mat4c3f",
- "matPPll6h",
- "mat993yy",
- "mat4JKKh",
+ "ma4x3f",
+ "OOaJxii",
+ "mft4G3f",
+ "mat4x322T",
+ "datlx3h",
+ "bat4x3h",
"mat4x3h",
- "mat4_h",
- "ayK3h",
- "mzt4V3k",
- "qaSKx4",
- "mat44",
- "ma4xVV",
+ "BBatx3h",
+ "PPIXt4S3h",
+ "mjjt4x3h",
+ "macc4_4",
+ "SS6zz4xx",
+ "mtx",
"mat4x4",
- "mAAt4xI",
- "jb44",
- "t4YYx",
- "mao4x4",
- "mtx114f",
- "mtmxccf",
+ "mxxtvN",
+ "AA00t44",
+ "tyexy",
+ "mabWWx0f",
+ "ttatMMxmf",
+ "madf",
"mat4x4f",
- "aJJ4x4f",
- "fCCDD4x4U",
- "mgt4x4f",
- "CCx4h",
- "mat4x66",
- "maN4M4h",
+ "mat_4f",
+ "Vat4EE4f",
+ "mat44f",
+ "mRIxah",
+ "ma4mmh",
+ "at4x4p",
"mat4x4h",
- "mattth",
- "maKWxh",
- "mateezx4h",
- "",
- "w9",
- "4tnn",
+ "mat4xh",
+ "aaxh",
+ "mad4x4h",
+ "pCPtd",
+ "p",
+ "5tr",
"ptr",
- "tll",
- "4to",
- "wEgg",
- "gamler",
- "spleS",
- "aampl",
+ "ff99j",
+ "YYvXR",
+ "r",
+ "XX8m5le",
+ "mpler",
+ "sccmlppr",
"sampler",
- "TamplZRRr",
- "sa8TplOr",
- "m0ampler",
- "sampler_Bmomparison",
- "Mamper_ppomarison",
- "samper_compOOrison",
+ "sampver",
+ "EESSmplr",
+ "smplr",
+ "samplecomp_risa",
+ "sampler_co_prwwson",
+ "samplerdd99omparison",
"sampler_comparison",
- "sampler_compGrGGon",
- "sHHm11ler_comparison",
- "sa6ler_FFeemparison",
- "texure_1",
- "tKiilure_1d",
- "exture_1d",
+ "ampler_o99paPPison",
+ "saplerKKcomparison",
+ "saMpler_oomDDarison",
+ "teiie_1B",
+ "txureq1d",
+ "txt00rLL_d",
"texture_1d",
- "99etvIIre_1d",
- "texture_d",
- "texture_hd",
- "llxzzure_PPd",
- "exue2d",
- "tffqqtre_2d",
+ "tnxture_16vv",
+ "trrxtur_nd",
+ "xxture_eed",
+ "CCNOxture_2d",
+ "txture_2d",
+ "tex4uae_2d",
"texture_2d",
- "texturJdd_d",
- "trXXtu_2zz",
- "textu2e2d",
- "tNyyture_2d_array",
- "txture_2d_rOOa",
- "textureErduaZPay",
+ "extuNNe_2NN",
+ "texture2d",
+ "tuxtre2d",
+ "teYYtuAe_2d_arESy",
+ "texture_2d_0rray",
+ "texture_2d_aarray",
"texture_2d_array",
- "exl22re_2dd_areeay",
- "mextureVV_ar9ay",
- "teIItu1_2d_array",
- "tebture_3d",
- "ie7ure3d",
- "teotiire_3d",
+ "texturmm_2d_arra",
+ "texture_2d_aray",
+ "teEuUUe_2darray",
+ "tKKture_Dd",
+ "text__r0_3d",
+ "tAtuel3p",
"texture_3d",
- "extre_35",
- "textre_iS",
- "t22xtur_3",
- "teC711recuGe",
- "texture8cffbe",
- "textue_cue",
+ "textue_3d",
+ "texturBB_3d",
+ "nnbb99re_3d",
+ "AAEExture_cub",
+ "t66Ttu5e_cube",
+ "textuHe_cube",
"texture_cube",
- "texture_SSJJbe",
- "textrecu9e",
- "TTeJJbture_cube",
- "t66ture_cube_aray",
- "textur66_cubu_arra",
- "textureWubeyarray",
+ "textrexxHcub",
+ "tzx0uryy_cnbe",
+ "texture_cue",
+ "texurH_kube_array",
+ "exture_cube_array",
+ "ooexrrre_cbe_array",
"texture_cube_array",
- "texture_cube_ara",
- "texture_ube_array",
- "rexture_cube_array",
- "tex2ure_depth_2B",
- "texture_dpBBh_2d",
- "texture_dpth_RRd",
+ "textre_cubJJarray",
+ "tCCxtu0e_cube_arry",
+ "texturAAcxbe99aFray",
+ "textcre_depth_2d",
+ "texture_Septh_2d",
+ "textureodpthBB2d",
"texture_depth_2d",
- "tLL0Vure_deth_2d",
- "tetKKredOOpth_2d",
- "textgwre_dpth_2d",
- "textue_depthLh2d_arpay",
- "texture_depEh2diiKrray",
- "texture_dept_2d_array",
+ "texture_dept_2d",
+ "textummedepth_2d",
+ "toxture_ggeQQtPP2d",
+ "tetur_dptB_2d_rray",
+ "texNure_deKKh2d_arrlly",
+ "teture_dpth_2d_arrray",
"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",
+ "texture_epth_ppd_array",
+ "teyturPP_depth_2d_array",
+ "texture_ZZptcc_2d_arry",
+ "txtue_depth_cube",
+ "texture00depth_cube",
+ "texPPuBB_deJth_cusse",
"texture_depth_cube",
- "textur_devvth_cubEE",
- "tzxturi99epth_cube",
- "teQQtuJJGe_nepth_cuAe",
- "texture_depth_cusse_array",
- "texture_Pepth_cKbe_array",
- "texture_dppp_cube_attray",
+ "texJJre_dffpwwh_fube",
+ "textIre_depXXh_cub",
+ "textur_ph_cue",
+ "textue_depth_cube_array",
+ "tKKxtue_depth_cube_array",
+ "teture_d44ptm_cube_adray",
"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",
+ "pexture_deoth_cube_array",
+ "thhHxtureNdepth_cubejarray",
+ "texwwuUUe_depthEc33be_array",
+ "texture_dept_multiuuampled_2",
+ "ddextKre_depth_ultisampcerr_2d",
+ "textuPPe_depr_multttsample2_2d",
"texture_depth_multisampled_2d",
- "te77ture_depth_multisamQled_2d",
- "teture_depthYYmultisampled_2d",
- "texture_deptk_multiampled_Sd",
- "txturn_ext2rnal",
- "txture_FFternal",
- "texUPPIre_GGxuernal",
+ "1exture_depth_wwsltisampled_2d",
+ "textuce_depth_mnnltisamp11ed_2d",
+ "texture_depth_multisapled_2d",
+ "texture_externl",
+ "teSS66ue_exaaeInal",
+ "textuEEe_extenal",
"texture_external",
- "taxtuvEE_externl",
- "textureexBddernDDl",
- "tEEMtur_e55tccrnal",
- "texturemuKKtisample_d",
- "texture_multisRmpled_2d",
- "texturemulDisampl9d_2d",
+ "ccexture_exVerIRl",
+ "te9tue_extrnal",
+ "taaxture_exterha",
+ "texture_multisamLLeS_2d",
+ "tefurmm_mutisampled_2d",
+ "texture_mul4isampld_qV",
"texture_multisampled_2d",
- "teture_multisampled_2d",
- "textuIa_multisampld_2d",
- "texture_multisamp77ed_2d",
- "texIure_storage_1d",
- "texture_storagedd",
- "texture_storae_1d",
+ "texture_multisa_pled_d",
+ "texure_multisampledQd",
+ "texRRuremultisampledEd2d",
+ "textur_st9rage_1d",
+ "tCCx0ure_strag_1",
+ "textuezstorae_1d",
"texture_storage_1d",
- "texture_strate_d",
- "texture33stoXXcge_1d",
- "texturestorage_1E",
- "textuXXestorage_2d",
- "texture_stoBaxxe_2d",
- "texte_storWge_2G",
+ "texccure_storage_1d",
+ "textureOQQ_orge_1d",
+ "teturettstrage_1d",
+ "textCCrepzzstEr33ge_2d",
+ "textudde_storaghh_2d",
+ "_etur77_66torage_2d",
"texture_storage_2d",
- "texture_s66orage_2d",
- "textvTr_so0age_2d",
- "textureorgek2d",
- "textppre_stoae_2d_array",
- "textre_stora11e_d_array",
- "textureystorBEgeJ2d_array",
+ "texture_storaPe_2d",
+ "twxture_storage_2d",
+ "textur_straguu_2",
+ "textureXXstorage_6d_array",
+ "extuRRestorage_2d_aray",
+ "txtre_storage_2dVVarr1",
"texture_storage_2d_array",
- "texture_mtorage_2dxIqrray",
- "teture_storageF2d_array",
- "textur_Ytorage_2d_array",
- "heDture_sHHorage_3d",
- "texturstorage23H",
- "teture_strage_3d",
+ "GGexture_storHHge_2d_array",
+ "MFFxt7re_storage_2d_array",
+ "texture_storage_d_array",
+ "3xTugge_stoage_3d",
+ "texturP_QtKKrag1__d",
+ "textre_storageE3d",
"texture_storage_3d",
- "texture_storage_d",
- "texturestorage_3d",
- "ddexture_storage_3d",
- "uPO",
- "ba",
- "u02",
+ "tMture_storage_d",
+ "t77xture_sGGorSSe_3d",
+ "txtttre_storage_3FF",
+ "uZZss2",
+ "u2",
+ "u3l",
"u32",
- "h32",
- "gYY",
- "O32",
- "eh",
- "ppfe2",
- "vev",
+ "u3h",
+ "uTT",
+ "ww2",
+ "vKvjj",
+ "vYY",
+ "EcI2",
"vec2",
- "vzz2",
- "vc2",
- "OOii",
- "vGc2f",
- "22ecTTf",
- "dlc2f",
+ "vecQQ",
+ "Pc",
+ "veffH",
+ "vec2n",
+ "g6F2f",
+ "vssh8f",
"vec2f",
- "vecbf",
- "ec2BB",
- "IIScXPP",
- "jjec2h",
- "cc_c2h",
- "zz6xx2h",
+ "veFllf",
+ "00e2j",
+ "gec2f",
+ "vece",
+ "ffc2h",
+ "ve",
"vec2h",
- "c2",
- "4xx2N",
- "p0AAeh",
- "vey2",
- "vbWW0i",
- "meMMtti",
+ "ve2h",
+ "vqc2h",
+ "AAe",
+ "ec2i",
+ "vec2j",
+ "ZZec2i",
"vec2i",
- "di",
- "vvc_",
- "VEEc2i",
- "vec24",
- "VVeX2u",
- "veVou",
+ "PPecII2",
+ "ZZec2i",
+ "vnnc2i",
+ "HekkZ222",
+ "ec2",
+ "RcNQQ",
"vec2u",
- "ve2u",
- "ecKKt",
- "eG",
- "ea3",
- "OOc",
- "G",
+ "eDu",
+ "s3c2cu",
+ "vRR2u",
+ "vlJJ3",
+ "MM",
+ "vT63",
"vec3",
- "ve53",
- "9fjec3",
- "vvXcRY",
- "ccf",
- "v8XX5",
- "ec3",
+ "QQec3",
+ "vuA",
+ "e3",
+ "yeq3",
+ "vec3xx",
+ "crr",
"vec3f",
- "ppc3cc",
- "vecvf",
- "eEE3SS",
- "vec",
- "eh",
- "ec3ww",
+ "v99cf",
+ "vecf",
+ "ecHl",
+ "e_h",
+ "uec3",
+ "vc3h",
"vec3h",
- "vecd99h",
- "ve99P",
- "KKec3",
- "ooMcDD",
- "vei",
- "vqi",
+ "EEtmec3h",
+ "vec",
+ "ec3rr",
+ "xc3i",
+ "vezz",
+ "vec3e",
"vec3i",
- "veL30",
- "vncvv66",
- "vrrn3",
- "vxxce",
- "NCCOc3u",
- "vc3u",
+ "uc3Zp",
+ "00uc7TT",
+ "vvJJ",
+ "vecQu",
+ "ve3R",
+ "e",
"vec3u",
- "aec4u",
- "NNc3NN",
- "ve3u",
- "vc",
- "vAYS4",
- "vec0",
+ "veprPP",
+ "xxeDD88u",
+ "lldmYYqqu",
+ "FFec4",
+ "rGecNN",
+ "Mecl",
"vec4",
- "vecaa",
- "mmcq",
- "vc4",
- "vE4U",
- "veKD4",
- "v0t4__",
+ "c",
+ "qxl4",
+ "ve4",
+ "ae44f",
+ "vec4WW",
+ "vecjj",
"vec4f",
- "cpA",
- "ec4f",
- "vBBc4f",
- "vbnn99",
- "EEcAAh",
- "v5c66h",
+ "vjjc4f",
+ "vj1f",
+ "vc4f",
+ "vec499",
+ "vyVV4h",
+ "ec4xZ",
"vec4h",
- "vHc4h",
- "vecxh",
- "vzyn40",
- "ve4i",
- "kH4i",
- "veci",
+ "v33vvh",
+ "vecs9",
+ "veF4",
+ "uec4i",
+ "eIKK",
+ "ve4J",
"vec4i",
- "oo4rr",
- "JJc4",
- "vcCC0",
- "xAA99F",
- "veccu",
- "vec4S",
+ "vSSCCXXi",
+ "JecWW6ZZ",
+ "ecd5",
+ "vBBcBU",
+ "JJ0c411",
+ "vecttu",
"vec4u",
- "vocBB",
- "ec4u",
- "veemm",
+ "vttc",
+ "veL4u",
+ "v1c4u",
};
for (auto _ : state) {
for (auto* str : kStrings) {
@@ -528,7 +710,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(BuiltinParser);
diff --git a/src/tint/builtin/builtin_test.cc b/src/tint/builtin/builtin_test.cc
index 9ff8d99..ab8c4c6 100644
--- a/src/tint/builtin/builtin_test.cc
+++ b/src/tint/builtin/builtin_test.cc
@@ -43,6 +43,32 @@
}
static constexpr Case kValidCases[] = {
+ {"__atomic_compare_exchange_result_i32", Builtin::kAtomicCompareExchangeResultI32},
+ {"__atomic_compare_exchange_result_u32", Builtin::kAtomicCompareExchangeResultU32},
+ {"__frexp_result_abstract", Builtin::kFrexpResultAbstract},
+ {"__frexp_result_f16", Builtin::kFrexpResultF16},
+ {"__frexp_result_f32", Builtin::kFrexpResultF32},
+ {"__frexp_result_vec2_abstract", Builtin::kFrexpResultVec2Abstract},
+ {"__frexp_result_vec2_f16", Builtin::kFrexpResultVec2F16},
+ {"__frexp_result_vec2_f32", Builtin::kFrexpResultVec2F32},
+ {"__frexp_result_vec3_abstract", Builtin::kFrexpResultVec3Abstract},
+ {"__frexp_result_vec3_f16", Builtin::kFrexpResultVec3F16},
+ {"__frexp_result_vec3_f32", Builtin::kFrexpResultVec3F32},
+ {"__frexp_result_vec4_abstract", Builtin::kFrexpResultVec4Abstract},
+ {"__frexp_result_vec4_f16", Builtin::kFrexpResultVec4F16},
+ {"__frexp_result_vec4_f32", Builtin::kFrexpResultVec4F32},
+ {"__modf_result_abstract", Builtin::kModfResultAbstract},
+ {"__modf_result_f16", Builtin::kModfResultF16},
+ {"__modf_result_f32", Builtin::kModfResultF32},
+ {"__modf_result_vec2_abstract", Builtin::kModfResultVec2Abstract},
+ {"__modf_result_vec2_f16", Builtin::kModfResultVec2F16},
+ {"__modf_result_vec2_f32", Builtin::kModfResultVec2F32},
+ {"__modf_result_vec3_abstract", Builtin::kModfResultVec3Abstract},
+ {"__modf_result_vec3_f16", Builtin::kModfResultVec3F16},
+ {"__modf_result_vec3_f32", Builtin::kModfResultVec3F32},
+ {"__modf_result_vec4_abstract", Builtin::kModfResultVec4Abstract},
+ {"__modf_result_vec4_f16", Builtin::kModfResultVec4F16},
+ {"__modf_result_vec4_f32", Builtin::kModfResultVec4F32},
{"__packed_vec3", Builtin::kPackedVec3},
{"array", Builtin::kArray},
{"atomic", Builtin::kAtomic},
@@ -116,216 +142,294 @@
};
static constexpr Case kInvalidCases[] = {
- {"__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},
- {"316", Builtin::kUndefined},
- {"fE2", Builtin::kUndefined},
- {"fPTT", Builtin::kUndefined},
- {"dxx2", 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},
- {"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},
- {"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},
- {"matx4h", Builtin::kUndefined},
- {"mrrt2x4h", Builtin::kUndefined},
- {"Gat2x4h", Builtin::kUndefined},
- {"matFFx2", Builtin::kUndefined},
- {"mtx", Builtin::kUndefined},
- {"mrrt3x", Builtin::kUndefined},
+ {"__atomic_compareexchangeccresult_i32", Builtin::kUndefined},
+ {"__atoml3_compare_exchane_resulti2", Builtin::kUndefined},
+ {"__atomic_compare_Vxchange_result_i32", Builtin::kUndefined},
+ {"__atomic_com1are_exchange_result_u32", Builtin::kUndefined},
+ {"__atomic_qqompare_exchage_resulJ_u32", Builtin::kUndefined},
+ {"__atllmic_compare_exchange_result_u377", Builtin::kUndefined},
+ {"qpp_frexp_resultHHbstract", Builtin::kUndefined},
+ {"__fep_esulv_abstract", Builtin::kUndefined},
+ {"__Gbexp_resul_abstract", Builtin::kUndefined},
+ {"_vfrexp_resiilt_f16", Builtin::kUndefined},
+ {"__fr8xp_resultWWf16", Builtin::kUndefined},
+ {"__frxp_result_fMxx", Builtin::kUndefined},
+ {"gg_fXexp_reslt_f32", Builtin::kUndefined},
+ {"__frXxpresul_V32", Builtin::kUndefined},
+ {"__frexp_r3sult_f32", Builtin::kUndefined},
+ {"__frexpEresult_vec2_abstract", Builtin::kUndefined},
+ {"__frex_rPPsult_vTTc2_abstract", Builtin::kUndefined},
+ {"__frexp_resuddt_ec2_xxbstract", Builtin::kUndefined},
+ {"__frexp_result_ve442_f16", Builtin::kUndefined},
+ {"_SSfrexp_resulVV_vec2_f16", Builtin::kUndefined},
+ {"__fRxpRr22sult_vec2_f16", Builtin::kUndefined},
+ {"__frexp_res9lt_vec_fF2", Builtin::kUndefined},
+ {"__frexp_result_ve2_f32", Builtin::kUndefined},
+ {"_OOfrexp_result_VeHRRf32", Builtin::kUndefined},
+ {"__frexp_reyult_vec3_absract", Builtin::kUndefined},
+ {"__frexp_re77ulll_vecG_arrnstract", Builtin::kUndefined},
+ {"__4rexp_result_vec3_00bstract", Builtin::kUndefined},
+ {"__oorxp_result_vec316", Builtin::kUndefined},
+ {"zz_frexp_esult_ec3_f16", Builtin::kUndefined},
+ {"__iirex11_result_vp3_f16", Builtin::kUndefined},
+ {"__frXXxp_result_vec3_f32", Builtin::kUndefined},
+ {"__fnnexp99resIIlt_vec3_f355", Builtin::kUndefined},
+ {"__faSSerrp_result_vHHc3_fY2", Builtin::kUndefined},
+ {"__freHp_resutve4_abstkkact", Builtin::kUndefined},
+ {"jfrexpgresult_veRR4_abstrac", Builtin::kUndefined},
+ {"__frexp_resul_vec4_absbrac", Builtin::kUndefined},
+ {"_jfrexp_result_vec4_f16", Builtin::kUndefined},
+ {"__frexp_resultvec4_f16", Builtin::kUndefined},
+ {"__freqpresultvec4_f16", Builtin::kUndefined},
+ {"__frexNN_result_vec_f32", Builtin::kUndefined},
+ {"__frexp_resvvlt_vc4_f3", Builtin::kUndefined},
+ {"__frexp_esult_vec4_f3QQ", Builtin::kUndefined},
+ {"rmodf_reffultabstract", Builtin::kUndefined},
+ {"__jodf_result_abstract", Builtin::kUndefined},
+ {"_mNNwdf_r2sult8abstract", Builtin::kUndefined},
+ {"__mdf_result_f16", Builtin::kUndefined},
+ {"__modrr_result_f16", Builtin::kUndefined},
+ {"__mGdf_result_f16", Builtin::kUndefined},
+ {"__modf_resulFF_f32", Builtin::kUndefined},
+ {"__modf_eult_E3", Builtin::kUndefined},
+ {"__odf_resurrt_f32", Builtin::kUndefined},
+ {"__modf_reslt_vec_abstract", Builtin::kUndefined},
+ {"__modfJJresuDt_Xc2_abstract", Builtin::kUndefined},
+ {"_modf_reslt_vec28abstrct", Builtin::kUndefined},
+ {"__odf_reult_vkc211f1", Builtin::kUndefined},
+ {"__mdf_result_vec2_f16", Builtin::kUndefined},
+ {"__modf_resuJt_vec2_f6", Builtin::kUndefined},
+ {"__modf_result_vec2cf32", Builtin::kUndefined},
+ {"__modf_result_vec2_fO2", Builtin::kUndefined},
+ {"KK_movvf_result_vec2_ftt__", Builtin::kUndefined},
+ {"xx_modf_r8sult_vec3_abtr5ct", Builtin::kUndefined},
+ {"__modf_resuFt_vec3_aqt__act", Builtin::kUndefined},
+ {"__modf_result_vec3_aqqstrac", Builtin::kUndefined},
+ {"__odf_33esult_vec3_f1O6", Builtin::kUndefined},
+ {"_ttm6df_resQQlt_ooec9_f16", Builtin::kUndefined},
+ {"_modf_resu66t_vec3_f16", Builtin::kUndefined},
+ {"__mdf_resultOvxc3_f36zz", Builtin::kUndefined},
+ {"__modf_resuyyt_vec3_f32", Builtin::kUndefined},
+ {"__mod_resul_vecZHHf32", Builtin::kUndefined},
+ {"__modf_reqult_44ec4WWbstract", Builtin::kUndefined},
+ {"__mof_result_vec4_abstrOOct", Builtin::kUndefined},
+ {"__modYooresult_vh4_bstract", Builtin::kUndefined},
+ {"__modf_relt_ve4_f16", Builtin::kUndefined},
+ {"__modf_result_ve4Ff16", Builtin::kUndefined},
+ {"__modf_result_wec4_f1", Builtin::kUndefined},
+ {"__Kdff_rGsult_vec4_f2", Builtin::kUndefined},
+ {"__modf_reKKulq_vec4_f32", Builtin::kUndefined},
+ {"__modf_resummt3vec4_f3F", Builtin::kUndefined},
+ {"__packed_ec3", Builtin::kUndefined},
+ {"__packed_ecq", Builtin::kUndefined},
+ {"_backed_bbec3", Builtin::kUndefined},
+ {"iira", Builtin::kUndefined},
+ {"aqOOy", Builtin::kUndefined},
+ {"arvvTTy", Builtin::kUndefined},
+ {"atomFFc", Builtin::kUndefined},
+ {"aoQ00P", Builtin::kUndefined},
+ {"atPmic", Builtin::kUndefined},
+ {"bos77", Builtin::kUndefined},
+ {"CoRbbl", Builtin::kUndefined},
+ {"booXX", Builtin::kUndefined},
+ {"qOOO6", Builtin::kUndefined},
+ {"fs", Builtin::kUndefined},
+ {"f1X", Builtin::kUndefined},
+ {"f3", Builtin::kUndefined},
+ {"q", Builtin::kUndefined},
+ {"f322", Builtin::kUndefined},
+ {"0yz2", Builtin::kUndefined},
+ {"iVP", Builtin::kUndefined},
+ {"Cnn", Builtin::kUndefined},
+ {"AtqqHH2", Builtin::kUndefined},
+ {"at2x2", Builtin::kUndefined},
+ {"mafKK", Builtin::kUndefined},
+ {"ltgg2f", Builtin::kUndefined},
+ {"mat2xf", Builtin::kUndefined},
+ {"NTTtcx4f", Builtin::kUndefined},
+ {"ma7ppl2h", Builtin::kUndefined},
+ {"mNNt2xg", Builtin::kUndefined},
+ {"uub2XX2h", Builtin::kUndefined},
+ {"mt2x3", Builtin::kUndefined},
+ {"m88xK", Builtin::kUndefined},
+ {"maqx3", Builtin::kUndefined},
+ {"m11t2x3f", Builtin::kUndefined},
+ {"22at2iif", Builtin::kUndefined},
+ {"at2x377", Builtin::kUndefined},
+ {"m2t2xNh", Builtin::kUndefined},
+ {"mVVt2x3h", Builtin::kUndefined},
+ {"FaWW2w11h", Builtin::kUndefined},
+ {"matww4", Builtin::kUndefined},
+ {"mat2D4", Builtin::kUndefined},
+ {"maKx4", Builtin::kUndefined},
+ {"mat21PPhf", Builtin::kUndefined},
+ {"mat24f", Builtin::kUndefined},
+ {"mYYt2x4f", Builtin::kUndefined},
+ {"mttHH4kk", Builtin::kUndefined},
+ {"mat2rr4h", Builtin::kUndefined},
+ {"WWas2x4h", Builtin::kUndefined},
+ {"maYx2", Builtin::kUndefined},
+ {"mq3f2", Builtin::kUndefined},
+ {"vvafu222", Builtin::kUndefined},
{"t3x2f", Builtin::kUndefined},
- {"Da3xJJf", Builtin::kUndefined},
- {"ma82", 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},
- {"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},
- {"mi4x2h", Builtin::kUndefined},
- {"maOO4xq", Builtin::kUndefined},
- {"matTvvx2h", Builtin::kUndefined},
- {"mat4FF3", Builtin::kUndefined},
- {"mtQ00P", Builtin::kUndefined},
- {"maP4x3", Builtin::kUndefined},
- {"ma774xss", 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},
- {"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},
- {"5eFF2h", Builtin::kUndefined},
- {"rrecz44", Builtin::kUndefined},
- {"vWW", 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},
- {"v3dc4h", Builtin::kUndefined},
- {"vcyyh", Builtin::kUndefined},
- {"u4", Builtin::kUndefined},
- {"v03nni", Builtin::kUndefined},
- {"Cuuecnv", Builtin::kUndefined},
- {"vX4ll", Builtin::kUndefined},
- {"vocppu", Builtin::kUndefined},
- {"vwwc4", Builtin::kUndefined},
- {"veuug", Builtin::kUndefined},
+ {"YYat3f", Builtin::kUndefined},
+ {"may3x2EYY", Builtin::kUndefined},
+ {"da3xMoh", Builtin::kUndefined},
+ {"matMMx2", Builtin::kUndefined},
+ {"mat3x55h", Builtin::kUndefined},
+ {"maN3", Builtin::kUndefined},
+ {"ma33x3", Builtin::kUndefined},
+ {"mt3x3", Builtin::kUndefined},
+ {"mm66Issf", Builtin::kUndefined},
+ {"mat3x1f", Builtin::kUndefined},
+ {"Xt3x3", Builtin::kUndefined},
+ {"LatIx3h", Builtin::kUndefined},
+ {"at3fh", Builtin::kUndefined},
+ {"mYtURD3", Builtin::kUndefined},
+ {"mah3x4", Builtin::kUndefined},
+ {"muqII4", Builtin::kUndefined},
+ {"mat3xH", Builtin::kUndefined},
+ {"at3QQvv", Builtin::kUndefined},
+ {"at66ef", Builtin::kUndefined},
+ {"ma7O4f", Builtin::kUndefined},
+ {"m55t3x0DD", Builtin::kUndefined},
+ {"maH3x4II", Builtin::kUndefined},
+ {"at3x4", Builtin::kUndefined},
+ {"ma994x2", Builtin::kUndefined},
+ {"mWWt4Gt2", Builtin::kUndefined},
+ {"ay42", Builtin::kUndefined},
+ {"mt4x2f", Builtin::kUndefined},
+ {"IIaBB4x2f", Builtin::kUndefined},
+ {"TTat4x833", Builtin::kUndefined},
+ {"ddUUnntYYx2h", Builtin::kUndefined},
+ {"m5CCxxdZ", Builtin::kUndefined},
+ {"matkkq2h", Builtin::kUndefined},
+ {"5iitp00", Builtin::kUndefined},
+ {"mnntIIx3", Builtin::kUndefined},
+ {"ccaKx", Builtin::kUndefined},
+ {"m43KK", Builtin::kUndefined},
+ {"mat66x3f", Builtin::kUndefined},
+ {"Et4PP3K", Builtin::kUndefined},
+ {"xxatx3h", Builtin::kUndefined},
+ {"qat4x3h", Builtin::kUndefined},
+ {"MMayySrxh", Builtin::kUndefined},
+ {"uat4", Builtin::kUndefined},
+ {"tx4", Builtin::kUndefined},
+ {"ma54FF4", Builtin::kUndefined},
+ {"rra444z4f", Builtin::kUndefined},
+ {"matWW", Builtin::kUndefined},
+ {"CatZJXx4f", Builtin::kUndefined},
+ {"maPPx4h", Builtin::kUndefined},
+ {"mat4c4h", Builtin::kUndefined},
+ {"matPPll6h", Builtin::kUndefined},
+ {"9tyy", Builtin::kUndefined},
+ {"ptKK", Builtin::kUndefined},
+ {"x_", Builtin::kUndefined},
+ {"ayKer", Builtin::kUndefined},
+ {"szmpVek", Builtin::kUndefined},
+ {"sampqeK", Builtin::kUndefined},
+ {"sampler_comparisn", Builtin::kUndefined},
+ {"sapler_comparisVVn", Builtin::kUndefined},
+ {"samplerIcompaAUison", Builtin::kUndefined},
+ {"jexurbRd", Builtin::kUndefined},
+ {"exure_YYd", Builtin::kUndefined},
+ {"exture_1d", Builtin::kUndefined},
+ {"texxxur_1d", Builtin::kUndefined},
+ {"tJxucce_2d", Builtin::kUndefined},
+ {"texure_JJd", Builtin::kUndefined},
+ {"lDexture_fCC_arraU", Builtin::kUndefined},
+ {"tegture_2d_array", Builtin::kUndefined},
+ {"teCCure2d_arra", Builtin::kUndefined},
+ {"textue_3d", Builtin::kUndefined},
+ {"tIx__ure_3d", Builtin::kUndefined},
+ {"texurettPP", Builtin::kUndefined},
+ {"tddx3ure_cube", Builtin::kUndefined},
+ {"teKyyur_cube", Builtin::kUndefined},
+ {"teturecub", Builtin::kUndefined},
+ {"textinne_c03e_array", Builtin::kUndefined},
+ {"nextCCruuvcubK_array", Builtin::kUndefined},
+ {"tXxturellcbe_array", Builtin::kUndefined},
+ {"tppxture_depth_2d", Builtin::kUndefined},
+ {"txture_deptww_2d", Builtin::kUndefined},
+ {"gexturedemmthuu2", Builtin::kUndefined},
+ {"texmmre_depthaa2daray", Builtin::kUndefined},
+ {"texture_RRepth_Td_ccZray", Builtin::kUndefined},
+ {"text88re_depthTOd_array", Builtin::kUndefined},
+ {"texture_depth_cm00e", Builtin::kUndefined},
+ {"texture_Bmepth_cube", Builtin::kUndefined},
+ {"Mextre_ppeph_cube", Builtin::kUndefined},
+ {"texturOO_depth_cub_array", Builtin::kUndefined},
+ {"GeGGture_depthcube_array", Builtin::kUndefined},
+ {"texture11Hdepth_cube_array", Builtin::kUndefined},
+ {"textu6e_FFepth_multiameeled_2d", Builtin::kUndefined},
+ {"texture_epth_mltisampled_2d", Builtin::kUndefined},
+ {"texture_depth_mullKsaiipled_2d", Builtin::kUndefined},
+ {"texture_extenal", Builtin::kUndefined},
+ {"IIext99reexvvernal", Builtin::kUndefined},
+ {"texture_externl", Builtin::kUndefined},
+ {"texture_mhltisampled_2d", Builtin::kUndefined},
+ {"texturemPllltisampzzed_2d", Builtin::kUndefined},
+ {"exture_mltisamed_2d", Builtin::kUndefined},
+ {"texture_qqtoragff_1", Builtin::kUndefined},
+ {"textre_JJddorage_1W", Builtin::kUndefined},
+ {"XXrxture_storae1zz", Builtin::kUndefined},
+ {"texturestorag2_2d", Builtin::kUndefined},
+ {"yyNxture_storage_2d", Builtin::kUndefined},
+ {"etue_storage_2OO", Builtin::kUndefined},
+ {"reutuPe_storZgeE2d_array", Builtin::kUndefined},
+ {"texlure_storddeee_d_22rray", Builtin::kUndefined},
+ {"texture_mtorage_2V_a9ra", Builtin::kUndefined},
+ {"teII1re_storage_3d", Builtin::kUndefined},
+ {"texture_storagb_3d", Builtin::kUndefined},
+ {"texizrestorge73d", Builtin::kUndefined},
+ {"u3oi", Builtin::kUndefined},
+ {"3", Builtin::kUndefined},
+ {"S2", Builtin::kUndefined},
+ {"e22", Builtin::kUndefined},
+ {"1eC2", Builtin::kUndefined},
+ {"vf8c2", Builtin::kUndefined},
+ {"c2f", Builtin::kUndefined},
+ {"JJecSSf", Builtin::kUndefined},
+ {"92f", Builtin::kUndefined},
+ {"vbbJJ2TT", Builtin::kUndefined},
+ {"e66h", Builtin::kUndefined},
+ {"u662h", Builtin::kUndefined},
+ {"vW2i", Builtin::kUndefined},
+ {"v2i", Builtin::kUndefined},
+ {"veci", Builtin::kUndefined},
+ {"rec2u", Builtin::kUndefined},
+ {"2ec2B", Builtin::kUndefined},
+ {"vcBBu", Builtin::kUndefined},
+ {"veRR", Builtin::kUndefined},
+ {"VLL0", Builtin::kUndefined},
+ {"KOe3", Builtin::kUndefined},
+ {"vgwcf", Builtin::kUndefined},
+ {"vLphf", Builtin::kUndefined},
+ {"eiiEf", Builtin::kUndefined},
+ {"ec3h", Builtin::kUndefined},
+ {"UU883", Builtin::kUndefined},
+ {"rrecvvh", Builtin::kUndefined},
+ {"ecmm", Builtin::kUndefined},
+ {"vec4j", Builtin::kUndefined},
+ {"vec3X", Builtin::kUndefined},
+ {"vec38", Builtin::kUndefined},
+ {"vecvEE", Builtin::kUndefined},
+ {"z99ci", Builtin::kUndefined},
+ {"JJGeQQ4", Builtin::kUndefined},
+ {"ssec4", Builtin::kUndefined},
+ {"PecK", Builtin::kUndefined},
+ {"tpc4f", Builtin::kUndefined},
+ {"vec", Builtin::kUndefined},
+ {"MMec4f", Builtin::kUndefined},
+ {"vJJc40", Builtin::kUndefined},
+ {"8c", Builtin::kUndefined},
+ {"vecggKh", Builtin::kUndefined},
+ {"vecfi", Builtin::kUndefined},
+ {"vec47Q", Builtin::kUndefined},
+ {"veY4i", Builtin::kUndefined},
+ {"keSu", Builtin::kUndefined},
+ {"n422", Builtin::kUndefined},
+ {"vFFu", Builtin::kUndefined},
};
using BuiltinParseTest = testing::TestWithParam<Case>;
diff --git a/src/tint/builtin/builtin_value_bench.cc b/src/tint/builtin/builtin_value_bench.cc
index 4d2e562..28c01ac 100644
--- a/src/tint/builtin/builtin_value_bench.cc
+++ b/src/tint/builtin/builtin_value_bench.cc
@@ -129,7 +129,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(BuiltinValueParser);
diff --git a/src/tint/builtin/diagnostic_rule_bench.cc b/src/tint/builtin/diagnostic_rule_bench.cc
index fb60580..efa6977 100644
--- a/src/tint/builtin/diagnostic_rule_bench.cc
+++ b/src/tint/builtin/diagnostic_rule_bench.cc
@@ -41,7 +41,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(CoreDiagnosticRuleParser);
@@ -56,7 +56,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(ChromiumDiagnosticRuleParser);
diff --git a/src/tint/builtin/diagnostic_severity_bench.cc b/src/tint/builtin/diagnostic_severity_bench.cc
index 13c3ff1..35fe046 100644
--- a/src/tint/builtin/diagnostic_severity_bench.cc
+++ b/src/tint/builtin/diagnostic_severity_bench.cc
@@ -42,7 +42,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(DiagnosticSeverityParser);
diff --git a/src/tint/builtin/extension_bench.cc b/src/tint/builtin/extension_bench.cc
index b3e410e..7a50281 100644
--- a/src/tint/builtin/extension_bench.cc
+++ b/src/tint/builtin/extension_bench.cc
@@ -80,7 +80,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(ExtensionParser);
diff --git a/src/tint/builtin/interpolation.h b/src/tint/builtin/interpolation.h
new file mode 100644
index 0000000..ad73c30
--- /dev/null
+++ b/src/tint/builtin/interpolation.h
@@ -0,0 +1,33 @@
+// 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_BUILTIN_INTERPOLATION_H_
+#define SRC_TINT_BUILTIN_INTERPOLATION_H_
+
+#include "src/tint/builtin/interpolation_sampling.h"
+#include "src/tint/builtin/interpolation_type.h"
+
+namespace tint::builtin {
+
+/// The values of an `@interpolate` attribute
+struct Interpolation {
+ /// The first argument of a `@interpolate` attribute
+ builtin::InterpolationType type = builtin::InterpolationType::kUndefined;
+ /// The second argument of a `@interpolate` attribute
+ builtin::InterpolationSampling sampling = builtin::InterpolationSampling::kUndefined;
+};
+
+} // namespace tint::builtin
+
+#endif // SRC_TINT_BUILTIN_INTERPOLATION_H_
diff --git a/src/tint/builtin/interpolation_sampling_bench.cc b/src/tint/builtin/interpolation_sampling_bench.cc
index 4fb7e09..deb4de0 100644
--- a/src/tint/builtin/interpolation_sampling_bench.cc
+++ b/src/tint/builtin/interpolation_sampling_bench.cc
@@ -40,7 +40,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(InterpolationSamplingParser);
diff --git a/src/tint/builtin/interpolation_type_bench.cc b/src/tint/builtin/interpolation_type_bench.cc
index 5098f26..70b5961 100644
--- a/src/tint/builtin/interpolation_type_bench.cc
+++ b/src/tint/builtin/interpolation_type_bench.cc
@@ -43,7 +43,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(InterpolationTypeParser);
diff --git a/src/tint/builtin/texel_format_bench.cc b/src/tint/builtin/texel_format_bench.cc
index 5d202ea..0773b9a 100644
--- a/src/tint/builtin/texel_format_bench.cc
+++ b/src/tint/builtin/texel_format_bench.cc
@@ -62,7 +62,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK(TexelFormatParser);
diff --git a/src/tint/cmd/loopy.cc b/src/tint/cmd/loopy.cc
index 1714e3b..75102eb 100644
--- a/src/tint/cmd/loopy.cc
+++ b/src/tint/cmd/loopy.cc
@@ -19,6 +19,7 @@
#include "tint/tint.h"
#if TINT_BUILD_IR
+#include "src/tint/ir/converter.h"
#include "src/tint/ir/module.h"
#endif // TINT_BUILD_IR
@@ -377,7 +378,7 @@
loop_count = options.loop_count;
}
for (uint32_t i = 0; i < loop_count; ++i) {
- auto result = tint::ir::Module::FromProgram(program.get());
+ auto result = tint::ir::Converter::FromProgram(program.get());
if (!result) {
std::cerr << "Failed to build IR from program: " << result.Failure() << std::endl;
}
diff --git a/src/tint/cmd/main.cc b/src/tint/cmd/main.cc
index d61ae24..c8260f1 100644
--- a/src/tint/cmd/main.cc
+++ b/src/tint/cmd/main.cc
@@ -49,10 +49,11 @@
#include "tint/tint.h"
#if TINT_BUILD_IR
-#include "src/tint/ir/debug.h"
-#include "src/tint/ir/disassembler.h"
-#include "src/tint/ir/module.h"
-#endif // TINT_BUILD_IR
+#include "src/tint/ir/converter.h" // nogncheck
+#include "src/tint/ir/debug.h" // nogncheck
+#include "src/tint/ir/disassembler.h" // nogncheck
+#include "src/tint/ir/module.h" // nogncheck
+#endif // TINT_BUILD_IR
namespace {
@@ -1078,7 +1079,7 @@
#if TINT_BUILD_IR
if (options.dump_ir || options.dump_ir_graph) {
- auto result = tint::ir::Module::FromProgram(program.get());
+ auto result = tint::ir::Converter::FromProgram(program.get());
if (!result) {
std::cerr << "Failed to build IR from program: " << result.Failure() << std::endl;
} else {
diff --git a/src/tint/inspector/inspector.cc b/src/tint/inspector/inspector.cc
index 246943d..adafe3a 100644
--- a/src/tint/inspector/inspector.cc
+++ b/src/tint/inspector/inspector.cc
@@ -621,8 +621,8 @@
// Recurse into members.
for (auto* member : struct_ty->Members()) {
AddEntryPointInOutVariables(name + "." + member->Name().Name(), member->Type(),
- member->Declaration()->attributes, member->Location(),
- variables);
+ member->Declaration()->attributes,
+ member->Attributes().location, variables);
}
return;
}
diff --git a/src/tint/intrinsics.def b/src/tint/intrinsics.def
index ee4b517..0d667ab 100644
--- a/src/tint/intrinsics.def
+++ b/src/tint/intrinsics.def
@@ -218,6 +218,32 @@
// Internal types.
__packed_vec3
+ __atomic_compare_exchange_result_i32
+ __atomic_compare_exchange_result_u32
+ __frexp_result_abstract
+ __frexp_result_f16
+ __frexp_result_f32
+ __frexp_result_vec2_abstract
+ __frexp_result_vec2_f16
+ __frexp_result_vec2_f32
+ __frexp_result_vec3_abstract
+ __frexp_result_vec3_f16
+ __frexp_result_vec3_f32
+ __frexp_result_vec4_abstract
+ __frexp_result_vec4_f16
+ __frexp_result_vec4_f32
+ __modf_result_abstract
+ __modf_result_f16
+ __modf_result_f32
+ __modf_result_vec2_abstract
+ __modf_result_vec2_f16
+ __modf_result_vec2_f32
+ __modf_result_vec3_abstract
+ __modf_result_vec3_f16
+ __modf_result_vec3_f32
+ __modf_result_vec4_abstract
+ __modf_result_vec4_f16
+ __modf_result_vec4_f32
}
// https://gpuweb.github.io/gpuweb/wgsl/#attributes
diff --git a/src/tint/ir/binary.cc b/src/tint/ir/binary.cc
index 6cbf742..d3e3548 100644
--- a/src/tint/ir/binary.cc
+++ b/src/tint/ir/binary.cc
@@ -19,8 +19,8 @@
namespace tint::ir {
-Binary::Binary(Kind kind, Value* result, Value* lhs, Value* rhs)
- : Base(result), kind_(kind), lhs_(lhs), rhs_(rhs) {
+Binary::Binary(uint32_t id, Kind kind, const type::Type* ty, Value* lhs, Value* rhs)
+ : Base(id, ty), kind_(kind), lhs_(lhs), rhs_(rhs) {
TINT_ASSERT(IR, lhs_);
TINT_ASSERT(IR, rhs_);
lhs_->AddUsage(this);
@@ -29,69 +29,68 @@
Binary::~Binary() = default;
-utils::StringStream& Binary::ToString(utils::StringStream& out) const {
- Result()->ToString(out) << " = ";
- lhs_->ToString(out) << " ";
+utils::StringStream& Binary::ToInstruction(utils::StringStream& out) const {
+ ToValue(out) << " = ";
switch (GetKind()) {
case Binary::Kind::kAdd:
- out << "+";
+ out << "add";
break;
case Binary::Kind::kSubtract:
- out << "-";
+ out << "sub";
break;
case Binary::Kind::kMultiply:
- out << "*";
+ out << "mul";
break;
case Binary::Kind::kDivide:
- out << "/";
+ out << "div";
break;
case Binary::Kind::kModulo:
- out << "%";
+ out << "mod";
break;
case Binary::Kind::kAnd:
- out << "&";
+ out << "bit_and";
break;
case Binary::Kind::kOr:
- out << "|";
+ out << "bit_or";
break;
case Binary::Kind::kXor:
- out << "^";
+ out << "bit_xor";
break;
case Binary::Kind::kLogicalAnd:
- out << "&&";
+ out << "log_and";
break;
case Binary::Kind::kLogicalOr:
- out << "||";
+ out << "log_or";
break;
case Binary::Kind::kEqual:
- out << "==";
+ out << "eq";
break;
case Binary::Kind::kNotEqual:
- out << "!=";
+ out << "neq";
break;
case Binary::Kind::kLessThan:
- out << "<";
+ out << "lt";
break;
case Binary::Kind::kGreaterThan:
- out << ">";
+ out << "gt";
break;
case Binary::Kind::kLessThanEqual:
- out << "<=";
+ out << "lte";
break;
case Binary::Kind::kGreaterThanEqual:
- out << ">=";
+ out << "gte";
break;
case Binary::Kind::kShiftLeft:
- out << "<<";
+ out << "shiftl";
break;
case Binary::Kind::kShiftRight:
- out << ">>";
+ out << "shiftr";
break;
}
out << " ";
- rhs_->ToString(out);
-
+ lhs_->ToValue(out) << ", ";
+ rhs_->ToValue(out);
return out;
}
diff --git a/src/tint/ir/binary.h b/src/tint/ir/binary.h
index 400e381..92a1998 100644
--- a/src/tint/ir/binary.h
+++ b/src/tint/ir/binary.h
@@ -51,17 +51,18 @@
};
/// Constructor
+ /// @param id the instruction id
/// @param kind the kind of binary instruction
- /// @param result the result value
+ /// @param type the result type
/// @param lhs the lhs of the instruction
/// @param rhs the rhs of the instruction
- Binary(Kind kind, Value* result, Value* lhs, Value* rhs);
- Binary(const Binary& instr) = delete;
- Binary(Binary&& instr) = delete;
+ Binary(uint32_t id, Kind kind, const type::Type* type, Value* lhs, Value* rhs);
+ Binary(const Binary& inst) = delete;
+ Binary(Binary&& inst) = delete;
~Binary() override;
- Binary& operator=(const Binary& instr) = delete;
- Binary& operator=(Binary&& instr) = delete;
+ Binary& operator=(const Binary& inst) = delete;
+ Binary& operator=(Binary&& inst) = delete;
/// @returns the kind of instruction
Kind GetKind() const { return kind_; }
@@ -75,7 +76,7 @@
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
- utils::StringStream& ToString(utils::StringStream& out) const override;
+ utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
Kind kind_;
diff --git a/src/tint/ir/binary_test.cc b/src/tint/ir/binary_test.cc
index 6be82f9..e03a61d 100644
--- a/src/tint/ir/binary_test.cc
+++ b/src/tint/ir/binary_test.cc
@@ -20,537 +20,469 @@
namespace {
using namespace tint::number_suffixes; // NOLINT
- //
+
using IR_InstructionTest = TestHelper;
TEST_F(IR_InstructionTest, CreateAnd) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.And(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
- b.builder.Constant(2_i));
+ const auto* inst = b.builder.And(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
+ b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kAnd);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kAnd);
+ ASSERT_NE(inst->Type(), nullptr);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- ASSERT_NE(instr->Result()->Type(), nullptr);
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = 4 & 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = bit_and 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateOr) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.Or(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
- b.builder.Constant(2_i));
+ const auto* inst = b.builder.Or(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
+ b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kOr);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kOr);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = 4 | 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = bit_or 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateXor) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.Xor(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
- b.builder.Constant(2_i));
+ const auto* inst = b.builder.Xor(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
+ b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kXor);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kXor);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = 4 ^ 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = bit_xor 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateLogicalAnd) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.LogicalAnd(b.builder.ir.types.Get<type::Bool>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.LogicalAnd(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kLogicalAnd);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kLogicalAnd);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (bool) = 4 && 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(bool) = log_and 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateLogicalOr) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.LogicalOr(b.builder.ir.types.Get<type::Bool>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.LogicalOr(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kLogicalOr);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kLogicalOr);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (bool) = 4 || 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(bool) = log_or 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateEqual) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.Equal(b.builder.ir.types.Get<type::Bool>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.Equal(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kEqual);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kEqual);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (bool) = 4 == 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(bool) = eq 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateNotEqual) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.NotEqual(b.builder.ir.types.Get<type::Bool>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.NotEqual(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kNotEqual);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kNotEqual);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (bool) = 4 != 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(bool) = neq 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateLessThan) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.LessThan(b.builder.ir.types.Get<type::Bool>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.LessThan(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kLessThan);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kLessThan);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (bool) = 4 < 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(bool) = lt 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateGreaterThan) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.GreaterThan(b.builder.ir.types.Get<type::Bool>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.GreaterThan(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kGreaterThan);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kGreaterThan);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (bool) = 4 > 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(bool) = gt 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateLessThanEqual) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.LessThanEqual(b.builder.ir.types.Get<type::Bool>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.LessThanEqual(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kLessThanEqual);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kLessThanEqual);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (bool) = 4 <= 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(bool) = lte 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.GreaterThanEqual(
- b.builder.ir.types.Get<type::Bool>(), b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.GreaterThanEqual(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kGreaterThanEqual);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kGreaterThanEqual);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (bool) = 4 >= 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(bool) = gte 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateShiftLeft) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.ShiftLeft(b.builder.ir.types.Get<type::I32>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.ShiftLeft(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kShiftLeft);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kShiftLeft);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = 4 << 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = shiftl 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateShiftRight) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.ShiftRight(b.builder.ir.types.Get<type::I32>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.ShiftRight(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kShiftRight);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kShiftRight);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = 4 >> 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = shiftr 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateAdd) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.Add(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
- b.builder.Constant(2_i));
+ const auto* inst = b.builder.Add(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
+ b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kAdd);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kAdd);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = 4 + 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = add 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateSubtract) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.Subtract(b.builder.ir.types.Get<type::I32>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.Subtract(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kSubtract);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kSubtract);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = 4 - 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = sub 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateMultiply) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.Multiply(b.builder.ir.types.Get<type::I32>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.Multiply(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kMultiply);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kMultiply);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = 4 * 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = mul 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateDivide) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.Divide(b.builder.ir.types.Get<type::I32>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.Divide(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kDivide);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kDivide);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = 4 / 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = div 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateModulo) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.Modulo(b.builder.ir.types.Get<type::I32>(),
- b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* inst = b.builder.Modulo(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kModulo);
+ ASSERT_TRUE(inst->Is<Binary>());
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kModulo);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->LHS()->Is<Constant>());
+ auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>()->value;
+ ASSERT_TRUE(inst->RHS()->Is<Constant>());
+ auto rhs = inst->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = 4 % 2");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = mod 4i, 2i");
}
TEST_F(IR_InstructionTest, Binary_Usage) {
auto& b = CreateEmptyBuilder();
+ const auto* inst = b.builder.And(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
+ b.builder.Constant(2_i));
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.And(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
- b.builder.Constant(2_i));
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kAnd);
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kAnd);
+ ASSERT_NE(inst->LHS(), nullptr);
+ ASSERT_EQ(inst->LHS()->Usage().Length(), 1u);
+ EXPECT_EQ(inst->LHS()->Usage()[0], inst);
- ASSERT_NE(instr->Result(), nullptr);
- ASSERT_EQ(instr->Result()->Usage().Length(), 1u);
- EXPECT_EQ(instr->Result()->Usage()[0], instr);
-
- ASSERT_NE(instr->LHS(), nullptr);
- ASSERT_EQ(instr->LHS()->Usage().Length(), 1u);
- EXPECT_EQ(instr->LHS()->Usage()[0], instr);
-
- ASSERT_NE(instr->RHS(), nullptr);
- ASSERT_EQ(instr->RHS()->Usage().Length(), 1u);
- EXPECT_EQ(instr->RHS()->Usage()[0], instr);
+ ASSERT_NE(inst->RHS(), nullptr);
+ ASSERT_EQ(inst->RHS()->Usage().Length(), 1u);
+ EXPECT_EQ(inst->RHS()->Usage()[0], inst);
}
TEST_F(IR_InstructionTest, Binary_Usage_DuplicateValue) {
auto& b = CreateEmptyBuilder();
-
auto val = b.builder.Constant(4_i);
+ const auto* inst = b.builder.And(b.builder.ir.types.Get<type::I32>(), val, val);
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.And(b.builder.ir.types.Get<type::I32>(), val, val);
+ EXPECT_EQ(inst->GetKind(), Binary::Kind::kAnd);
+ ASSERT_EQ(inst->LHS(), inst->RHS());
- EXPECT_EQ(instr->GetKind(), Binary::Kind::kAnd);
-
- ASSERT_NE(instr->Result(), nullptr);
- ASSERT_EQ(instr->Result()->Usage().Length(), 1u);
- EXPECT_EQ(instr->Result()->Usage()[0], instr);
-
- ASSERT_EQ(instr->LHS(), instr->RHS());
-
- ASSERT_NE(instr->LHS(), nullptr);
- ASSERT_EQ(instr->LHS()->Usage().Length(), 1u);
- EXPECT_EQ(instr->LHS()->Usage()[0], instr);
+ ASSERT_NE(inst->LHS(), nullptr);
+ ASSERT_EQ(inst->LHS()->Usage().Length(), 1u);
+ EXPECT_EQ(inst->LHS()->Usage()[0], inst);
}
} // namespace
diff --git a/src/tint/ir/bitcast.cc b/src/tint/ir/bitcast.cc
index 749702e..70f412c 100644
--- a/src/tint/ir/bitcast.cc
+++ b/src/tint/ir/bitcast.cc
@@ -19,18 +19,14 @@
namespace tint::ir {
-Bitcast::Bitcast(Value* result, Value* val) : Base(result), val_(val) {
- TINT_ASSERT(IR, val_);
- val_->AddUsage(this);
-}
+Bitcast::Bitcast(uint32_t id, const type::Type* type, Value* val)
+ : Base(id, type, utils::Vector{val}) {}
Bitcast::~Bitcast() = default;
-utils::StringStream& Bitcast::ToString(utils::StringStream& out) const {
- Result()->ToString(out);
- out << " = bitcast(";
- val_->ToString(out);
- out << ")";
+utils::StringStream& Bitcast::ToInstruction(utils::StringStream& out) const {
+ ToValue(out) << " = bitcast ";
+ EmitArgs(out);
return out;
}
diff --git a/src/tint/ir/bitcast.h b/src/tint/ir/bitcast.h
index c7d9cb8..253ea0b 100644
--- a/src/tint/ir/bitcast.h
+++ b/src/tint/ir/bitcast.h
@@ -15,36 +15,31 @@
#ifndef SRC_TINT_IR_BITCAST_H_
#define SRC_TINT_IR_BITCAST_H_
-#include "src/tint/ir/instruction.h"
+#include "src/tint/ir/call.h"
#include "src/tint/utils/castable.h"
#include "src/tint/utils/string_stream.h"
namespace tint::ir {
/// A bitcast instruction in the IR.
-class Bitcast : public utils::Castable<Bitcast, Instruction> {
+class Bitcast : public utils::Castable<Bitcast, Call> {
public:
/// Constructor
- /// @param result the result value
+ /// @param id the instruction id
+ /// @param type the result type
/// @param val the value being bitcast
- Bitcast(Value* result, Value* val);
- Bitcast(const Bitcast& instr) = delete;
- Bitcast(Bitcast&& instr) = delete;
+ Bitcast(uint32_t id, const type::Type* type, Value* val);
+ Bitcast(const Bitcast& inst) = delete;
+ Bitcast(Bitcast&& inst) = delete;
~Bitcast() override;
- Bitcast& operator=(const Bitcast& instr) = delete;
- Bitcast& operator=(Bitcast&& instr) = delete;
-
- /// @returns the left-hand-side value for the instruction
- const Value* Val() const { return val_; }
+ Bitcast& operator=(const Bitcast& inst) = delete;
+ Bitcast& operator=(Bitcast&& inst) = delete;
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
- utils::StringStream& ToString(utils::StringStream& out) const override;
-
- private:
- Value* val_ = nullptr;
+ utils::StringStream& ToInstruction(utils::StringStream& out) const override;
};
} // namespace tint::ir
diff --git a/src/tint/ir/bitcast_test.cc b/src/tint/ir/bitcast_test.cc
index 2e6ca9d..a70fb92 100644
--- a/src/tint/ir/bitcast_test.cc
+++ b/src/tint/ir/bitcast_test.cc
@@ -20,44 +20,37 @@
namespace {
using namespace tint::number_suffixes; // NOLINT
- //
+
using IR_InstructionTest = TestHelper;
TEST_F(IR_InstructionTest, Bitcast) {
auto& b = CreateEmptyBuilder();
-
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr =
+ const auto* inst =
b.builder.Bitcast(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
- ASSERT_NE(instr->Result()->Type(), nullptr);
+ ASSERT_TRUE(inst->Is<ir::Bitcast>());
+ ASSERT_NE(inst->Type(), nullptr);
- ASSERT_TRUE(instr->Val()->Is<Constant>());
- auto val = instr->Val()->As<Constant>()->value;
+ ASSERT_EQ(inst->Args().Length(), 1u);
+ ASSERT_TRUE(inst->Args()[0]->Is<Constant>());
+ auto val = inst->Args()[0]->As<Constant>()->value;
ASSERT_TRUE(val->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, val->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = bitcast(4)");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = bitcast 4i");
}
TEST_F(IR_InstructionTest, Bitcast_Usage) {
auto& b = CreateEmptyBuilder();
-
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr =
+ const auto* inst =
b.builder.Bitcast(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
- ASSERT_NE(instr->Result(), nullptr);
- ASSERT_EQ(instr->Result()->Usage().Length(), 1u);
- EXPECT_EQ(instr->Result()->Usage()[0], instr);
-
- ASSERT_NE(instr->Val(), nullptr);
- ASSERT_EQ(instr->Val()->Usage().Length(), 1u);
- EXPECT_EQ(instr->Val()->Usage()[0], instr);
+ ASSERT_EQ(inst->Args().Length(), 1u);
+ ASSERT_NE(inst->Args()[0], nullptr);
+ ASSERT_EQ(inst->Args()[0]->Usage().Length(), 1u);
+ EXPECT_EQ(inst->Args()[0]->Usage()[0], inst);
}
} // namespace
diff --git a/src/tint/ir/block.h b/src/tint/ir/block.h
index e83d43a..3981355 100644
--- a/src/tint/ir/block.h
+++ b/src/tint/ir/block.h
@@ -33,7 +33,7 @@
/// @returns true if this is a dead block. This can happen in the case like a loop merge block
/// which is never reached.
- bool IsDead() const { return branch.target == nullptr; }
+ bool IsDead() const override { return branch.target == nullptr; }
/// The node this block branches too.
Branch branch = {};
diff --git a/src/tint/ir/builder.cc b/src/tint/ir/builder.cc
index 13ef345..2c97737 100644
--- a/src/tint/ir/builder.cc
+++ b/src/tint/ir/builder.cc
@@ -16,8 +16,6 @@
#include <utility>
-#include "src/tint/ir/builder_impl.h"
-
namespace tint::ir {
Builder::Builder() {}
@@ -26,6 +24,17 @@
Builder::~Builder() = default;
+ir::Block* Builder::CreateRootBlockIfNeeded() {
+ if (!ir.root_block) {
+ ir.root_block = CreateBlock();
+
+ // Everything in the module scope must have been const-eval's, so everything will go into a
+ // single block. So, we can create the terminator for the root-block now.
+ ir.root_block->branch.target = CreateTerminator();
+ }
+ return ir.root_block;
+}
+
Block* Builder::CreateBlock() {
return ir.flow_nodes.Create<Block>();
}
@@ -93,12 +102,8 @@
to->inbound_branches.Push(from);
}
-Runtime::Id Builder::AllocateRuntimeId() {
- return next_runtime_id++;
-}
-
Binary* Builder::CreateBinary(Binary::Kind kind, const type::Type* type, Value* lhs, Value* rhs) {
- return ir.instructions.Create<ir::Binary>(kind, Runtime(type), lhs, rhs);
+ return ir.instructions.Create<ir::Binary>(next_inst_id(), kind, type, lhs, rhs);
}
Binary* Builder::And(const type::Type* type, Value* lhs, Value* rhs) {
@@ -174,7 +179,7 @@
}
Unary* Builder::CreateUnary(Unary::Kind kind, const type::Type* type, Value* val) {
- return ir.instructions.Create<ir::Unary>(kind, Runtime(type), val);
+ return ir.instructions.Create<ir::Unary>(next_inst_id(), kind, type, val);
}
Unary* Builder::AddressOf(const type::Type* type, Value* val) {
@@ -198,37 +203,43 @@
}
ir::Bitcast* Builder::Bitcast(const type::Type* type, Value* val) {
- return ir.instructions.Create<ir::Bitcast>(Runtime(type), val);
+ return ir.instructions.Create<ir::Bitcast>(next_inst_id(), type, val);
}
ir::Discard* Builder::Discard() {
- return ir.instructions.Create<ir::Discard>(Runtime(ir.types.Get<type::Void>()));
+ return ir.instructions.Create<ir::Discard>();
}
ir::UserCall* Builder::UserCall(const type::Type* type,
Symbol name,
utils::VectorRef<Value*> args) {
- return ir.instructions.Create<ir::UserCall>(Runtime(type), name, std::move(args));
+ return ir.instructions.Create<ir::UserCall>(next_inst_id(), type, name, std::move(args));
}
ir::Convert* Builder::Convert(const type::Type* to,
const type::Type* from,
utils::VectorRef<Value*> args) {
- return ir.instructions.Create<ir::Convert>(Runtime(to), from, std::move(args));
+ return ir.instructions.Create<ir::Convert>(next_inst_id(), to, from, std::move(args));
}
ir::Construct* Builder::Construct(const type::Type* to, utils::VectorRef<Value*> args) {
- return ir.instructions.Create<ir::Construct>(Runtime(to), std::move(args));
+ return ir.instructions.Create<ir::Construct>(next_inst_id(), to, std::move(args));
}
ir::Builtin* Builder::Builtin(const type::Type* type,
builtin::Function func,
utils::VectorRef<Value*> args) {
- return ir.instructions.Create<ir::Builtin>(Runtime(type), func, args);
+ return ir.instructions.Create<ir::Builtin>(next_inst_id(), type, func, args);
}
ir::Store* Builder::Store(Value* to, Value* from) {
return ir.instructions.Create<ir::Store>(to, from);
}
+ir::Var* Builder::Declare(const type::Type* type,
+ builtin::AddressSpace address_space,
+ builtin::Access access) {
+ return ir.instructions.Create<ir::Var>(next_inst_id(), type, address_space, access);
+}
+
} // namespace tint::ir
diff --git a/src/tint/ir/builder.h b/src/tint/ir/builder.h
index 3fc78d2..d509c06 100644
--- a/src/tint/ir/builder.h
+++ b/src/tint/ir/builder.h
@@ -29,13 +29,13 @@
#include "src/tint/ir/if.h"
#include "src/tint/ir/loop.h"
#include "src/tint/ir/module.h"
-#include "src/tint/ir/runtime.h"
#include "src/tint/ir/store.h"
#include "src/tint/ir/switch.h"
#include "src/tint/ir/terminator.h"
#include "src/tint/ir/unary.h"
#include "src/tint/ir/user_call.h"
#include "src/tint/ir/value.h"
+#include "src/tint/ir/var.h"
#include "src/tint/type/bool.h"
#include "src/tint/type/f16.h"
#include "src/tint/type/f32.h"
@@ -141,13 +141,6 @@
return Constant(create<constant::Scalar<bool>>(ir.types.Get<type::Bool>(), v));
}
- /// Creates a new Runtime value
- /// @param type the type of the temporary
- /// @returns the new temporary
- ir::Runtime* Runtime(const type::Type* type) {
- return ir.values.Create<ir::Runtime>(type, AllocateRuntimeId());
- }
-
/// Creates an op for `lhs kind rhs`
/// @param kind the kind of operation
/// @param type the result type of the binary expression
@@ -366,14 +359,26 @@
/// @returns the instruction
ir::Store* Store(Value* to, Value* from);
- /// @returns a unique runtime id
- Runtime::Id AllocateRuntimeId();
+ /// Creates a new `var` declaration
+ /// @param type the var type
+ /// @param address_space the address space
+ /// @param access the access mode
+ /// @returns the instruction
+ ir::Var* Declare(const type::Type* type,
+ builtin::AddressSpace address_space,
+ builtin::Access access);
+
+ /// Retrieves the root block for the module, creating if necessary
+ /// @returns the root block
+ ir::Block* CreateRootBlockIfNeeded();
/// The IR module.
Module ir;
- /// The next temporary number to allocate
- Runtime::Id next_runtime_id = 1;
+ private:
+ uint32_t next_inst_id() { return next_instruction_id_++; }
+
+ uint32_t next_instruction_id_ = 1;
};
} // namespace tint::ir
diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc
index 1f0f79a..19caf6f 100644
--- a/src/tint/ir/builder_impl.cc
+++ b/src/tint/ir/builder_impl.cc
@@ -39,6 +39,7 @@
#include "src/tint/ast/identifier_expression.h"
#include "src/tint/ast/if_statement.h"
#include "src/tint/ast/int_literal_expression.h"
+#include "src/tint/ast/let.h"
#include "src/tint/ast/literal_expression.h"
#include "src/tint/ast/loop_statement.h"
#include "src/tint/ast/override.h"
@@ -50,6 +51,7 @@
#include "src/tint/ast/switch_statement.h"
#include "src/tint/ast/templated_identifier.h"
#include "src/tint/ast/unary_op_expression.h"
+#include "src/tint/ast/var.h"
#include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/ast/while_statement.h"
#include "src/tint/ir/function.h"
@@ -69,8 +71,10 @@
#include "src/tint/sem/value_constructor.h"
#include "src/tint/sem/value_conversion.h"
#include "src/tint/sem/value_expression.h"
+#include "src/tint/sem/variable.h"
#include "src/tint/switch.h"
#include "src/tint/type/void.h"
+#include "src/tint/utils/scoped_assignment.h"
namespace tint::ir {
namespace {
@@ -169,10 +173,13 @@
[&](const ast::Alias*) {
// Folded away and doesn't appear in the IR.
},
- // [&](const ast::Variable* var) {
- // TODO(dsinclair): Implement
- // },
- [&](const ast::Function* func) { return EmitFunction(func); },
+ [&](const ast::Variable* var) {
+ // Setup the current flow node to be the root block for the module. The builder will
+ // handle creating it if it doesn't exist already.
+ TINT_SCOPED_ASSIGNMENT(current_flow_block, builder.CreateRootBlockIfNeeded());
+ EmitVariable(var);
+ },
+ [&](const ast::Function* func) { EmitFunction(func); },
// [&](const ast::Enable*) {
// TODO(dsinclair): Implement? I think these need to be passed along so further stages
// know what is enabled.
@@ -291,69 +298,69 @@
}
auto* ty = lhs.Get()->Type();
- Binary* instr = nullptr;
+ Binary* inst = nullptr;
switch (stmt->op) {
case ast::BinaryOp::kAnd:
- instr = builder.And(ty, lhs.Get(), rhs.Get());
+ inst = builder.And(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kOr:
- instr = builder.Or(ty, lhs.Get(), rhs.Get());
+ inst = builder.Or(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kXor:
- instr = builder.Xor(ty, lhs.Get(), rhs.Get());
+ inst = builder.Xor(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLogicalAnd:
- instr = builder.LogicalAnd(ty, lhs.Get(), rhs.Get());
+ inst = builder.LogicalAnd(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLogicalOr:
- instr = builder.LogicalOr(ty, lhs.Get(), rhs.Get());
+ inst = builder.LogicalOr(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kEqual:
- instr = builder.Equal(ty, lhs.Get(), rhs.Get());
+ inst = builder.Equal(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kNotEqual:
- instr = builder.NotEqual(ty, lhs.Get(), rhs.Get());
+ inst = builder.NotEqual(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLessThan:
- instr = builder.LessThan(ty, lhs.Get(), rhs.Get());
+ inst = builder.LessThan(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kGreaterThan:
- instr = builder.GreaterThan(ty, lhs.Get(), rhs.Get());
+ inst = builder.GreaterThan(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLessThanEqual:
- instr = builder.LessThanEqual(ty, lhs.Get(), rhs.Get());
+ inst = builder.LessThanEqual(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kGreaterThanEqual:
- instr = builder.GreaterThanEqual(ty, lhs.Get(), rhs.Get());
+ inst = builder.GreaterThanEqual(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kShiftLeft:
- instr = builder.ShiftLeft(ty, lhs.Get(), rhs.Get());
+ inst = builder.ShiftLeft(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kShiftRight:
- instr = builder.ShiftRight(ty, lhs.Get(), rhs.Get());
+ inst = builder.ShiftRight(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kAdd:
- instr = builder.Add(ty, lhs.Get(), rhs.Get());
+ inst = builder.Add(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kSubtract:
- instr = builder.Subtract(ty, lhs.Get(), rhs.Get());
+ inst = builder.Subtract(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kMultiply:
- instr = builder.Multiply(ty, lhs.Get(), rhs.Get());
+ inst = builder.Multiply(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kDivide:
- instr = builder.Divide(ty, lhs.Get(), rhs.Get());
+ inst = builder.Divide(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kModulo:
- instr = builder.Modulo(ty, lhs.Get(), rhs.Get());
+ inst = builder.Modulo(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kNone:
TINT_ICE(IR, diagnostics_) << "missing binary operand type";
return;
}
- current_flow_block->instructions.Push(instr);
+ current_flow_block->instructions.Push(inst);
- auto store = builder.Store(lhs.Get(), instr->Result());
+ auto store = builder.Store(lhs.Get(), inst);
current_flow_block->instructions.Push(store);
}
@@ -430,8 +437,8 @@
BranchToIfNeeded(loop_node->start.target);
}
- // The loop merge can get disconnected if the loop returns directly, or the continuing target
- // branches, eventually, to the merge, but nothing branched to the continuing target.
+ // The loop merge can get disconnected if the loop returns directly, or the continuing
+ // target branches, eventually, to the merge, but nothing branched to the continuing target.
current_flow_block = loop_node->merge.target->As<Block>();
if (!IsConnected(loop_node->merge.target)) {
current_flow_block = nullptr;
@@ -613,12 +620,12 @@
}
// Discard is being treated as an instruction. The semantics in WGSL is demote_to_helper, so the
-// code has to continue as before it just predicates writes. If WGSL grows some kind of terminating
-// discard that would probably make sense as a FlowNode but would then require figuring out the
-// multi-level exit that is triggered.
+// code has to continue as before it just predicates writes. If WGSL grows some kind of
+// terminating discard that would probably make sense as a FlowNode but would then require
+// figuring out the multi-level exit that is triggered.
void BuilderImpl::EmitDiscard(const ast::DiscardStatement*) {
- auto* instr = builder.Discard();
- current_flow_block->instructions.Push(instr);
+ auto* inst = builder.Discard();
+ current_flow_block->instructions.Push(inst);
}
void BuilderImpl::EmitBreakIf(const ast::BreakIfStatement* stmt) {
@@ -655,6 +662,15 @@
}
utils::Result<Value*> BuilderImpl::EmitExpression(const ast::Expression* expr) {
+ // If this is a value that has been const-eval'd return the result.
+ if (auto* sem = program_->Sem().Get(expr)->As<sem::ValueExpression>()) {
+ if (auto* v = sem->ConstantValue()) {
+ if (auto* cv = v->Clone(clone_ctx_)) {
+ return builder.Constant(cv);
+ }
+ }
+ }
+
return tint::Switch(
expr,
// [&](const ast::IndexAccessorExpression* a) {
@@ -682,14 +698,35 @@
}
void BuilderImpl::EmitVariable(const ast::Variable* var) {
+ auto* sem = program_->Sem().Get(var);
+
return tint::Switch( //
var,
- // [&](const ast::Var* var) {
- // TODO(dsinclair): Implement
- // },
- // [&](const ast::Let*) {
- // TODO(dsinclair): Implement
- // },
+ [&](const ast::Var* v) {
+ auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
+ auto* val = builder.Declare(ty, sem->AddressSpace(), sem->Access());
+ current_flow_block->instructions.Push(val);
+
+ if (v->initializer) {
+ auto init = EmitExpression(v->initializer);
+ if (!init) {
+ return;
+ }
+
+ auto* store = builder.Store(val, init.Get());
+ current_flow_block->instructions.Push(store);
+ }
+ // TODO(dsinclair): Store the mapping from the var name to the `Declare` value
+ },
+ [&](const ast::Let* l) {
+ // A `let` doesn't exist as a standalone item in the IR, it's just the result of the
+ // initializer.
+ auto init = EmitExpression(l->initializer);
+ if (!init) {
+ return;
+ }
+ // TODO(dsinclair): Store the mapping from the let name to the `init` value
+ },
[&](const ast::Override*) {
add_error(var->source,
"found an `Override` variable. The SubstituteOverrides "
@@ -701,8 +738,8 @@
// should never be used.
//
// TODO(dsinclair): Probably want to store the const variable somewhere and then in
- // identifier expression log an error if we ever see a const identifier. Add this when
- // identifiers and variables are supported.
+ // identifier expression log an error if we ever see a const identifier. Add this
+ // when identifiers and variables are supported.
},
[&](Default) {
add_error(var->source, "unknown variable: " + std::string(var->TypeInfo().name));
@@ -718,27 +755,27 @@
auto* sem = program_->Sem().Get(expr);
auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
- Unary* instr = nullptr;
+ Unary* inst = nullptr;
switch (expr->op) {
case ast::UnaryOp::kAddressOf:
- instr = builder.AddressOf(ty, val.Get());
+ inst = builder.AddressOf(ty, val.Get());
break;
case ast::UnaryOp::kComplement:
- instr = builder.Complement(ty, val.Get());
+ inst = builder.Complement(ty, val.Get());
break;
case ast::UnaryOp::kIndirection:
- instr = builder.Indirection(ty, val.Get());
+ inst = builder.Indirection(ty, val.Get());
break;
case ast::UnaryOp::kNegation:
- instr = builder.Negation(ty, val.Get());
+ inst = builder.Negation(ty, val.Get());
break;
case ast::UnaryOp::kNot:
- instr = builder.Not(ty, val.Get());
+ inst = builder.Not(ty, val.Get());
break;
}
- current_flow_block->instructions.Push(instr);
- return instr->Result();
+ current_flow_block->instructions.Push(inst);
+ return inst;
}
utils::Result<Value*> BuilderImpl::EmitBinary(const ast::BinaryExpression* expr) {
@@ -755,69 +792,69 @@
auto* sem = program_->Sem().Get(expr);
auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
- Binary* instr = nullptr;
+ Binary* inst = nullptr;
switch (expr->op) {
case ast::BinaryOp::kAnd:
- instr = builder.And(ty, lhs.Get(), rhs.Get());
+ inst = builder.And(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kOr:
- instr = builder.Or(ty, lhs.Get(), rhs.Get());
+ inst = builder.Or(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kXor:
- instr = builder.Xor(ty, lhs.Get(), rhs.Get());
+ inst = builder.Xor(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLogicalAnd:
- instr = builder.LogicalAnd(ty, lhs.Get(), rhs.Get());
+ inst = builder.LogicalAnd(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLogicalOr:
- instr = builder.LogicalOr(ty, lhs.Get(), rhs.Get());
+ inst = builder.LogicalOr(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kEqual:
- instr = builder.Equal(ty, lhs.Get(), rhs.Get());
+ inst = builder.Equal(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kNotEqual:
- instr = builder.NotEqual(ty, lhs.Get(), rhs.Get());
+ inst = builder.NotEqual(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLessThan:
- instr = builder.LessThan(ty, lhs.Get(), rhs.Get());
+ inst = builder.LessThan(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kGreaterThan:
- instr = builder.GreaterThan(ty, lhs.Get(), rhs.Get());
+ inst = builder.GreaterThan(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLessThanEqual:
- instr = builder.LessThanEqual(ty, lhs.Get(), rhs.Get());
+ inst = builder.LessThanEqual(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kGreaterThanEqual:
- instr = builder.GreaterThanEqual(ty, lhs.Get(), rhs.Get());
+ inst = builder.GreaterThanEqual(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kShiftLeft:
- instr = builder.ShiftLeft(ty, lhs.Get(), rhs.Get());
+ inst = builder.ShiftLeft(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kShiftRight:
- instr = builder.ShiftRight(ty, lhs.Get(), rhs.Get());
+ inst = builder.ShiftRight(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kAdd:
- instr = builder.Add(ty, lhs.Get(), rhs.Get());
+ inst = builder.Add(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kSubtract:
- instr = builder.Subtract(ty, lhs.Get(), rhs.Get());
+ inst = builder.Subtract(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kMultiply:
- instr = builder.Multiply(ty, lhs.Get(), rhs.Get());
+ inst = builder.Multiply(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kDivide:
- instr = builder.Divide(ty, lhs.Get(), rhs.Get());
+ inst = builder.Divide(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kModulo:
- instr = builder.Modulo(ty, lhs.Get(), rhs.Get());
+ inst = builder.Modulo(ty, lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kNone:
TINT_ICE(IR, diagnostics_) << "missing binary operand type";
return utils::Failure;
}
- current_flow_block->instructions.Push(instr);
- return instr->Result();
+ current_flow_block->instructions.Push(inst);
+ return inst;
}
utils::Result<Value*> BuilderImpl::EmitBitcast(const ast::BitcastExpression* expr) {
@@ -828,10 +865,10 @@
auto* sem = program_->Sem().Get(expr);
auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
- auto* instr = builder.Bitcast(ty, val.Get());
+ auto* inst = builder.Bitcast(ty, val.Get());
- current_flow_block->instructions.Push(instr);
- return instr->Result();
+ current_flow_block->instructions.Push(inst);
+ return inst;
}
void BuilderImpl::EmitCall(const ast::CallStatement* stmt) {
@@ -874,29 +911,29 @@
auto* ty = sem->Target()->ReturnType()->Clone(clone_ctx_.type_ctx);
- Instruction* instr = nullptr;
+ Instruction* inst = nullptr;
// If this is a builtin function, emit the specific builtin value
if (auto* b = sem->Target()->As<sem::Builtin>()) {
- instr = builder.Builtin(ty, b->Type(), args);
+ inst = builder.Builtin(ty, b->Type(), args);
} else if (sem->Target()->As<sem::ValueConstructor>()) {
- instr = builder.Construct(ty, std::move(args));
+ inst = builder.Construct(ty, std::move(args));
} else if (auto* conv = sem->Target()->As<sem::ValueConversion>()) {
auto* from = conv->Source()->Clone(clone_ctx_.type_ctx);
- instr = builder.Convert(ty, from, std::move(args));
+ inst = builder.Convert(ty, from, std::move(args));
} else if (expr->target->identifier->Is<ast::TemplatedIdentifier>()) {
TINT_UNIMPLEMENTED(IR, diagnostics_) << "missing templated ident support";
return utils::Failure;
} else {
// Not a builtin and not a templated call, so this is a user function.
auto name = CloneSymbol(expr->target->identifier->symbol);
- instr = builder.UserCall(ty, name, std::move(args));
+ inst = builder.UserCall(ty, name, std::move(args));
}
- if (instr == nullptr) {
+ if (inst == nullptr) {
return utils::Failure;
}
- current_flow_block->instructions.Push(instr);
- return instr->Result();
+ current_flow_block->instructions.Push(inst);
+ return inst;
}
utils::Result<Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) {
diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc
index cd6bf0b..1e6a26d 100644
--- a/src/tint/ir/builder_impl_test.cc
+++ b/src/tint/ir/builder_impl_test.cc
@@ -42,10 +42,10 @@
EXPECT_EQ(1u, f->start_target->inbound_branches.Length());
EXPECT_EQ(1u, f->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function f
- %bb1 = Block
- Return ()
-FunctionEnd
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func f
+ %fn1 = block
+ ret
+func_end
)");
}
@@ -88,23 +88,23 @@
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = if (true)
+ %fn2 = if true [t: %fn3, f: %fn4, m: %fn5]
# true branch
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn3 = block
+ branch %fn5
# false branch
- %bb5 = Block
- BranchTo %bb4 ()
+ %fn4 = block
+ branch %fn5
# if merge
- %bb4 = Block
- Return ()
-FunctionEnd
+ %fn5 = block
+ ret
+func_end
)");
}
@@ -136,22 +136,22 @@
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = if (true)
+ %fn2 = if true [t: %fn3, f: %fn4, m: %fn5]
# true branch
- %bb3 = Block
- Return ()
+ %fn3 = block
+ ret
# false branch
- %bb4 = Block
- BranchTo %bb5 ()
+ %fn4 = block
+ branch %fn5
# if merge
- %bb5 = Block
- Return ()
-FunctionEnd
+ %fn5 = block
+ ret
+func_end
)");
}
@@ -183,22 +183,22 @@
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = if (true)
+ %fn2 = if true [t: %fn3, f: %fn4, m: %fn5]
# true branch
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn3 = block
+ branch %fn5
# false branch
- %bb5 = Block
- Return ()
+ %fn4 = block
+ ret
# if merge
- %bb4 = Block
- Return ()
-FunctionEnd
+ %fn5 = block
+ ret
+func_end
)");
}
@@ -230,18 +230,18 @@
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = if (true)
+ %fn2 = if true [t: %fn3, f: %fn4]
# true branch
- %bb3 = Block
- Return ()
+ %fn3 = block
+ ret
# false branch
- %bb4 = Block
- Return ()
-FunctionEnd
+ %fn4 = block
+ ret
+func_end
)");
}
@@ -273,36 +273,32 @@
ASSERT_NE(loop_flow->continuing.target, nullptr);
ASSERT_NE(loop_flow->merge.target, nullptr);
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = if (true)
+ %fn2 = if true [t: %fn3, f: %fn4, m: %fn5]
# true branch
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn3 = block
+ branch %fn6
- %bb4 = loop
+ %fn6 = loop [s: %fn7, m: %fn8]
# loop start
- %bb5 = Block
- BranchTo %bb6 ()
-
- # loop continuing
- %bb7 = Block
- BranchTo %bb5 ()
+ %fn7 = block
+ branch %fn8
# loop merge
- %bb6 = Block
- BranchTo %bb8 ()
+ %fn8 = block
+ branch %fn5
# false branch
- %bb9 = Block
- BranchTo %bb8 ()
+ %fn4 = block
+ branch %fn5
# if merge
- %bb8 = Block
- Return ()
-FunctionEnd
+ %fn5 = block
+ ret
+func_end
)");
}
@@ -334,23 +330,19 @@
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = loop
+ %fn2 = loop [s: %fn3, m: %fn4]
# loop start
- %bb3 = Block
- BranchTo %bb4 ()
-
- # loop continuing
- %bb5 = Block
- BranchTo %bb3 ()
+ %fn3 = block
+ branch %fn4
# loop merge
- %bb4 = Block
- Return ()
-FunctionEnd
+ %fn4 = block
+ ret
+func_end
)");
}
@@ -396,36 +388,36 @@
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = loop
+ %fn2 = loop [s: %fn3, c: %fn4, m: %fn5]
# loop start
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn3 = block
+ branch %fn6
- %bb4 = if (true)
+ %fn6 = if true [t: %fn7, f: %fn8, m: %fn9]
# true branch
- %bb5 = Block
- BranchTo %bb6 ()
+ %fn7 = block
+ branch %fn5
# false branch
- %bb7 = Block
- BranchTo %bb8 ()
+ %fn8 = block
+ branch %fn9
# if merge
- %bb8 = Block
- BranchTo %bb9 ()
+ %fn9 = block
+ branch %fn4
# loop continuing
- %bb9 = Block
- BranchTo %bb3 ()
+ %fn4 = block
+ branch %fn3
# loop merge
- %bb6 = Block
- Return ()
-FunctionEnd
+ %fn5 = block
+ ret
+func_end
)");
}
@@ -471,36 +463,36 @@
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = loop
+ %fn2 = loop [s: %fn3, c: %fn4, m: %fn5]
# loop start
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn3 = block
+ branch %fn4
# loop continuing
- %bb4 = Block
- BranchTo %bb5 ()
+ %fn4 = block
+ branch %fn6
- %bb5 = if (true)
+ %fn6 = if true [t: %fn7, f: %fn8, m: %fn9]
# true branch
- %bb6 = Block
- BranchTo %bb7 ()
+ %fn7 = block
+ branch %fn5
# false branch
- %bb8 = Block
- BranchTo %bb9 ()
+ %fn8 = block
+ branch %fn9
# if merge
- %bb9 = Block
- BranchTo %bb3 ()
+ %fn9 = block
+ branch %fn3
# loop merge
- %bb7 = Block
- Return ()
-FunctionEnd
+ %fn5 = block
+ ret
+func_end
)");
}
@@ -546,34 +538,32 @@
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = loop
+ %fn2 = loop [s: %fn3, c: %fn4]
# loop start
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn3 = block
+ branch %fn5
- %bb4 = if (true)
+ %fn5 = if true [t: %fn6, f: %fn7, m: %fn8]
# true branch
- %bb5 = Block
- Return ()
+ %fn6 = block
+ ret
# false branch
- %bb6 = Block
- BranchTo %bb7 ()
+ %fn7 = block
+ branch %fn8
# if merge
- %bb7 = Block
- BranchTo %bb8 ()
+ %fn8 = block
+ branch %fn4
# loop continuing
- %bb8 = Block
- BranchTo %bb3 ()
+ %fn4 = block
+ branch %fn3
- # loop merge
- # Dead
-FunctionEnd
+func_end
)");
}
@@ -605,21 +595,15 @@
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = loop
+ %fn2 = loop [s: %fn3]
# loop start
- %bb3 = Block
- Return ()
- # loop continuing
- %bb4 = Block
- BranchTo %bb3 ()
-
- # loop merge
- # Dead
-FunctionEnd
+ %fn3 = block
+ ret
+func_end
)");
}
@@ -629,6 +613,9 @@
// `ast_if` below), it doesn't get emitted as there is no way to reach the
// loop merge due to the loop itself doing a `return`. This is why the
// loop merge gets marked as Dead and the `ast_if` doesn't appear.
+ //
+ // Similar, the continuing block goes away as there is no way to get there, so it's treated
+ // as dead code and dropped.
auto* ast_break_if = BreakIf(true);
auto* ast_loop = Loop(Block(Return()), Block(ast_break_if));
auto* ast_if = If(true, Block(Return()));
@@ -670,34 +657,15 @@
// This is 1 because only the loop branch happens. The subsequent if return is dead code.
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = loop
+ %fn2 = loop [s: %fn3]
# loop start
- %bb3 = Block
- Return ()
- # loop continuing
- %bb4 = Block
- BranchTo %bb5 ()
-
- %bb5 = if (true)
- # true branch
- %bb6 = Block
- BranchTo %bb7 ()
-
- # false branch
- %bb8 = Block
- BranchTo %bb9 ()
-
- # if merge
- %bb9 = Block
- BranchTo %bb3 ()
-
- # loop merge
- # Dead
-FunctionEnd
+ %fn3 = block
+ ret
+func_end
)");
}
@@ -743,32 +711,28 @@
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = loop
+ %fn2 = loop [s: %fn3, m: %fn4]
# loop start
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn3 = block
+ branch %fn5
- %bb4 = if (true)
+ %fn5 = if true [t: %fn6, f: %fn7]
# true branch
- %bb5 = Block
- BranchTo %bb6 ()
+ %fn6 = block
+ branch %fn4
# false branch
- %bb7 = Block
- BranchTo %bb6 ()
-
- # loop continuing
- %bb8 = Block
- BranchTo %bb3 ()
+ %fn7 = block
+ branch %fn4
# loop merge
- %bb6 = Block
- Return ()
-FunctionEnd
+ %fn4 = block
+ ret
+func_end
)");
}
@@ -893,114 +857,110 @@
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = loop
+ %fn2 = loop [s: %fn3, c: %fn4, m: %fn5]
# loop start
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn3 = block
+ branch %fn6
- %bb4 = loop
+ %fn6 = loop [s: %fn7, c: %fn8, m: %fn9]
# loop start
- %bb5 = Block
- BranchTo %bb6 ()
+ %fn7 = block
+ branch %fn10
- %bb6 = if (true)
+ %fn10 = if true [t: %fn11, f: %fn12, m: %fn13]
# true branch
- %bb7 = Block
- BranchTo %bb8 ()
+ %fn11 = block
+ branch %fn9
# false branch
- %bb9 = Block
- BranchTo %bb10 ()
+ %fn12 = block
+ branch %fn13
# if merge
- %bb10 = Block
- BranchTo %bb11 ()
+ %fn13 = block
+ branch %fn14
- %bb11 = if (true)
+ %fn14 = if true [t: %fn15, f: %fn16, m: %fn17]
# true branch
- %bb12 = Block
- BranchTo %bb13 ()
+ %fn15 = block
+ branch %fn8
# false branch
- %bb14 = Block
- BranchTo %bb15 ()
+ %fn16 = block
+ branch %fn17
# if merge
- %bb15 = Block
- BranchTo %bb13 ()
+ %fn17 = block
+ branch %fn8
# loop continuing
- %bb13 = Block
- BranchTo %bb16 ()
+ %fn8 = block
+ branch %fn18
- %bb16 = loop
+ %fn18 = loop [s: %fn19, m: %fn20]
# loop start
- %bb17 = Block
- BranchTo %bb18 ()
-
- # loop continuing
- %bb19 = Block
- BranchTo %bb17 ()
+ %fn19 = block
+ branch %fn20
# loop merge
- %bb18 = Block
- BranchTo %bb20 ()
+ %fn20 = block
+ branch %fn21
- %bb20 = loop
+ %fn21 = loop [s: %fn22, c: %fn23, m: %fn24]
# loop start
- %bb21 = Block
- BranchTo %bb22 ()
+ %fn22 = block
+ branch %fn23
# loop continuing
- %bb22 = Block
- BranchTo %bb23 ()
+ %fn23 = block
+ branch %fn25
- %bb23 = if (true)
+ %fn25 = if true [t: %fn26, f: %fn27, m: %fn28]
# true branch
- %bb24 = Block
- BranchTo %bb25 ()
+ %fn26 = block
+ branch %fn24
# false branch
- %bb26 = Block
- BranchTo %bb27 ()
+ %fn27 = block
+ branch %fn28
# if merge
- %bb27 = Block
- BranchTo %bb21 ()
+ %fn28 = block
+ branch %fn22
# loop merge
- %bb25 = Block
- BranchTo %bb5 ()
+ %fn24 = block
+ branch %fn7
# loop merge
- %bb8 = Block
- BranchTo %bb28 ()
+ %fn9 = block
+ branch %fn29
- %bb28 = if (true)
+ %fn29 = if true [t: %fn30, f: %fn31, m: %fn32]
# true branch
- %bb29 = Block
- BranchTo %bb30 ()
+ %fn30 = block
+ branch %fn5
# false branch
- %bb31 = Block
- BranchTo %bb32 ()
+ %fn31 = block
+ branch %fn32
# if merge
- %bb32 = Block
- BranchTo %bb33 ()
+ %fn32 = block
+ branch %fn4
# loop continuing
- %bb33 = Block
- BranchTo %bb3 ()
+ %fn4 = block
+ branch %fn3
# loop merge
- %bb30 = Block
- Return ()
-FunctionEnd
+ %fn5 = block
+ ret
+func_end
)");
}
@@ -1041,36 +1001,36 @@
EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = loop
+ %fn2 = loop [s: %fn3, c: %fn4, m: %fn5]
# loop start
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn3 = block
+ branch %fn6
- %bb4 = if (false)
+ %fn6 = if false [t: %fn7, f: %fn8, m: %fn9]
# true branch
- %bb5 = Block
- BranchTo %bb6 ()
+ %fn7 = block
+ branch %fn9
# false branch
- %bb7 = Block
- BranchTo %bb8 ()
+ %fn8 = block
+ branch %fn5
# if merge
- %bb6 = Block
- BranchTo %bb9 ()
+ %fn9 = block
+ branch %fn4
# loop continuing
- %bb9 = Block
- BranchTo %bb3 ()
+ %fn4 = block
+ branch %fn3
# loop merge
- %bb8 = Block
- Return ()
-FunctionEnd
+ %fn5 = block
+ ret
+func_end
)");
}
@@ -1111,35 +1071,31 @@
EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = loop
+ %fn2 = loop [s: %fn3, m: %fn4]
# loop start
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn3 = block
+ branch %fn5
- %bb4 = if (true)
+ %fn5 = if true [t: %fn6, f: %fn7, m: %fn8]
# true branch
- %bb5 = Block
- BranchTo %bb6 ()
+ %fn6 = block
+ branch %fn8
# false branch
- %bb7 = Block
- BranchTo %bb8 ()
+ %fn7 = block
+ branch %fn4
# if merge
- %bb6 = Block
- Return ()
- # loop continuing
- %bb9 = Block
- BranchTo %bb3 ()
-
+ %fn8 = block
+ ret
# loop merge
- %bb8 = Block
- Return ()
-FunctionEnd
+ %fn4 = block
+ ret
+func_end
)");
}
@@ -1222,23 +1178,19 @@
EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = loop
+ %fn2 = loop [s: %fn3, m: %fn4]
# loop start
- %bb3 = Block
- BranchTo %bb4 ()
-
- # loop continuing
- %bb5 = Block
- BranchTo %bb3 ()
+ %fn3 = block
+ branch %fn4
# loop merge
- %bb4 = Block
- Return ()
-FunctionEnd
+ %fn4 = block
+ ret
+func_end
)");
}
@@ -1285,27 +1237,83 @@
EXPECT_EQ(3u, flow->merge.target->inbound_branches.Length());
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = Switch (1)
- # Case 0
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn2 = switch 1i [c: (0i, %fn3), c: (1i, %fn4), c: (default, %fn5), m: %fn6]
+ # case 0i
+ %fn3 = block
+ branch %fn6
- # Case 1
- %bb5 = Block
- BranchTo %bb4 ()
+ # case 1i
+ %fn4 = block
+ branch %fn6
- # Case default
- %bb6 = Block
- BranchTo %bb4 ()
+ # case default
+ %fn5 = block
+ branch %fn6
- # Switch Merge
- %bb4 = Block
- Return ()
-FunctionEnd
+ # switch merge
+ %fn6 = block
+ ret
+func_end
+
+)");
+}
+
+TEST_F(IR_BuilderImplTest, Switch_MultiSelector) {
+ auto* ast_switch = Switch(
+ 1_i,
+ utils::Vector{Case(
+ utils::Vector{CaseSelector(0_i), CaseSelector(1_i), DefaultCaseSelector()}, Block())});
+
+ WrapInFunction(ast_switch);
+
+ auto r = Build();
+ ASSERT_TRUE(r) << Error();
+ auto m = r.Move();
+
+ auto* ir_switch = FlowNodeForAstNode(ast_switch);
+ ASSERT_NE(ir_switch, nullptr);
+ ASSERT_TRUE(ir_switch->Is<ir::Switch>());
+
+ auto* flow = ir_switch->As<ir::Switch>();
+ ASSERT_NE(flow->merge.target, nullptr);
+ ASSERT_EQ(1u, flow->cases.Length());
+
+ ASSERT_EQ(1u, m.functions.Length());
+ auto* func = m.functions[0];
+
+ ASSERT_EQ(3u, flow->cases[0].selectors.Length());
+ ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
+ EXPECT_EQ(0_i,
+ flow->cases[0].selectors[0].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
+
+ ASSERT_TRUE(flow->cases[0].selectors[1].val->value->Is<constant::Scalar<tint::i32>>());
+ EXPECT_EQ(1_i,
+ flow->cases[0].selectors[1].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
+
+ EXPECT_TRUE(flow->cases[0].selectors[2].IsDefault());
+
+ EXPECT_EQ(1u, flow->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
+ EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
+
+ %fn2 = switch 1i [c: (0i 1i default, %fn3), m: %fn4]
+ # case 0i 1i default
+ %fn3 = block
+ branch %fn4
+
+ # switch merge
+ %fn4 = block
+ ret
+func_end
)");
}
@@ -1337,19 +1345,19 @@
EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = Switch (1)
- # Case default
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn2 = switch 1i [c: (default, %fn3), m: %fn4]
+ # case default
+ %fn3 = block
+ branch %fn4
- # Switch Merge
- %bb4 = Block
- Return ()
-FunctionEnd
+ # switch merge
+ %fn4 = block
+ ret
+func_end
)");
}
@@ -1390,23 +1398,23 @@
// This is 1 because the if is dead-code eliminated and the return doesn't happen.
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = Switch (1)
- # Case 0
- %bb3 = Block
- BranchTo %bb4 ()
+ %fn2 = switch 1i [c: (0i, %fn3), c: (default, %fn4), m: %fn5]
+ # case 0i
+ %fn3 = block
+ branch %fn5
- # Case default
- %bb5 = Block
- BranchTo %bb4 ()
+ # case default
+ %fn4 = block
+ branch %fn5
- # Switch Merge
- %bb4 = Block
- Return ()
-FunctionEnd
+ # switch merge
+ %fn5 = block
+ ret
+func_end
)");
}
@@ -1449,20 +1457,18 @@
EXPECT_EQ(0u, flow->merge.target->inbound_branches.Length());
EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- BranchTo %bb2 ()
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ branch %fn2
- %bb2 = Switch (1)
- # Case 0
- %bb3 = Block
- Return ()
- # Case default
- %bb4 = Block
- Return ()
- # Switch Merge
- # Dead
-FunctionEnd
+ %fn2 = switch 1i [c: (0i, %fn3), c: (default, %fn4)]
+ # case 0i
+ %fn3 = block
+ ret
+ # case default
+ %fn4 = block
+ ret
+func_end
)");
}
@@ -1552,8 +1558,75 @@
EXPECT_EQ(2_u, val->As<constant::Scalar<u32>>()->ValueAs<f32>());
}
+TEST_F(IR_BuilderImplTest, Emit_GlobalVar_NoInit) {
+ GlobalVar("a", ty.u32(), builtin::AddressSpace::kPrivate);
+
+ auto r = Build();
+ ASSERT_TRUE(r) << Error();
+ auto m = r.Move();
+
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = block
+%1(ref<private, u32, read_write>) = var private read_write
+ret
+
+)");
+}
+
+TEST_F(IR_BuilderImplTest, Emit_GlobalVar_Init) {
+ auto* expr = Expr(2_u);
+ GlobalVar("a", ty.u32(), builtin::AddressSpace::kPrivate, expr);
+
+ auto r = Build();
+ ASSERT_TRUE(r) << Error();
+ auto m = r.Move();
+
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = block
+%1(ref<private, u32, read_write>) = var private read_write
+store %1(ref<private, u32, read_write>), 2u
+ret
+
+)");
+}
+
+TEST_F(IR_BuilderImplTest, Emit_Var_NoInit) {
+ auto* a = Var("a", ty.u32(), builtin::AddressSpace::kFunction);
+ WrapInFunction(a);
+
+ auto r = Build();
+ ASSERT_TRUE(r) << Error();
+ auto m = r.Move();
+
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ %1(ref<function, u32, read_write>) = var function read_write
+ ret
+func_end
+
+)");
+}
+
+TEST_F(IR_BuilderImplTest, Emit_Var_Init) {
+ auto* expr = Expr(2_u);
+ auto* a = Var("a", ty.u32(), builtin::AddressSpace::kFunction, expr);
+ WrapInFunction(a);
+
+ auto r = Build();
+ ASSERT_TRUE(r) << Error();
+ auto m = r.Move();
+
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ %1(ref<function, u32, read_write>) = var function read_write
+ store %1(ref<function, u32, read_write>), 2u
+ ret
+func_end
+
+)");
+}
+
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Add) {
- auto* expr = Add(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = Add(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1564,12 +1637,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 + 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = add %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Subtract) {
- auto* expr = Sub(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = Sub(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1580,12 +1655,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 - 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = sub %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Multiply) {
- auto* expr = Mul(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = Mul(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1596,12 +1673,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 * 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = mul %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Div) {
- auto* expr = Div(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = Div(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1612,12 +1691,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 / 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = div %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Modulo) {
- auto* expr = Mod(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = Mod(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1628,12 +1709,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 % 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = mod %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_And) {
- auto* expr = And(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = And(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1644,12 +1727,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 & 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = bit_and %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Or) {
- auto* expr = Or(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = Or(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1660,12 +1745,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 | 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = bit_or %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Xor) {
- auto* expr = Xor(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = Xor(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1676,12 +1763,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 ^ 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = bit_xor %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalAnd) {
- auto* expr = LogicalAnd(true, false);
+ Func("my_func", utils::Empty, ty.bool_(), utils::Vector{Return(true)});
+ auto* expr = LogicalAnd(Call("my_func"), false);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1692,12 +1781,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (bool) = true && false
+ EXPECT_EQ(d.AsString(), R"(%1(bool) = call my_func
+%2(bool) = log_and %1(bool), false
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalOr) {
- auto* expr = LogicalOr(false, true);
+ Func("my_func", utils::Empty, ty.bool_(), utils::Vector{Return(true)});
+ auto* expr = LogicalOr(Call("my_func"), true);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1708,12 +1799,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (bool) = false || true
+ EXPECT_EQ(d.AsString(), R"(%1(bool) = call my_func
+%2(bool) = log_or %1(bool), true
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Equal) {
- auto* expr = Equal(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = Equal(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1724,12 +1817,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 == 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = eq %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_NotEqual) {
- auto* expr = NotEqual(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = NotEqual(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1740,12 +1835,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 != 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = neq %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThan) {
- auto* expr = LessThan(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = LessThan(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1756,12 +1853,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 < 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = lt %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThan) {
- auto* expr = GreaterThan(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = GreaterThan(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1772,12 +1871,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 > 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = gt %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThanEqual) {
- auto* expr = LessThanEqual(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = LessThanEqual(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1788,12 +1889,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 <= 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = lte %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThanEqual) {
- auto* expr = GreaterThanEqual(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = GreaterThanEqual(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1804,12 +1907,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 >= 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = gte %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftLeft) {
- auto* expr = Shl(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = Shl(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1820,12 +1925,14 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 << 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = shiftl %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftRight) {
- auto* expr = Shr(3_u, 4_u);
+ Func("my_func", utils::Empty, ty.u32(), utils::Vector{Return(0_u)});
+ auto* expr = Shr(Call("my_func"), 4_u);
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1836,13 +1943,16 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 >> 4
+ EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = shiftr %1(u32), 4u
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Compound) {
- auto* expr = LogicalAnd(LessThan(1_u, Add(Shr(3_u, 4_u), 9_u)),
- GreaterThan(2.5_f, Div(6.7_f, Mul(2.3_f, 5.5_f))));
+ Func("my_func", utils::Empty, ty.f32(), utils::Vector{Return(0_f)});
+
+ auto* expr = LogicalAnd(LessThan(Call("my_func"), 2_f),
+ GreaterThan(2.5_f, Div(Call("my_func"), Mul(2.3_f, Call("my_func")))));
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1853,18 +1963,39 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 >> 4
-%2 (u32) = %1 (u32) + 9
-%3 (bool) = 1 < %2 (u32)
-%4 (f32) = 2.29999995231628417969 * 5.5
-%5 (f32) = 6.69999980926513671875 / %4 (f32)
-%6 (bool) = 2.5 > %5 (f32)
-%7 (bool) = %3 (bool) && %6 (bool)
+ EXPECT_EQ(d.AsString(), R"(%1(f32) = call my_func
+%2(bool) = lt %1(f32), 2.0f
+%3(f32) = call my_func
+%4(f32) = call my_func
+%5(f32) = mul 2.29999995231628417969f, %4(f32)
+%6(f32) = div %3(f32), %5(f32)
+%7(bool) = gt 2.5f, %6(f32)
+%8(bool) = log_and %2(bool), %7(bool)
+)");
+}
+
+TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Compound_WithConstEval) {
+ Func("my_func", utils::Vector{Param("p", ty.bool_())}, ty.bool_(), utils::Vector{Return(true)});
+ auto* expr = Call("my_func", LogicalAnd(LessThan(2.4_f, 2_f),
+ GreaterThan(2.5_f, Div(10_f, Mul(2.3_f, 9.4_f)))));
+ WrapInFunction(expr);
+
+ auto& b = CreateBuilder();
+ InjectFlowBlock();
+ auto r = b.EmitExpression(expr);
+ ASSERT_THAT(b.Diagnostics(), testing::IsEmpty());
+ ASSERT_TRUE(r);
+
+ Disassembler d(b.builder.ir);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
+ EXPECT_EQ(d.AsString(), R"(%1(bool) = call my_func, false
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_Bitcast) {
- auto* expr = Bitcast<f32>(3_u);
+ Func("my_func", utils::Empty, ty.f32(), utils::Vector{Return(0_f)});
+
+ auto* expr = Bitcast<f32>(Call("my_func"));
WrapInFunction(expr);
auto& b = CreateBuilder();
@@ -1875,7 +2006,8 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (f32) = bitcast(3)
+ EXPECT_EQ(d.AsString(), R"(%1(f32) = call my_func
+%2(f32) = bitcast %1(f32)
)");
}
@@ -1893,25 +2025,25 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (void) = discard
+ EXPECT_EQ(d.AsString(), R"(discard
)");
}
TEST_F(IR_BuilderImplTest, EmitStatement_UserFunction) {
Func("my_func", utils::Vector{Param("p", ty.f32())}, ty.void_(), utils::Empty);
- auto* stmt = CallStmt(Call("my_func", Mul(2_f, 3_f)));
+ auto* stmt = CallStmt(Call("my_func", Mul(2_a, 3_a)));
WrapInFunction(stmt);
auto& b = CreateBuilder();
+
InjectFlowBlock();
b.EmitStatement(stmt);
ASSERT_THAT(b.Diagnostics(), testing::IsEmpty());
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (f32) = 2.0 * 3.0
-%2 (void) = call(my_func, %1 (f32))
+ EXPECT_EQ(d.AsString(), R"(%1(void) = call my_func, 6.0f
)");
}
@@ -1930,7 +2062,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%1 (vec3<f32>) = construct(vec3<f32>)
+ EXPECT_EQ(d.AsString(), R"(%1(vec3<f32>) = construct
)");
}
@@ -1948,7 +2080,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%2 (vec3<f32>) = construct(vec3<f32>, 2.0, 3.0, %1 (void))
+ EXPECT_EQ(d.AsString(), R"(%2(vec3<f32>) = construct 2.0f, 3.0f, %1(void)
)");
}
@@ -1966,7 +2098,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%2 (f32) = convert(f32, i32, %1 (void))
+ EXPECT_EQ(d.AsString(), R"(%2(f32) = convert i32, %1(void)
)");
}
@@ -1979,10 +2111,10 @@
ASSERT_TRUE(r) << Error();
auto m = r.Move();
- EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
- %bb1 = Block
- Return (2.0)
-FunctionEnd
+ EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+ %fn1 = block
+ ret 2.0f
+func_end
)");
}
@@ -2001,7 +2133,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
- EXPECT_EQ(d.AsString(), R"(%2 (f32) = asin(%1 (void))
+ EXPECT_EQ(d.AsString(), R"(%2(f32) = asin %1(void)
)");
}
diff --git a/src/tint/ir/builtin.cc b/src/tint/ir/builtin.cc
index 4237797..54cf882 100644
--- a/src/tint/ir/builtin.cc
+++ b/src/tint/ir/builtin.cc
@@ -20,16 +20,17 @@
// \cond DO_NOT_DOCUMENT
namespace tint::ir {
-Builtin::Builtin(Value* result, builtin::Function func, utils::VectorRef<Value*> args)
- : Base(result, args), func_(func) {}
+Builtin::Builtin(uint32_t id,
+ const type::Type* type,
+ builtin::Function func,
+ utils::VectorRef<Value*> args)
+ : Base(id, type, args), func_(func) {}
Builtin::~Builtin() = default;
-utils::StringStream& Builtin::ToString(utils::StringStream& out) const {
- Result()->ToString(out);
- out << " = " << builtin::str(func_) << "(";
+utils::StringStream& Builtin::ToInstruction(utils::StringStream& out) const {
+ ToValue(out) << " = " << builtin::str(func_) << " ";
EmitArgs(out);
- out << ")";
return out;
}
diff --git a/src/tint/ir/builtin.h b/src/tint/ir/builtin.h
index b1fd61d..9f6f666 100644
--- a/src/tint/ir/builtin.h
+++ b/src/tint/ir/builtin.h
@@ -26,16 +26,20 @@
class Builtin : public utils::Castable<Builtin, Call> {
public:
/// Constructor
- /// @param result the result value
+ /// @param id the instruction id
+ /// @param type the result type
/// @param func the builtin function
/// @param args the conversion arguments
- Builtin(Value* result, builtin::Function func, utils::VectorRef<Value*> args);
- Builtin(const Builtin& instr) = delete;
- Builtin(Builtin&& instr) = delete;
+ Builtin(uint32_t id,
+ const type::Type* type,
+ builtin::Function func,
+ utils::VectorRef<Value*> args);
+ Builtin(const Builtin& inst) = delete;
+ Builtin(Builtin&& inst) = delete;
~Builtin() override;
- Builtin& operator=(const Builtin& instr) = delete;
- Builtin& operator=(Builtin&& instr) = delete;
+ Builtin& operator=(const Builtin& inst) = delete;
+ Builtin& operator=(Builtin&& inst) = delete;
/// @returns the builtin function
builtin::Function Func() const { return func_; }
@@ -43,7 +47,7 @@
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
- utils::StringStream& ToString(utils::StringStream& out) const override;
+ utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
const builtin::Function func_;
diff --git a/src/tint/ir/call.cc b/src/tint/ir/call.cc
index b801260..322f83d 100644
--- a/src/tint/ir/call.cc
+++ b/src/tint/ir/call.cc
@@ -18,7 +18,10 @@
namespace tint::ir {
-Call::Call(Value* result, utils::VectorRef<Value*> args) : Base(result), args_(args) {
+Call::Call() : Base() {}
+
+Call::Call(uint32_t id, const type::Type* type, utils::VectorRef<Value*> args)
+ : Base(id, type), args_(args) {
for (auto* arg : args) {
arg->AddUsage(this);
}
@@ -33,7 +36,7 @@
out << ", ";
}
first = false;
- arg->ToString(out);
+ arg->ToValue(out);
}
}
diff --git a/src/tint/ir/call.h b/src/tint/ir/call.h
index e7bf684..a49e9fa 100644
--- a/src/tint/ir/call.h
+++ b/src/tint/ir/call.h
@@ -24,16 +24,12 @@
/// A Call instruction in the IR.
class Call : public utils::Castable<Call, Instruction> {
public:
- /// Constructor
- /// @param result the result value
- /// @param args the constructor arguments
- Call(Value* result, utils::VectorRef<Value*> args);
- Call(const Call& instr) = delete;
- Call(Call&& instr) = delete;
+ Call(const Call& inst) = delete;
+ Call(Call&& inst) = delete;
~Call() override;
- Call& operator=(const Call& instr) = delete;
- Call& operator=(Call&& instr) = delete;
+ Call& operator=(const Call& inst) = delete;
+ Call& operator=(Call&& inst) = delete;
/// @returns the constructor arguments
utils::VectorRef<Value*> Args() const { return args_; }
@@ -42,6 +38,15 @@
/// @param out the output stream
void EmitArgs(utils::StringStream& out) const;
+ protected:
+ /// Constructor
+ Call();
+ /// Constructor
+ /// @param id the instruction id
+ /// @param type the result type
+ /// @param args the constructor arguments
+ Call(uint32_t id, const type::Type* type, utils::VectorRef<Value*> args);
+
private:
utils::Vector<Value*, 1> args_;
};
diff --git a/src/tint/ir/constant.cc b/src/tint/ir/constant.cc
index 4036616..0666e91 100644
--- a/src/tint/ir/constant.cc
+++ b/src/tint/ir/constant.cc
@@ -29,33 +29,39 @@
Constant::~Constant() = default;
-utils::StringStream& Constant::ToString(utils::StringStream& out) const {
+utils::StringStream& Constant::ToValue(utils::StringStream& out) const {
std::function<void(const constant::Value*)> emit = [&](const constant::Value* c) {
Switch(
c,
[&](const constant::Scalar<AFloat>* scalar) { out << scalar->ValueAs<AFloat>().value; },
[&](const constant::Scalar<AInt>* scalar) { out << scalar->ValueAs<AInt>().value; },
- [&](const constant::Scalar<i32>* scalar) { out << scalar->ValueAs<i32>().value; },
- [&](const constant::Scalar<u32>* scalar) { out << scalar->ValueAs<u32>().value; },
- [&](const constant::Scalar<f32>* scalar) { out << scalar->ValueAs<f32>().value; },
- [&](const constant::Scalar<f16>* scalar) { out << scalar->ValueAs<f16>().value; },
+ [&](const constant::Scalar<i32>* scalar) {
+ out << scalar->ValueAs<i32>().value << "i";
+ },
+ [&](const constant::Scalar<u32>* scalar) {
+ out << scalar->ValueAs<u32>().value << "u";
+ },
+ [&](const constant::Scalar<f32>* scalar) {
+ out << scalar->ValueAs<f32>().value << "f";
+ },
+ [&](const constant::Scalar<f16>* scalar) {
+ out << scalar->ValueAs<f16>().value << "h";
+ },
[&](const constant::Scalar<bool>* scalar) {
out << (scalar->ValueAs<bool>() ? "true" : "false");
},
[&](const constant::Splat* splat) {
- out << splat->Type()->FriendlyName() << "(";
+ out << splat->Type()->FriendlyName() << " ";
emit(splat->Index(0));
- out << ")";
},
[&](const constant::Composite* composite) {
- out << composite->Type()->FriendlyName() << "(";
+ out << composite->Type()->FriendlyName() << " ";
for (const auto* elem : composite->elements) {
if (elem != composite->elements[0]) {
out << ", ";
}
emit(elem);
}
- out << ")";
});
};
emit(value);
diff --git a/src/tint/ir/constant.h b/src/tint/ir/constant.h
index 207af5d..2413721 100644
--- a/src/tint/ir/constant.h
+++ b/src/tint/ir/constant.h
@@ -35,7 +35,7 @@
/// Write the constant to the given stream
/// @param out the stream to write to
/// @returns the stream
- utils::StringStream& ToString(utils::StringStream& out) const override;
+ utils::StringStream& ToValue(utils::StringStream& out) 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 f407cdb..43d92b4 100644
--- a/src/tint/ir/constant_test.cc
+++ b/src/tint/ir/constant_test.cc
@@ -31,8 +31,8 @@
auto* c = b.builder.Constant(1.2_f);
EXPECT_EQ(1.2_f, c->value->As<constant::Scalar<f32>>()->ValueAs<f32>());
- c->ToString(str);
- EXPECT_EQ("1.20000004768371582031", str.str());
+ c->ToValue(str);
+ EXPECT_EQ("1.20000004768371582031f", str.str());
EXPECT_TRUE(c->value->Is<constant::Scalar<f32>>());
EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
@@ -49,8 +49,8 @@
auto* c = b.builder.Constant(1.1_h);
EXPECT_EQ(1.1_h, c->value->As<constant::Scalar<f16>>()->ValueAs<f16>());
- c->ToString(str);
- EXPECT_EQ("1.099609375", str.str());
+ c->ToValue(str);
+ EXPECT_EQ("1.099609375h", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
EXPECT_TRUE(c->value->Is<constant::Scalar<f16>>());
@@ -67,8 +67,8 @@
auto* c = b.builder.Constant(1_i);
EXPECT_EQ(1_i, c->value->As<constant::Scalar<i32>>()->ValueAs<i32>());
- c->ToString(str);
- EXPECT_EQ("1", str.str());
+ c->ToValue(str);
+ EXPECT_EQ("1i", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
@@ -85,8 +85,8 @@
auto* c = b.builder.Constant(2_u);
EXPECT_EQ(2_u, c->value->As<constant::Scalar<u32>>()->ValueAs<u32>());
- c->ToString(str);
- EXPECT_EQ("2", str.str());
+ c->ToValue(str);
+ EXPECT_EQ("2u", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
@@ -104,7 +104,7 @@
auto* c = b.builder.Constant(false);
EXPECT_FALSE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
- c->ToString(str);
+ c->ToValue(str);
EXPECT_EQ("false", str.str());
}
@@ -113,7 +113,7 @@
auto c = b.builder.Constant(true);
EXPECT_TRUE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
- c->ToString(str);
+ c->ToValue(str);
EXPECT_EQ("true", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
diff --git a/src/tint/ir/construct.cc b/src/tint/ir/construct.cc
index 595075b..1507e8f 100644
--- a/src/tint/ir/construct.cc
+++ b/src/tint/ir/construct.cc
@@ -19,18 +19,14 @@
namespace tint::ir {
-Construct::Construct(Value* result, utils::VectorRef<Value*> args) : Base(result, args) {}
+Construct::Construct(uint32_t id, const type::Type* type, utils::VectorRef<Value*> args)
+ : Base(id, type, args) {}
Construct::~Construct() = default;
-utils::StringStream& Construct::ToString(utils::StringStream& out) const {
- Result()->ToString(out);
- out << " = construct(" << Result()->Type()->FriendlyName();
- if (!Args().IsEmpty()) {
- out << ", ";
- EmitArgs(out);
- }
- out << ")";
+utils::StringStream& Construct::ToInstruction(utils::StringStream& out) const {
+ ToValue(out) << " = construct ";
+ EmitArgs(out);
return out;
}
diff --git a/src/tint/ir/construct.h b/src/tint/ir/construct.h
index c9d1819..1cc0102 100644
--- a/src/tint/ir/construct.h
+++ b/src/tint/ir/construct.h
@@ -25,20 +25,21 @@
class Construct : public utils::Castable<Construct, Call> {
public:
/// Constructor
- /// @param result the result value
+ /// @param id the instruction id
+ /// @param type the result type
/// @param args the constructor arguments
- Construct(Value* result, utils::VectorRef<Value*> args);
- Construct(const Construct& instr) = delete;
- Construct(Construct&& instr) = delete;
+ Construct(uint32_t id, const type::Type* type, utils::VectorRef<Value*> args);
+ Construct(const Construct& inst) = delete;
+ Construct(Construct&& inst) = delete;
~Construct() override;
- Construct& operator=(const Construct& instr) = delete;
- Construct& operator=(Construct&& instr) = delete;
+ Construct& operator=(const Construct& inst) = delete;
+ Construct& operator=(Construct&& inst) = delete;
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
- utils::StringStream& ToString(utils::StringStream& out) const override;
+ utils::StringStream& ToInstruction(utils::StringStream& out) const override;
};
} // namespace tint::ir
diff --git a/src/tint/ir/convert.cc b/src/tint/ir/convert.cc
index ed31250..7ffd6f5 100644
--- a/src/tint/ir/convert.cc
+++ b/src/tint/ir/convert.cc
@@ -19,17 +19,17 @@
namespace tint::ir {
-Convert::Convert(Value* result, const type::Type* from, utils::VectorRef<Value*> args)
- : Base(result, args), from_(from) {}
+Convert::Convert(uint32_t id,
+ const type::Type* to_type,
+ const type::Type* from_type,
+ utils::VectorRef<Value*> args)
+ : Base(id, to_type, args), from_type_(from_type) {}
Convert::~Convert() = default;
-utils::StringStream& Convert::ToString(utils::StringStream& out) const {
- Result()->ToString(out);
- out << " = convert(" << Result()->Type()->FriendlyName() << ", " << from_->FriendlyName()
- << ", ";
+utils::StringStream& Convert::ToInstruction(utils::StringStream& out) const {
+ ToValue(out) << " = convert " << from_type_->FriendlyName() << ", ";
EmitArgs(out);
- out << ")";
return out;
}
diff --git a/src/tint/ir/convert.h b/src/tint/ir/convert.h
index d157e03..c164a45 100644
--- a/src/tint/ir/convert.h
+++ b/src/tint/ir/convert.h
@@ -26,29 +26,33 @@
class Convert : public utils::Castable<Convert, Call> {
public:
/// Constructor
- /// @param result the result value
- /// @param from the type being converted from
+ /// @param id the instruction id
+ /// @param result_type the result type
+ /// @param from_type the type being converted from
/// @param args the conversion arguments
- Convert(Value* result, const type::Type* from, utils::VectorRef<Value*> args);
- Convert(const Convert& instr) = delete;
- Convert(Convert&& instr) = delete;
+ Convert(uint32_t id,
+ const type::Type* result_type,
+ const type::Type* from_type,
+ utils::VectorRef<Value*> args);
+ Convert(const Convert& inst) = delete;
+ Convert(Convert&& inst) = delete;
~Convert() override;
- Convert& operator=(const Convert& instr) = delete;
- Convert& operator=(Convert&& instr) = delete;
+ Convert& operator=(const Convert& inst) = delete;
+ Convert& operator=(Convert&& inst) = delete;
/// @returns the from type
- const type::Type* From() const { return from_; }
+ const type::Type* FromType() const { return from_type_; }
/// @returns the to type
- const type::Type* To() const { return Result()->Type(); }
+ const type::Type* ToType() const { return Type(); }
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
- utils::StringStream& ToString(utils::StringStream& out) const override;
+ utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
- const type::Type* from_ = nullptr;
+ const type::Type* from_type_ = nullptr;
};
} // namespace tint::ir
diff --git a/src/tint/ir/converter.cc b/src/tint/ir/converter.cc
new file mode 100644
index 0000000..e89be3a
--- /dev/null
+++ b/src/tint/ir/converter.cc
@@ -0,0 +1,42 @@
+// 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/ir/converter.h"
+
+#include "src/tint/ir/builder_impl.h"
+#include "src/tint/program.h"
+
+namespace tint::ir {
+
+// static
+Converter::Result Converter::FromProgram(const Program* program) {
+ if (!program->IsValid()) {
+ return Result{std::string("input program is not valid")};
+ }
+
+ BuilderImpl b(program);
+ auto r = b.Build();
+ if (!r) {
+ return b.Diagnostics().str();
+ }
+
+ return Result{r.Move()};
+}
+
+// static
+const Program* Converter::ToProgram() {
+ return nullptr;
+}
+
+} // namespace tint::ir
diff --git a/src/tint/ir/converter.h b/src/tint/ir/converter.h
new file mode 100644
index 0000000..8defd83
--- /dev/null
+++ b/src/tint/ir/converter.h
@@ -0,0 +1,54 @@
+// 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_IR_CONVERTER_H_
+#define SRC_TINT_IR_CONVERTER_H_
+
+#include <string>
+
+#include "src/tint/ir/module.h"
+#include "src/tint/utils/result.h"
+
+// Forward Declarations
+namespace tint {
+class Program;
+} // namespace tint
+
+namespace tint::ir {
+
+/// Class for converting into and out of IR.
+class Converter {
+ public:
+ /// The result type for the FromProgram method.
+ using Result = utils::Result<Module, std::string>;
+
+ /// Builds an ir::Module from the given Program
+ /// @param program the Program to use.
+ /// @returns the `utiils::Result` of generating the IR. The result will contain the `ir::Module`
+ /// on success, otherwise the `std::string` error.
+ ///
+ /// @note this assumes the program |IsValid|, and has had const-eval done so
+ /// any abstract values have been calculated and converted into the relevant
+ /// concrete types.
+ static Result FromProgram(const Program* program);
+
+ /// Converts the module back to a Program
+ /// @returns the resulting program, or nullptr on error
+ /// (Note, this will probably turn into a utils::Result, just stubbing for now)
+ static const Program* ToProgram();
+};
+
+} // namespace tint::ir
+
+#endif // SRC_TINT_IR_CONVERTER_H_
diff --git a/src/tint/ir/disassembler.cc b/src/tint/ir/disassembler.cc
index c3bb006..2b8de0b 100644
--- a/src/tint/ir/disassembler.cc
+++ b/src/tint/ir/disassembler.cc
@@ -20,6 +20,7 @@
#include "src/tint/ir/switch.h"
#include "src/tint/ir/terminator.h"
#include "src/tint/switch.h"
+#include "src/tint/utils/scoped_assignment.h"
namespace tint::ir {
namespace {
@@ -62,9 +63,9 @@
}
void Disassembler::EmitBlockInstructions(const Block* b) {
- for (const auto* instr : b->instructions) {
+ for (const auto* inst : b->instructions) {
Indent();
- instr->ToString(out_) << std::endl;
+ inst->ToInstruction(out_) << std::endl;
}
}
@@ -89,7 +90,9 @@
tint::Switch(
node,
[&](const ir::Function* f) {
- Indent() << "%bb" << GetIdForNode(f) << " = Function " << f->name.Name() << std::endl;
+ TINT_SCOPED_ASSIGNMENT(in_function_, true);
+
+ Indent() << "%fn" << GetIdForNode(f) << " = func " << f->name.Name() << std::endl;
{
ScopedIndent func_indent(&indent_size_);
@@ -101,27 +104,28 @@
[&](const ir::Block* b) {
// If this block is dead, nothing to do
if (b->IsDead()) {
- Indent() << "# Dead" << std::endl;
return;
}
- Indent() << "%bb" << GetIdForNode(b) << " = Block" << std::endl;
+ Indent() << "%fn" << GetIdForNode(b) << " = block" << std::endl;
EmitBlockInstructions(b);
if (b->branch.target->Is<Terminator>()) {
- Indent() << "Return";
+ Indent() << "ret";
} else {
- Indent() << "BranchTo "
- << "%bb" << GetIdForNode(b->branch.target);
+ Indent() << "branch "
+ << "%fn" << GetIdForNode(b->branch.target);
}
- out_ << " (";
- for (const auto* v : b->branch.args) {
- if (v != b->branch.args.Front()) {
- out_ << ", ";
+ if (!b->branch.args.IsEmpty()) {
+ out_ << " ";
+ for (const auto* v : b->branch.args) {
+ if (v != b->branch.args.Front()) {
+ out_ << ", ";
+ }
+ v->ToValue(out_);
}
- v->ToString(out_);
}
- out_ << ")" << std::endl;
+ out_ << std::endl;
if (!b->branch.target->Is<Terminator>()) {
out_ << std::endl;
@@ -130,15 +134,37 @@
Walk(b->branch.target);
},
[&](const ir::Switch* s) {
- Indent() << "%bb" << GetIdForNode(s) << " = Switch (";
- s->condition->ToString(out_);
- out_ << ")" << std::endl;
+ Indent() << "%fn" << GetIdForNode(s) << " = switch ";
+ s->condition->ToValue(out_);
+ out_ << " [";
+ for (const auto& c : s->cases) {
+ if (&c != &s->cases.Front()) {
+ out_ << ", ";
+ }
+ out_ << "c: (";
+ for (const auto& selector : c.selectors) {
+ if (&selector != &c.selectors.Front()) {
+ out_ << " ";
+ }
+
+ if (selector.IsDefault()) {
+ out_ << "default";
+ } else {
+ selector.val->ToValue(out_);
+ }
+ }
+ out_ << ", %fn" << GetIdForNode(c.start.target) << ")";
+ }
+ if (s->merge.target->IsConnected()) {
+ out_ << ", m: %fn" << GetIdForNode(s->merge.target);
+ }
+ out_ << "]" << std::endl;
{
ScopedIndent switch_indent(&indent_size_);
ScopedStopNode scope(&stop_nodes_, s->merge.target);
for (const auto& c : s->cases) {
- Indent() << "# Case ";
+ Indent() << "# case ";
for (const auto& selector : c.selectors) {
if (&selector != &c.selectors.Front()) {
out_ << " ";
@@ -147,7 +173,7 @@
if (selector.IsDefault()) {
out_ << "default";
} else {
- selector.val->ToString(out_);
+ selector.val->ToValue(out_);
}
}
out_ << std::endl;
@@ -155,13 +181,20 @@
}
}
- Indent() << "# Switch Merge" << std::endl;
- Walk(s->merge.target);
+ if (s->merge.target->IsConnected()) {
+ Indent() << "# switch merge" << std::endl;
+ Walk(s->merge.target);
+ }
},
[&](const ir::If* i) {
- Indent() << "%bb" << GetIdForNode(i) << " = if (";
- i->condition->ToString(out_);
- out_ << ")" << std::endl;
+ Indent() << "%fn" << GetIdForNode(i) << " = if ";
+ i->condition->ToValue(out_);
+ out_ << " [t: %fn" << GetIdForNode(i->true_.target) << ", f: %fn"
+ << GetIdForNode(i->false_.target);
+ if (i->merge.target->IsConnected()) {
+ out_ << ", m: %fn" << GetIdForNode(i->merge.target);
+ }
+ out_ << "]" << std::endl;
{
ScopedIndent if_indent(&indent_size_);
@@ -174,13 +207,23 @@
Walk(i->false_.target);
}
- if (!i->merge.target->IsDisconnected()) {
+ if (i->merge.target->IsConnected()) {
Indent() << "# if merge" << std::endl;
Walk(i->merge.target);
}
},
[&](const ir::Loop* l) {
- Indent() << "%bb" << GetIdForNode(l) << " = loop" << std::endl;
+ Indent() << "%fn" << GetIdForNode(l) << " = loop [s: %fn"
+ << GetIdForNode(l->start.target);
+
+ if (l->continuing.target->IsConnected()) {
+ out_ << ", c: %fn" << GetIdForNode(l->continuing.target);
+ }
+ if (l->merge.target->IsConnected()) {
+ out_ << ", m: %fn" << GetIdForNode(l->merge.target);
+ }
+ out_ << "]" << std::endl;
+
{
ScopedStopNode loop_scope(&stop_nodes_, l->merge.target);
ScopedIndent loop_indent(&indent_size_);
@@ -190,18 +233,30 @@
Walk(l->start.target);
}
- Indent() << "# loop continuing" << std::endl;
- Walk(l->continuing.target);
+ if (l->continuing.target->IsConnected()) {
+ Indent() << "# loop continuing" << std::endl;
+ Walk(l->continuing.target);
+ }
}
- Indent() << "# loop merge" << std::endl;
- Walk(l->merge.target);
+ if (l->merge.target->IsConnected()) {
+ Indent() << "# loop merge" << std::endl;
+ Walk(l->merge.target);
+ }
},
- [&](const ir::Terminator*) { Indent() << "FunctionEnd" << std::endl
- << std::endl; });
+ [&](const ir::Terminator*) {
+ if (in_function_) {
+ Indent() << "func_end" << std::endl;
+ }
+ out_ << std::endl;
+ });
}
std::string Disassembler::Disassemble() {
+ if (mod_.root_block) {
+ Walk(mod_.root_block);
+ }
+
for (const auto* func : mod_.functions) {
Walk(func);
}
diff --git a/src/tint/ir/disassembler.h b/src/tint/ir/disassembler.h
index eee6b76..04b3997 100644
--- a/src/tint/ir/disassembler.h
+++ b/src/tint/ir/disassembler.h
@@ -56,6 +56,7 @@
std::unordered_map<const FlowNode*, size_t> flow_node_to_id_;
size_t next_node_id_ = 0;
uint32_t indent_size_ = 0;
+ bool in_function_ = false;
};
} // namespace tint::ir
diff --git a/src/tint/ir/discard.cc b/src/tint/ir/discard.cc
index 1d179b5..bc7bdc3 100644
--- a/src/tint/ir/discard.cc
+++ b/src/tint/ir/discard.cc
@@ -19,13 +19,12 @@
namespace tint::ir {
-Discard::Discard(Value* result) : Base(result) {}
+Discard::Discard() : Base() {}
Discard::~Discard() = default;
-utils::StringStream& Discard::ToString(utils::StringStream& out) const {
- Result()->ToString(out);
- out << " = discard";
+utils::StringStream& Discard::ToInstruction(utils::StringStream& out) const {
+ out << "discard";
return out;
}
diff --git a/src/tint/ir/discard.h b/src/tint/ir/discard.h
index b27dc9d..456c8d5 100644
--- a/src/tint/ir/discard.h
+++ b/src/tint/ir/discard.h
@@ -15,29 +15,29 @@
#ifndef SRC_TINT_IR_DISCARD_H_
#define SRC_TINT_IR_DISCARD_H_
-#include "src/tint/ir/instruction.h"
+#include "src/tint/debug.h"
+#include "src/tint/ir/call.h"
#include "src/tint/utils/castable.h"
#include "src/tint/utils/string_stream.h"
namespace tint::ir {
/// A discard instruction in the IR.
-class Discard : public utils::Castable<Discard, Instruction> {
+class Discard : public utils::Castable<Discard, Call> {
public:
/// Constructor
- /// @param result the result id
- explicit Discard(Value* result);
- Discard(const Discard& instr) = delete;
- Discard(Discard&& instr) = delete;
+ Discard();
+ Discard(const Discard& inst) = delete;
+ Discard(Discard&& inst) = delete;
~Discard() override;
- Discard& operator=(const Discard& instr) = delete;
- Discard& operator=(Discard&& instr) = delete;
+ Discard& operator=(const Discard& inst) = delete;
+ Discard& operator=(Discard&& inst) = delete;
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
- utils::StringStream& ToString(utils::StringStream& out) const override;
+ utils::StringStream& ToInstruction(utils::StringStream& out) const override;
};
} // namespace tint::ir
diff --git a/src/tint/ir/discard_test.cc b/src/tint/ir/discard_test.cc
index 0f2fb5d..32b5c1e 100644
--- a/src/tint/ir/discard_test.cc
+++ b/src/tint/ir/discard_test.cc
@@ -24,17 +24,12 @@
TEST_F(IR_InstructionTest, Discard) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr = b.builder.Discard();
-
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
- ASSERT_NE(instr->Result()->Type(), nullptr);
- ASSERT_NE(instr->Result()->Type()->As<type::Void>(), nullptr);
+ const auto* inst = b.builder.Discard();
+ ASSERT_TRUE(inst->Is<ir::Discard>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (void) = discard");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "discard");
}
} // namespace
diff --git a/src/tint/ir/flow_node.h b/src/tint/ir/flow_node.h
index 2a91674..905f077 100644
--- a/src/tint/ir/flow_node.h
+++ b/src/tint/ir/flow_node.h
@@ -32,8 +32,11 @@
/// - Node is a continue target outside control flow (loop that returns)
utils::Vector<FlowNode*, 2> inbound_branches;
- /// @returns true if this node has no inbound branches
- bool IsDisconnected() const { return inbound_branches.IsEmpty(); }
+ /// @returns true if this node has inbound branches and branches out
+ bool IsConnected() const { return !IsDead() && !inbound_branches.IsEmpty(); }
+
+ /// @returns true if the node does not branch out
+ virtual bool IsDead() const { return false; }
protected:
/// Constructor
diff --git a/src/tint/ir/instruction.cc b/src/tint/ir/instruction.cc
index 46644dd..3e3192f 100644
--- a/src/tint/ir/instruction.cc
+++ b/src/tint/ir/instruction.cc
@@ -18,10 +18,9 @@
namespace tint::ir {
-Instruction::Instruction(Value* result) : result_(result) {
- TINT_ASSERT(IR, result_);
- result_->AddUsage(this);
-}
+Instruction::Instruction() = default;
+
+Instruction::Instruction(uint32_t id, const type::Type* ty) : id_(id), type_(ty) {}
Instruction::~Instruction() = default;
diff --git a/src/tint/ir/instruction.h b/src/tint/ir/instruction.h
index df965e4..f2dac09 100644
--- a/src/tint/ir/instruction.h
+++ b/src/tint/ir/instruction.h
@@ -22,31 +22,46 @@
namespace tint::ir {
/// An instruction in the IR.
-class Instruction : public utils::Castable<Instruction> {
+class Instruction : public utils::Castable<Instruction, Value> {
public:
- Instruction(const Instruction& instr) = delete;
- Instruction(Instruction&& instr) = delete;
+ Instruction(const Instruction& inst) = delete;
+ Instruction(Instruction&& inst) = delete;
/// Destructor
~Instruction() override;
- Instruction& operator=(const Instruction& instr) = delete;
- Instruction& operator=(Instruction&& instr) = delete;
+ Instruction& operator=(const Instruction& inst) = delete;
+ Instruction& operator=(Instruction&& inst) = delete;
- /// @returns the result value for the instruction
- Value* Result() const { return result_; }
+ /// @returns the type of the value
+ const type::Type* Type() const override { return type_; }
+
+ /// Write the value to the given stream
+ /// @param out the stream to write to
+ /// @returns the stream
+ utils::StringStream& ToValue(utils::StringStream& out) const override {
+ out << "%" << std::to_string(id_);
+ if (type_ != nullptr) {
+ out << "(" << Type()->FriendlyName() << ")";
+ }
+ return out;
+ }
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
- virtual utils::StringStream& ToString(utils::StringStream& out) const = 0;
+ virtual utils::StringStream& ToInstruction(utils::StringStream& out) const = 0;
protected:
/// Constructor
- /// @param result the result value
- explicit Instruction(Value* result);
+ Instruction();
+ /// Constructor
+ /// @param id the instruction id
+ /// @param type the result type
+ Instruction(uint32_t id, const type::Type* type);
private:
- Value* result_ = nullptr;
+ uint32_t id_ = 0;
+ const type::Type* type_ = nullptr;
};
} // namespace tint::ir
diff --git a/src/tint/ir/module.cc b/src/tint/ir/module.cc
index e434888..133d364 100644
--- a/src/tint/ir/module.cc
+++ b/src/tint/ir/module.cc
@@ -14,26 +14,8 @@
#include "src/tint/ir/module.h"
-#include "src/tint/ir/builder_impl.h"
-#include "src/tint/program.h"
-
namespace tint::ir {
-// static
-Module::Result Module::FromProgram(const Program* program) {
- if (!program->IsValid()) {
- return Result{std::string("input program is not valid")};
- }
-
- BuilderImpl b(program);
- auto r = b.Build();
- if (!r) {
- return b.Diagnostics().str();
- }
-
- return Result{r.Move()};
-}
-
Module::Module() = default;
Module::Module(Module&&) = default;
@@ -42,8 +24,4 @@
Module& Module::operator=(Module&&) = default;
-const Program* Module::ToProgram() const {
- return nullptr;
-}
-
} // namespace tint::ir
diff --git a/src/tint/ir/module.h b/src/tint/ir/module.h
index 5cfc883..ebf9209 100644
--- a/src/tint/ir/module.h
+++ b/src/tint/ir/module.h
@@ -28,29 +28,11 @@
#include "src/tint/utils/result.h"
#include "src/tint/utils/vector.h"
-// Forward Declarations
-namespace tint {
-class Program;
-} // namespace tint
-
namespace tint::ir {
/// Main module class for the IR.
class Module {
public:
- /// The result type for the FromProgram method.
- using Result = utils::Result<Module, std::string>;
-
- /// Builds an ir::Module from the given Program
- /// @param program the Program to use.
- /// @returns the `utiils::Result` of generating the IR. The result will contain the `ir::Module`
- /// on success, otherwise the `std::string` error.
- ///
- /// @note this assumes the program |IsValid|, and has had const-eval done so
- /// any abstract values have been calculated and converted into the relevant
- /// concrete types.
- static Result FromProgram(const Program* program);
-
/// Constructor
Module();
/// Move constructor
@@ -64,11 +46,6 @@
/// @returns a reference to this module
Module& operator=(Module&& o);
- /// Converts the module back to a Program
- /// @returns the resulting program, or nullptr on error
- /// (Note, this will probably turn into a utils::Result, just stubbing for now)
- const Program* ToProgram() const;
-
private:
/// Program Id required to create other components
ProgramID prog_id_;
@@ -88,6 +65,9 @@
/// List of indexes into the functions list for the entry points
utils::Vector<Function*, 8> entry_points;
+ /// The block containing module level declarations, if any exist.
+ Block* root_block = nullptr;
+
/// The type manager for the module
type::Manager types;
diff --git a/src/tint/ir/runtime.cc b/src/tint/ir/runtime.cc
deleted file mode 100644
index a1f485d..0000000
--- a/src/tint/ir/runtime.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2022 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/ir/runtime.h"
-
-#include <string>
-
-TINT_INSTANTIATE_TYPEINFO(tint::ir::Runtime);
-
-namespace tint::ir {
-
-Runtime::Runtime(const type::Type* type, Id id) : type_(type), id_(id) {}
-
-Runtime::~Runtime() = default;
-
-utils::StringStream& Runtime::ToString(utils::StringStream& out) const {
- out << "%" << std::to_string(AsId()) << " (" << type_->FriendlyName() << ")";
- return out;
-}
-
-} // namespace tint::ir
diff --git a/src/tint/ir/runtime.h b/src/tint/ir/runtime.h
deleted file mode 100644
index 6e2558c..0000000
--- a/src/tint/ir/runtime.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2022 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_IR_RUNTIME_H_
-#define SRC_TINT_IR_RUNTIME_H_
-
-#include "src/tint/ir/value.h"
-#include "src/tint/utils/string_stream.h"
-
-namespace tint::ir {
-
-/// Runtime value in the IR.
-class Runtime : public utils::Castable<Runtime, Value> {
- public:
- /// A value id.
- using Id = uint32_t;
-
- /// Constructor
- /// @param type the type of the value
- /// @param id the id for the value
- Runtime(const type::Type* type, Id id);
-
- /// Destructor
- ~Runtime() override;
-
- Runtime(const Runtime&) = delete;
- Runtime(Runtime&&) = delete;
-
- Runtime& operator=(const Runtime&) = delete;
- Runtime& operator=(Runtime&&) = delete;
-
- /// @returns the value data as an `Id`.
- Id AsId() const { return id_; }
-
- /// @returns the type of the value
- const type::Type* Type() const override { return type_; }
-
- /// Write the id to the given stream
- /// @param out the stream to write to
- /// @returns the stream
- utils::StringStream& ToString(utils::StringStream& out) const override;
-
- private:
- const type::Type* type_ = nullptr;
- Id id_ = 0;
-};
-
-} // namespace tint::ir
-
-#endif // SRC_TINT_IR_RUNTIME_H_
diff --git a/src/tint/ir/runtime_test.cc b/src/tint/ir/runtime_test.cc
deleted file mode 100644
index 7959909..0000000
--- a/src/tint/ir/runtime_test.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2022 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/ir/runtime.h"
-#include "src/tint/ir/test_helper.h"
-#include "src/tint/utils/string_stream.h"
-
-namespace tint::ir {
-namespace {
-
-using namespace tint::number_suffixes; // NOLINT
-
-using IR_RuntimeTest = TestHelper;
-
-TEST_F(IR_RuntimeTest, id) {
- auto& b = CreateEmptyBuilder();
-
- utils::StringStream str;
-
- b.builder.next_runtime_id = Runtime::Id(4);
- auto* val = b.builder.Runtime(b.builder.ir.types.Get<type::I32>());
- EXPECT_EQ(4u, val->AsId());
-
- val->ToString(str);
- EXPECT_EQ("%4 (i32)", str.str());
-}
-
-} // namespace
-} // namespace tint::ir
diff --git a/src/tint/ir/store.cc b/src/tint/ir/store.cc
index 32162c3..8d35214 100644
--- a/src/tint/ir/store.cc
+++ b/src/tint/ir/store.cc
@@ -19,17 +19,19 @@
namespace tint::ir {
-Store::Store(Value* to, Value* from) : Base(to), from_(from) {
+Store::Store(Value* to, Value* from) : Base(), to_(to), from_(from) {
+ TINT_ASSERT(IR, to_);
TINT_ASSERT(IR, from_);
+ to_->AddUsage(this);
from_->AddUsage(this);
}
Store::~Store() = default;
-utils::StringStream& Store::ToString(utils::StringStream& out) const {
- Result()->ToString(out);
- out << " = ";
- from_->ToString(out);
+utils::StringStream& Store::ToInstruction(utils::StringStream& out) const {
+ out << "store ";
+ to_->ToValue(out) << ", ";
+ from_->ToValue(out);
return out;
}
diff --git a/src/tint/ir/store.h b/src/tint/ir/store.h
index 57544fc..ea5550d 100644
--- a/src/tint/ir/store.h
+++ b/src/tint/ir/store.h
@@ -28,22 +28,25 @@
/// @param to the value to store too
/// @param from the value being stored from
Store(Value* to, Value* from);
- Store(const Store& instr) = delete;
- Store(Store&& instr) = delete;
+ Store(const Store& inst) = delete;
+ Store(Store&& inst) = delete;
~Store() override;
- Store& operator=(const Store& instr) = delete;
- Store& operator=(Store&& instr) = delete;
+ Store& operator=(const Store& inst) = delete;
+ Store& operator=(Store&& inst) = delete;
+ /// @returns the value being stored too
+ const Value* to() const { return to_; }
/// @returns the value being stored
const Value* from() const { return from_; }
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
- utils::StringStream& ToString(utils::StringStream& out) const override;
+ utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
+ Value* to_ = nullptr;
Value* from_ = nullptr;
};
diff --git a/src/tint/ir/store_test.cc b/src/tint/ir/store_test.cc
index e0632dd..82347dc 100644
--- a/src/tint/ir/store_test.cc
+++ b/src/tint/ir/store_test.cc
@@ -26,39 +26,37 @@
TEST_F(IR_InstructionTest, CreateStore) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
+ // TODO(dsinclair): This is wrong, but we don't have anything correct to store too at the
+ // moment.
+ auto* to = b.builder.Discard();
+ const auto* inst = b.builder.Store(to, b.builder.Constant(4_i));
- auto* rt = b.builder.Runtime(b.builder.ir.types.Get<type::I32>());
- const auto* instr = b.builder.Store(rt, b.builder.Constant(4_i));
+ ASSERT_TRUE(inst->Is<Store>());
+ ASSERT_EQ(inst->to(), to);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- ASSERT_NE(instr->Result()->Type(), nullptr);
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->from()->Is<Constant>());
- auto lhs = instr->from()->As<Constant>()->value;
+ ASSERT_TRUE(inst->from()->Is<Constant>());
+ auto lhs = inst->from()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = 4");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "store %0, 4i");
}
TEST_F(IR_InstructionTest, Store_Usage) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
- auto* rt = b.builder.Runtime(b.builder.ir.types.Get<type::I32>());
- const auto* instr = b.builder.Store(rt, b.builder.Constant(4_i));
+ auto* to = b.builder.Discard();
+ const auto* inst = b.builder.Store(to, b.builder.Constant(4_i));
- ASSERT_NE(instr->Result(), nullptr);
- ASSERT_EQ(instr->Result()->Usage().Length(), 1u);
- EXPECT_EQ(instr->Result()->Usage()[0], instr);
+ ASSERT_NE(inst->to(), nullptr);
+ ASSERT_EQ(inst->to()->Usage().Length(), 1u);
+ EXPECT_EQ(inst->to()->Usage()[0], inst);
- ASSERT_NE(instr->from(), nullptr);
- ASSERT_EQ(instr->from()->Usage().Length(), 1u);
- EXPECT_EQ(instr->from()->Usage()[0], instr);
+ ASSERT_NE(inst->from(), nullptr);
+ ASSERT_EQ(inst->from()->Usage().Length(), 1u);
+ EXPECT_EQ(inst->from()->Usage()[0], inst);
}
} // namespace
diff --git a/src/tint/ir/unary.cc b/src/tint/ir/unary.cc
index 532efcc..f3c4f24 100644
--- a/src/tint/ir/unary.cc
+++ b/src/tint/ir/unary.cc
@@ -19,34 +19,35 @@
namespace tint::ir {
-Unary::Unary(Kind kind, Value* result, Value* val) : Base(result), kind_(kind), val_(val) {
+Unary::Unary(uint32_t id, Kind kind, const type::Type* type, Value* val)
+ : Base(id, type), kind_(kind), val_(val) {
TINT_ASSERT(IR, val_);
val_->AddUsage(this);
}
Unary::~Unary() = default;
-utils::StringStream& Unary::ToString(utils::StringStream& out) const {
- Result()->ToString(out) << " = ";
+utils::StringStream& Unary::ToInstruction(utils::StringStream& out) const {
+ ToValue(out) << " = ";
switch (GetKind()) {
case Unary::Kind::kAddressOf:
- out << "&";
+ out << "addr_of";
break;
case Unary::Kind::kComplement:
- out << "~";
+ out << "bit_complement";
break;
case Unary::Kind::kIndirection:
- out << "*";
+ out << "indirection";
break;
case Unary::Kind::kNegation:
- out << "-";
+ out << "negation";
break;
case Unary::Kind::kNot:
- out << "!";
+ out << "log_not";
break;
}
- val_->ToString(out);
-
+ out << " ";
+ val_->ToValue(out);
return out;
}
diff --git a/src/tint/ir/unary.h b/src/tint/ir/unary.h
index 0337b4f..ce3e5d7 100644
--- a/src/tint/ir/unary.h
+++ b/src/tint/ir/unary.h
@@ -34,16 +34,17 @@
};
/// Constructor
+ /// @param id the instruction id
/// @param kind the kind of unary instruction
- /// @param result the result value
+ /// @param type the result type
/// @param val the lhs of the instruction
- Unary(Kind kind, Value* result, Value* val);
- Unary(const Unary& instr) = delete;
- Unary(Unary&& instr) = delete;
+ Unary(uint32_t id, Kind kind, const type::Type* type, Value* val);
+ Unary(const Unary& inst) = delete;
+ Unary(Unary&& inst) = delete;
~Unary() override;
- Unary& operator=(const Unary& instr) = delete;
- Unary& operator=(Unary&& instr) = delete;
+ Unary& operator=(const Unary& inst) = delete;
+ Unary& operator=(Unary&& inst) = delete;
/// @returns the kind of instruction
Kind GetKind() const { return kind_; }
@@ -54,7 +55,7 @@
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
- utils::StringStream& ToString(utils::StringStream& out) const override;
+ utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
Kind kind_;
diff --git a/src/tint/ir/unary_test.cc b/src/tint/ir/unary_test.cc
index cfc5579..ff247a2 100644
--- a/src/tint/ir/unary_test.cc
+++ b/src/tint/ir/unary_test.cc
@@ -26,135 +26,112 @@
TEST_F(IR_InstructionTest, CreateAddressOf) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
// TODO(dsinclair): This would be better as an identifier, but works for now.
- const auto* instr =
+ const auto* inst =
b.builder.AddressOf(b.builder.ir.types.Get<type::Pointer>(
b.builder.ir.types.Get<type::I32>(),
builtin::AddressSpace::kPrivate, builtin::Access::kReadWrite),
b.builder.Constant(4_i));
- EXPECT_EQ(instr->GetKind(), Unary::Kind::kAddressOf);
+ ASSERT_TRUE(inst->Is<Unary>());
+ EXPECT_EQ(inst->GetKind(), Unary::Kind::kAddressOf);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- ASSERT_NE(instr->Result()->Type(), nullptr);
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
+ ASSERT_NE(inst->Type(), nullptr);
- ASSERT_TRUE(instr->Val()->Is<Constant>());
- auto lhs = instr->Val()->As<Constant>()->value;
+ ASSERT_TRUE(inst->Val()->Is<Constant>());
+ auto lhs = inst->Val()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (ptr<private, i32, read_write>) = &4");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(ptr<private, i32, read_write>) = addr_of 4i");
}
TEST_F(IR_InstructionTest, CreateComplement) {
auto& b = CreateEmptyBuilder();
-
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr =
+ const auto* inst =
b.builder.Complement(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
- EXPECT_EQ(instr->GetKind(), Unary::Kind::kComplement);
+ ASSERT_TRUE(inst->Is<Unary>());
+ EXPECT_EQ(inst->GetKind(), Unary::Kind::kComplement);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->Val()->Is<Constant>());
- auto lhs = instr->Val()->As<Constant>()->value;
+ ASSERT_TRUE(inst->Val()->Is<Constant>());
+ auto lhs = inst->Val()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = ~4");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = bit_complement 4i");
}
TEST_F(IR_InstructionTest, CreateIndirection) {
auto& b = CreateEmptyBuilder();
- b.builder.next_runtime_id = Runtime::Id(42);
// TODO(dsinclair): This would be better as an identifier, but works for now.
- const auto* instr =
+ const auto* inst =
b.builder.Indirection(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
- EXPECT_EQ(instr->GetKind(), Unary::Kind::kIndirection);
+ ASSERT_TRUE(inst->Is<Unary>());
+ EXPECT_EQ(inst->GetKind(), Unary::Kind::kIndirection);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->Val()->Is<Constant>());
- auto lhs = instr->Val()->As<Constant>()->value;
+ ASSERT_TRUE(inst->Val()->Is<Constant>());
+ auto lhs = inst->Val()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = *4");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = indirection 4i");
}
TEST_F(IR_InstructionTest, CreateNegation) {
auto& b = CreateEmptyBuilder();
-
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr =
+ const auto* inst =
b.builder.Negation(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
- EXPECT_EQ(instr->GetKind(), Unary::Kind::kNegation);
+ ASSERT_TRUE(inst->Is<Unary>());
+ EXPECT_EQ(inst->GetKind(), Unary::Kind::kNegation);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->Val()->Is<Constant>());
- auto lhs = instr->Val()->As<Constant>()->value;
+ ASSERT_TRUE(inst->Val()->Is<Constant>());
+ auto lhs = inst->Val()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (i32) = -4");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(i32) = negation 4i");
}
TEST_F(IR_InstructionTest, CreateNot) {
auto& b = CreateEmptyBuilder();
-
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr =
+ const auto* inst =
b.builder.Not(b.builder.ir.types.Get<type::Bool>(), b.builder.Constant(true));
- EXPECT_EQ(instr->GetKind(), Unary::Kind::kNot);
+ ASSERT_TRUE(inst->Is<Unary>());
+ EXPECT_EQ(inst->GetKind(), Unary::Kind::kNot);
- ASSERT_TRUE(instr->Result()->Is<Runtime>());
- EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
-
- ASSERT_TRUE(instr->Val()->Is<Constant>());
- auto lhs = instr->Val()->As<Constant>()->value;
+ ASSERT_TRUE(inst->Val()->Is<Constant>());
+ auto lhs = inst->Val()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<bool>>());
EXPECT_TRUE(lhs->As<constant::Scalar<bool>>()->ValueAs<bool>());
utils::StringStream str;
- instr->ToString(str);
- EXPECT_EQ(str.str(), "%42 (bool) = !true");
+ inst->ToInstruction(str);
+ EXPECT_EQ(str.str(), "%1(bool) = log_not true");
}
TEST_F(IR_InstructionTest, Unary_Usage) {
auto& b = CreateEmptyBuilder();
-
- b.builder.next_runtime_id = Runtime::Id(42);
- const auto* instr =
+ const auto* inst =
b.builder.Negation(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
- EXPECT_EQ(instr->GetKind(), Unary::Kind::kNegation);
+ EXPECT_EQ(inst->GetKind(), Unary::Kind::kNegation);
- ASSERT_NE(instr->Result(), nullptr);
- ASSERT_EQ(instr->Result()->Usage().Length(), 1u);
- EXPECT_EQ(instr->Result()->Usage()[0], instr);
-
- ASSERT_NE(instr->Val(), nullptr);
- ASSERT_EQ(instr->Val()->Usage().Length(), 1u);
- EXPECT_EQ(instr->Val()->Usage()[0], instr);
+ ASSERT_NE(inst->Val(), nullptr);
+ ASSERT_EQ(inst->Val()->Usage().Length(), 1u);
+ EXPECT_EQ(inst->Val()->Usage()[0], inst);
}
} // namespace
diff --git a/src/tint/ir/user_call.cc b/src/tint/ir/user_call.cc
index 9a1f7eb..f23a2ca 100644
--- a/src/tint/ir/user_call.cc
+++ b/src/tint/ir/user_call.cc
@@ -19,17 +19,17 @@
namespace tint::ir {
-UserCall::UserCall(Value* result, Symbol name, utils::VectorRef<Value*> args)
- : Base(result, args), name_(name) {}
+UserCall::UserCall(uint32_t id, const type::Type* type, Symbol name, utils::VectorRef<Value*> args)
+ : Base(id, type, args), name_(name) {}
UserCall::~UserCall() = default;
-utils::StringStream& UserCall::ToString(utils::StringStream& out) const {
- Result()->ToString(out);
- out << " = call(";
- out << name_.Name() << ", ";
+utils::StringStream& UserCall::ToInstruction(utils::StringStream& out) const {
+ ToValue(out) << " = call " << name_.Name();
+ if (Args().Length() > 0) {
+ out << ", ";
+ }
EmitArgs(out);
- out << ")";
return out;
}
diff --git a/src/tint/ir/user_call.h b/src/tint/ir/user_call.h
index 0662455..1e2b070 100644
--- a/src/tint/ir/user_call.h
+++ b/src/tint/ir/user_call.h
@@ -26,16 +26,17 @@
class UserCall : public utils::Castable<UserCall, Call> {
public:
/// Constructor
- /// @param result the result value
+ /// @param id the instruction id
+ /// @param type the result type
/// @param name the function name
/// @param args the function arguments
- UserCall(Value* result, Symbol name, utils::VectorRef<Value*> args);
- UserCall(const UserCall& instr) = delete;
- UserCall(UserCall&& instr) = delete;
+ UserCall(uint32_t id, const type::Type* type, Symbol name, utils::VectorRef<Value*> args);
+ UserCall(const UserCall& inst) = delete;
+ UserCall(UserCall&& inst) = delete;
~UserCall() override;
- UserCall& operator=(const UserCall& instr) = delete;
- UserCall& operator=(UserCall&& instr) = delete;
+ UserCall& operator=(const UserCall& inst) = delete;
+ UserCall& operator=(UserCall&& inst) = delete;
/// @returns the function name
Symbol Name() const { return name_; }
@@ -43,7 +44,7 @@
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
- utils::StringStream& ToString(utils::StringStream& out) const override;
+ utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
Symbol name_{};
diff --git a/src/tint/ir/value.cc b/src/tint/ir/value.cc
index 750fe19..c735cd9 100644
--- a/src/tint/ir/value.cc
+++ b/src/tint/ir/value.cc
@@ -15,7 +15,6 @@
#include "src/tint/ir/value.h"
#include "src/tint/ir/constant.h"
-#include "src/tint/ir/runtime.h"
TINT_INSTANTIATE_TYPEINFO(tint::ir::Value);
diff --git a/src/tint/ir/value.h b/src/tint/ir/value.h
index e2a642b..7f3f4b7 100644
--- a/src/tint/ir/value.h
+++ b/src/tint/ir/value.h
@@ -40,8 +40,8 @@
Value& operator=(Value&&) = delete;
/// Adds an instruction which uses this value.
- /// @param instr the instruction
- void AddUsage(const Instruction* instr) { uses_.Add(instr); }
+ /// @param inst the instruction
+ void AddUsage(const Instruction* inst) { uses_.Add(inst); }
/// @returns the vector of instructions which use this value. An instruction will only be
/// returned once even if that instruction uses the given value multiple times.
@@ -53,7 +53,7 @@
/// Write the value to the given stream
/// @param out the stream to write to
/// @returns the stream
- virtual utils::StringStream& ToString(utils::StringStream& out) const = 0;
+ virtual utils::StringStream& ToValue(utils::StringStream& out) const = 0;
protected:
/// Constructor
diff --git a/src/tint/ir/var.cc b/src/tint/ir/var.cc
new file mode 100644
index 0000000..740a35e
--- /dev/null
+++ b/src/tint/ir/var.cc
@@ -0,0 +1,35 @@
+// 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/ir/var.h"
+#include "src/tint/debug.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ir::Var);
+
+namespace tint::ir {
+
+Var::Var(uint32_t id,
+ const type::Type* ty,
+ builtin::AddressSpace address_space,
+ builtin::Access access)
+ : Base(id, ty), address_space_(address_space), access_(access) {}
+
+Var::~Var() = default;
+
+utils::StringStream& Var::ToInstruction(utils::StringStream& out) const {
+ ToValue(out) << " = var " << address_space_ << " " << access_;
+ return out;
+}
+
+} // namespace tint::ir
diff --git a/src/tint/ir/var.h b/src/tint/ir/var.h
new file mode 100644
index 0000000..456e7d3
--- /dev/null
+++ b/src/tint/ir/var.h
@@ -0,0 +1,63 @@
+// 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_IR_VAR_H_
+#define SRC_TINT_IR_VAR_H_
+
+#include "src/tint/builtin/access.h"
+#include "src/tint/builtin/address_space.h"
+#include "src/tint/ir/instruction.h"
+#include "src/tint/utils/castable.h"
+#include "src/tint/utils/string_stream.h"
+
+namespace tint::ir {
+
+/// An instruction in the IR.
+class Var : public utils::Castable<Var, Instruction> {
+ public:
+ /// Constructor
+ /// @param id the instruction id
+ /// @param type the type
+ /// @param address_space the address space of the var
+ /// @param access the access mode of the var
+ Var(uint32_t id,
+ const type::Type* type,
+ builtin::AddressSpace address_space,
+ builtin::Access access);
+ Var(const Var& inst) = delete;
+ Var(Var&& inst) = delete;
+ ~Var() override;
+
+ Var& operator=(const Var& inst) = delete;
+ Var& operator=(Var&& inst) = delete;
+
+ /// @returns the address space
+ builtin::AddressSpace AddressSpace() const { return address_space_; }
+
+ /// @returns the access mode
+ builtin::Access Access() const { return access_; }
+
+ /// Write the instruction to the given stream
+ /// @param out the stream to write to
+ /// @returns the stream
+ utils::StringStream& ToInstruction(utils::StringStream& out) const override;
+
+ private:
+ builtin::AddressSpace address_space_;
+ builtin::Access access_;
+};
+
+} // namespace tint::ir
+
+#endif // SRC_TINT_IR_VAR_H_
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index b4f5eea..49b14fc 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -1470,7 +1470,7 @@
/// @param name the symbol string
/// @return a Symbol with the given name
- Symbol Sym(const std::string& name) { return Symbols().Register(name); }
+ Symbol Sym(std::string_view name) { return Symbols().Register(name); }
/// @param enumerator the enumerator
/// @return a Symbol with the given enum value
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index 098ab17..b9160ce 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -131,6 +131,43 @@
return {};
}
+static std::string name(AttributeKind kind) {
+ switch (kind) {
+ case AttributeKind::kAlign:
+ return "@align";
+ case AttributeKind::kBinding:
+ return "@binding";
+ case AttributeKind::kBuiltin:
+ return "@builtin";
+ case AttributeKind::kDiagnostic:
+ return "@diagnostic";
+ case AttributeKind::kGroup:
+ return "@group";
+ case AttributeKind::kId:
+ return "@id";
+ case AttributeKind::kInterpolate:
+ return "@interpolate";
+ case AttributeKind::kInvariant:
+ return "@invariant";
+ case AttributeKind::kLocation:
+ return "@location";
+ case AttributeKind::kOffset:
+ return "@offset";
+ case AttributeKind::kMustUse:
+ return "@must_use";
+ case AttributeKind::kSize:
+ return "@size";
+ case AttributeKind::kStage:
+ return "@stage";
+ case AttributeKind::kStride:
+ return "@stride";
+ case AttributeKind::kWorkgroup:
+ return "@workgroup_size";
+ case AttributeKind::kBindingAndGroup:
+ return "@binding";
+ }
+ return "<unknown>";
+}
namespace FunctionInputAndOutputTests {
using FunctionParameterAttributeTest = TestWithParams;
TEST_P(FunctionParameterAttributeTest, IsValid) {
@@ -144,11 +181,16 @@
if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
+ } else if (params.kind == AttributeKind::kLocation || params.kind == AttributeKind::kBuiltin ||
+ params.kind == AttributeKind::kInvariant ||
+ params.kind == AttributeKind::kInterpolate) {
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "error: " + name(params.kind) +
+ " is not valid for non-entry point function parameters");
} else {
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "error: attribute is not valid for non-entry point function "
- "parameters");
+ "error: " + name(params.kind) + " is not valid for function parameters");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -184,9 +226,9 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- "error: attribute is not valid for non-entry point function "
- "return types");
+ EXPECT_EQ(r()->error(), "error: " + name(params.kind) +
+ " is not valid for non-entry point function "
+ "return types");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -234,10 +276,11 @@
} else if (params.kind == AttributeKind::kInterpolate ||
params.kind == AttributeKind::kLocation ||
params.kind == AttributeKind::kInvariant) {
- EXPECT_EQ(r()->error(),
- "12:34 error: attribute is not valid for compute shader inputs");
+ EXPECT_EQ(r()->error(), "12:34 error: " + name(params.kind) +
+ " is not valid for compute shader inputs");
} else {
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for function parameters");
+ EXPECT_EQ(r()->error(), "12:34 error: " + name(params.kind) +
+ " is not valid for function parameters");
}
}
}
@@ -277,7 +320,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for function parameters");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for function parameters");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -331,7 +375,8 @@
"12:34 error: invariant attribute must only be applied to a "
"position builtin");
} else {
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for function parameters");
+ EXPECT_EQ(r()->error(), "12:34 error: " + name(params.kind) +
+ " is not valid for function parameters");
}
}
}
@@ -378,12 +423,12 @@
} else if (params.kind == AttributeKind::kInterpolate ||
params.kind == AttributeKind::kLocation ||
params.kind == AttributeKind::kInvariant) {
- EXPECT_EQ(r()->error(),
- "12:34 error: attribute is not valid for compute shader output");
+ EXPECT_EQ(r()->error(), "12:34 error: " + name(params.kind) +
+ " is not valid for compute shader output");
} else {
- EXPECT_EQ(r()->error(),
- "12:34 error: attribute is not valid for entry point return "
- "types");
+ EXPECT_EQ(r()->error(), "12:34 error: " + name(params.kind) +
+ " is not valid for entry point return "
+ "types");
}
}
}
@@ -434,8 +479,8 @@
R"(34:56 error: duplicate location attribute
12:34 note: first attribute declared here)");
} else {
- EXPECT_EQ(r()->error(),
- R"(12:34 error: attribute is not valid for entry point return types)");
+ EXPECT_EQ(r()->error(), "12:34 error: " + name(params.kind) +
+ " is not valid for entry point return types");
}
}
}
@@ -484,8 +529,8 @@
R"(34:56 error: multiple entry point IO attributes
12:34 note: previously consumed @location)");
} else {
- EXPECT_EQ(r()->error(),
- R"(12:34 error: attribute is not valid for entry point return types)");
+ EXPECT_EQ(r()->error(), "12:34 error: " + name(params.kind) +
+ " is not valid for entry point return types");
}
}
}
@@ -591,7 +636,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for struct declarations");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for struct declarations");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -628,7 +674,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for structure members");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for struct members");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -871,7 +918,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for array types");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for array types");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -898,7 +946,6 @@
auto& params = GetParam();
auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
- auto* attr = attrs[0];
if (IsBindingAttribute(params.kind)) {
GlobalVar("a", ty.sampler(type::SamplerKind::kSampler), attrs);
} else {
@@ -910,8 +957,8 @@
} else {
EXPECT_FALSE(r()->Resolve());
if (!IsBindingAttribute(params.kind)) {
- EXPECT_EQ(r()->error(), "12:34 error: attribute '" + attr->Name() +
- "' is not valid for module-scope 'var'");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for module-scope 'var'");
}
}
}
@@ -944,13 +991,22 @@
12:34 note: first attribute declared here)");
}
-TEST_F(VariableAttributeTest, LocalVariable) {
+TEST_F(VariableAttributeTest, LocalVar) {
auto* v = Var("a", ty.f32(), utils::Vector{Binding(Source{{12, 34}}, 2_a)});
WrapInFunction(v);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attributes are not valid on local variables");
+ EXPECT_EQ(r()->error(), "12:34 error: @binding is not valid for function-scope 'var'");
+}
+
+TEST_F(VariableAttributeTest, LocalLet) {
+ auto* v = Let("a", utils::Vector{Binding(Source{{12, 34}}, 2_a)}, Expr(1_a));
+
+ WrapInFunction(v);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: @binding is not valid for 'let' declaration");
}
using ConstantAttributeTest = TestWithParams;
@@ -965,7 +1021,7 @@
} else {
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: attribute is not valid for module-scope 'const' declaration");
+ "12:34 error: " + name(params.kind) + " is not valid for 'const' declaration");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -987,17 +1043,14 @@
TestParams{AttributeKind::kWorkgroup, false},
TestParams{AttributeKind::kBindingAndGroup, false}));
-TEST_F(ConstantAttributeTest, DuplicateAttribute) {
+TEST_F(ConstantAttributeTest, InvalidAttribute) {
GlobalConst("a", ty.f32(), Expr(1.23_f),
utils::Vector{
Id(Source{{12, 34}}, 0_a),
- Id(Source{{56, 78}}, 1_a),
});
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- R"(56:78 error: duplicate id attribute
-12:34 note: first attribute declared here)");
+ EXPECT_EQ(r()->error(), "12:34 error: @id is not valid for 'const' declaration");
}
using OverrideAttributeTest = TestWithParams;
@@ -1010,7 +1063,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for 'override' declaration");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for 'override' declaration");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -1056,7 +1110,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for switch statements");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for switch statements");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -1089,7 +1144,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for switch body");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for switch body");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -1122,7 +1178,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for if statements");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for if statements");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -1155,7 +1212,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for for statements");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for for statements");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -1188,7 +1246,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for loop statements");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for loop statements");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -1221,7 +1280,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for while statements");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: " + name(params.kind) + " is not valid for while statements");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
@@ -1251,7 +1311,8 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "error: attribute is not valid for block statements");
+ EXPECT_EQ(r()->error(),
+ "error: " + name(GetParam().kind) + " is not valid for block statements");
}
}
};
diff --git a/src/tint/resolver/builtin_structs.cc b/src/tint/resolver/builtin_structs.cc
new file mode 100644
index 0000000..4e45c16
--- /dev/null
+++ b/src/tint/resolver/builtin_structs.cc
@@ -0,0 +1,239 @@
+// 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/resolver/builtin_structs.h"
+
+#include <algorithm>
+#include <string>
+#include <utility>
+
+#include "src/tint/program_builder.h"
+#include "src/tint/switch.h"
+#include "src/tint/type/abstract_float.h"
+#include "src/tint/type/abstract_int.h"
+#include "src/tint/type/vector.h"
+
+namespace tint::resolver {
+
+namespace {
+
+struct NameAndType {
+ std::string_view name;
+ const type::Type* type;
+};
+
+type::Struct* BuildStruct(ProgramBuilder& b,
+ builtin::Builtin name,
+ std::initializer_list<NameAndType> member_names_and_types) {
+ uint32_t offset = 0;
+ uint32_t max_align = 0;
+ utils::Vector<const type::StructMember*, 4> members;
+ for (auto& m : member_names_and_types) {
+ uint32_t align = std::max<uint32_t>(m.type->Align(), 1);
+ uint32_t size = m.type->Size();
+ offset = utils::RoundUp(align, offset);
+ max_align = std::max(max_align, align);
+ members.Push(b.create<type::StructMember>(
+ /* name */ b.Sym(m.name),
+ /* type */ m.type,
+ /* index */ static_cast<uint32_t>(members.Length()),
+ /* offset */ offset,
+ /* align */ align,
+ /* size */ size,
+ /* attributes */ type::StructMemberAttributes{}));
+ offset += size;
+ }
+ uint32_t size_without_padding = offset;
+ uint32_t size_with_padding = utils::RoundUp(max_align, offset);
+ return b.create<type::Struct>(
+ /* name */ b.Sym(name),
+ /* members */ std::move(members),
+ /* align */ max_align,
+ /* size */ size_with_padding,
+ /* size_no_padding */ size_without_padding);
+}
+} // namespace
+
+constexpr std::array kModfVecF32Names{
+ builtin::Builtin::kModfResultVec2F32,
+ builtin::Builtin::kModfResultVec3F32,
+ builtin::Builtin::kModfResultVec4F32,
+};
+constexpr std::array kModfVecF16Names{
+ builtin::Builtin::kModfResultVec2F16,
+ builtin::Builtin::kModfResultVec3F16,
+ builtin::Builtin::kModfResultVec4F16,
+};
+constexpr std::array kModfVecAbstractNames{
+ builtin::Builtin::kModfResultVec2Abstract,
+ builtin::Builtin::kModfResultVec3Abstract,
+ builtin::Builtin::kModfResultVec4Abstract,
+};
+
+type::Struct* CreateModfResult(ProgramBuilder& b, const type::Type* ty) {
+ return Switch(
+ ty,
+ [&](const type::F32*) {
+ return BuildStruct(b, builtin::Builtin::kModfResultF32, {{"fract", ty}, {"whole", ty}});
+ }, //
+ [&](const type::F16*) {
+ return BuildStruct(b, builtin::Builtin::kModfResultF16, {{"fract", ty}, {"whole", ty}});
+ },
+ [&](const type::AbstractFloat*) {
+ auto* abstract = BuildStruct(b, builtin::Builtin::kModfResultAbstract,
+ {{"fract", ty}, {"whole", ty}});
+ auto* f32 = b.create<type::F32>();
+ auto* f16 = b.create<type::F16>();
+ abstract->SetConcreteTypes(utils::Vector{
+ BuildStruct(b, builtin::Builtin::kModfResultF32, {{"fract", f32}, {"whole", f32}}),
+ BuildStruct(b, builtin::Builtin::kModfResultF16, {{"fract", f16}, {"whole", f16}}),
+ });
+ return abstract;
+ },
+ [&](const type::Vector* vec) {
+ auto width = vec->Width();
+ return Switch(
+ vec->type(), //
+ [&](const type::F32*) {
+ return BuildStruct(b, kModfVecF32Names[width - 2],
+ {{"fract", vec}, {"whole", vec}});
+ },
+ [&](const type::F16*) {
+ return BuildStruct(b, kModfVecF16Names[width - 2],
+ {{"fract", vec}, {"whole", vec}});
+ },
+ [&](const type::AbstractFloat*) {
+ auto* vec_f32 = b.create<type::Vector>(b.create<type::F32>(), width);
+ auto* vec_f16 = b.create<type::Vector>(b.create<type::F16>(), width);
+ auto* abstract = BuildStruct(b, kModfVecAbstractNames[width - 2],
+ {{"fract", vec}, {"whole", vec}});
+ abstract->SetConcreteTypes(utils::Vector{
+ BuildStruct(b, kModfVecF32Names[width - 2],
+ {{"fract", vec_f32}, {"whole", vec_f32}}),
+ BuildStruct(b, kModfVecF16Names[width - 2],
+ {{"fract", vec_f16}, {"whole", vec_f16}}),
+ });
+ return abstract;
+ },
+ [&](Default) {
+ TINT_ICE(Resolver, b.Diagnostics())
+ << "unhandled modf type: " << b.FriendlyName(ty);
+ return nullptr;
+ });
+ },
+ [&](Default) {
+ TINT_ICE(Resolver, b.Diagnostics()) << "unhandled modf type: " << b.FriendlyName(ty);
+ return nullptr;
+ });
+}
+
+constexpr std::array kFrexpVecF32Names{
+ builtin::Builtin::kFrexpResultVec2F32,
+ builtin::Builtin::kFrexpResultVec3F32,
+ builtin::Builtin::kFrexpResultVec4F32,
+};
+constexpr std::array kFrexpVecF16Names{
+ builtin::Builtin::kFrexpResultVec2F16,
+ builtin::Builtin::kFrexpResultVec3F16,
+ builtin::Builtin::kFrexpResultVec4F16,
+};
+constexpr std::array kFrexpVecAbstractNames{
+ builtin::Builtin::kFrexpResultVec2Abstract,
+ builtin::Builtin::kFrexpResultVec3Abstract,
+ builtin::Builtin::kFrexpResultVec4Abstract,
+};
+type::Struct* CreateFrexpResult(ProgramBuilder& b, const type::Type* ty) {
+ return Switch(
+ ty, //
+ [&](const type::F32*) {
+ auto* i32 = b.create<type::I32>();
+ return BuildStruct(b, builtin::Builtin::kFrexpResultF32, {{"fract", ty}, {"exp", i32}});
+ },
+ [&](const type::F16*) {
+ auto* i32 = b.create<type::I32>();
+ return BuildStruct(b, builtin::Builtin::kFrexpResultF16, {{"fract", ty}, {"exp", i32}});
+ },
+ [&](const type::AbstractFloat*) {
+ auto* f32 = b.create<type::F32>();
+ auto* f16 = b.create<type::F16>();
+ auto* i32 = b.create<type::I32>();
+ auto* ai = b.create<type::AbstractInt>();
+ auto* abstract = BuildStruct(b, builtin::Builtin::kFrexpResultAbstract,
+ {{"fract", ty}, {"exp", ai}});
+ abstract->SetConcreteTypes(utils::Vector{
+ BuildStruct(b, builtin::Builtin::kFrexpResultF32, {{"fract", f32}, {"exp", i32}}),
+ BuildStruct(b, builtin::Builtin::kFrexpResultF16, {{"fract", f16}, {"exp", i32}}),
+ });
+ return abstract;
+ },
+ [&](const type::Vector* vec) {
+ auto width = vec->Width();
+ return Switch(
+ vec->type(), //
+ [&](const type::F32*) {
+ auto* vec_i32 = b.create<type::Vector>(b.create<type::I32>(), width);
+ return BuildStruct(b, kFrexpVecF32Names[width - 2],
+ {{"fract", ty}, {"exp", vec_i32}});
+ },
+ [&](const type::F16*) {
+ auto* vec_i32 = b.create<type::Vector>(b.create<type::I32>(), width);
+ return BuildStruct(b, kFrexpVecF16Names[width - 2],
+ {{"fract", ty}, {"exp", vec_i32}});
+ },
+ [&](const type::AbstractFloat*) {
+ auto* vec_f32 = b.create<type::Vector>(b.create<type::F32>(), width);
+ auto* vec_f16 = b.create<type::Vector>(b.create<type::F16>(), width);
+ auto* vec_i32 = b.create<type::Vector>(b.create<type::I32>(), width);
+ auto* vec_ai = b.create<type::Vector>(b.create<type::AbstractInt>(), width);
+ auto* abstract = BuildStruct(b, kFrexpVecAbstractNames[width - 2],
+ {{"fract", ty}, {"exp", vec_ai}});
+ abstract->SetConcreteTypes(utils::Vector{
+ BuildStruct(b, kFrexpVecF32Names[width - 2],
+ {{"fract", vec_f32}, {"exp", vec_i32}}),
+ BuildStruct(b, kFrexpVecF16Names[width - 2],
+ {{"fract", vec_f16}, {"exp", vec_i32}}),
+ });
+ return abstract;
+ },
+ [&](Default) {
+ TINT_ICE(Resolver, b.Diagnostics())
+ << "unhandled frexp type: " << b.FriendlyName(ty);
+ return nullptr;
+ });
+ },
+ [&](Default) {
+ TINT_ICE(Resolver, b.Diagnostics()) << "unhandled frexp type: " << b.FriendlyName(ty);
+ return nullptr;
+ });
+}
+
+type::Struct* CreateAtomicCompareExchangeResult(ProgramBuilder& b, const type::Type* ty) {
+ return Switch(
+ ty, //
+ [&](const type::I32*) {
+ return BuildStruct(b, builtin::Builtin::kAtomicCompareExchangeResultI32,
+ {{"old_value", ty}, {"exchanged", b.create<type::Bool>()}});
+ },
+ [&](const type::U32*) {
+ return BuildStruct(b, builtin::Builtin::kAtomicCompareExchangeResultU32,
+ {{"old_value", ty}, {"exchanged", b.create<type::Bool>()}});
+ },
+ [&](Default) {
+ TINT_ICE(Resolver, b.Diagnostics())
+ << "unhandled atomic_compare_exchange type: " << b.FriendlyName(ty);
+ return nullptr;
+ });
+}
+
+} // namespace tint::resolver
diff --git a/src/tint/resolver/builtin_structs.h b/src/tint/resolver/builtin_structs.h
new file mode 100644
index 0000000..b8f56c7
--- /dev/null
+++ b/src/tint/resolver/builtin_structs.h
@@ -0,0 +1,49 @@
+// 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_RESOLVER_BUILTIN_STRUCTS_H_
+#define SRC_TINT_RESOLVER_BUILTIN_STRUCTS_H_
+
+// Forward declarations
+namespace tint {
+class ProgramBuilder;
+} // namespace tint
+namespace tint::type {
+class Struct;
+class Type;
+} // namespace tint::type
+
+namespace tint::resolver {
+
+/**
+ * @param ty the type of the `fract` and `whole` struct members.
+ * @return the builtin struct type for a modf() builtin call.
+ */
+type::Struct* CreateModfResult(ProgramBuilder& b, const type::Type* ty);
+
+/**
+ * @param fract the type of the `fract` struct member.
+ * @return the builtin struct type for a frexp() builtin call.
+ */
+type::Struct* CreateFrexpResult(ProgramBuilder& b, const type::Type* fract);
+
+/**
+ * @param ty the type of the `old_value` struct member.
+ * @return the builtin struct type for a atomic_compare_exchange() builtin call.
+ */
+type::Struct* CreateAtomicCompareExchangeResult(ProgramBuilder& b, const type::Type* ty);
+
+} // namespace tint::resolver
+
+#endif // SRC_TINT_RESOLVER_BUILTIN_STRUCTS_H_
diff --git a/src/tint/resolver/builtin_structs_test.cc b/src/tint/resolver/builtin_structs_test.cc
new file mode 100644
index 0000000..9adf209
--- /dev/null
+++ b/src/tint/resolver/builtin_structs_test.cc
@@ -0,0 +1,73 @@
+// 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/resolver/resolver.h"
+#include "src/tint/resolver/resolver_test_helper.h"
+
+#include "gmock/gmock.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::resolver {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+// access
+////////////////////////////////////////////////////////////////////////////////
+using ResolverBuiltinStructs = ResolverTestWithParam<builtin::Builtin>;
+
+TEST_P(ResolverBuiltinStructs, Resolve) {
+ Enable(builtin::Extension::kF16);
+
+ // var<private> p : NAME;
+ auto* var = GlobalVar("p", ty(GetParam()), builtin::AddressSpace::kPrivate);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+ auto* str = As<type::Struct>(TypeOf(var)->UnwrapRef());
+ ASSERT_NE(str, nullptr);
+ EXPECT_EQ(str->Name().Name(), utils::ToString(GetParam()));
+ EXPECT_FALSE(Is<sem::Struct>(str));
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+ ResolverBuiltinStructs,
+ testing::Values(builtin::Builtin::kAtomicCompareExchangeResultI32,
+ builtin::Builtin::kAtomicCompareExchangeResultU32,
+ builtin::Builtin::kFrexpResultAbstract,
+ builtin::Builtin::kFrexpResultF16,
+ builtin::Builtin::kFrexpResultF32,
+ builtin::Builtin::kFrexpResultVec2Abstract,
+ builtin::Builtin::kFrexpResultVec2F16,
+ builtin::Builtin::kFrexpResultVec2F32,
+ builtin::Builtin::kFrexpResultVec3Abstract,
+ builtin::Builtin::kFrexpResultVec3F16,
+ builtin::Builtin::kFrexpResultVec3F32,
+ builtin::Builtin::kFrexpResultVec4Abstract,
+ builtin::Builtin::kFrexpResultVec4F16,
+ builtin::Builtin::kFrexpResultVec4F32,
+ builtin::Builtin::kModfResultAbstract,
+ builtin::Builtin::kModfResultF16,
+ builtin::Builtin::kModfResultF32,
+ builtin::Builtin::kModfResultVec2Abstract,
+ builtin::Builtin::kModfResultVec2F16,
+ builtin::Builtin::kModfResultVec2F32,
+ builtin::Builtin::kModfResultVec3Abstract,
+ builtin::Builtin::kModfResultVec3F16,
+ builtin::Builtin::kModfResultVec3F32,
+ builtin::Builtin::kModfResultVec4Abstract,
+ builtin::Builtin::kModfResultVec4F16,
+ builtin::Builtin::kModfResultVec4F32));
+
+} // namespace
+} // namespace tint::resolver
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index 8cfbc67..60c01f7 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -925,7 +925,7 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- auto* ty = TypeOf(call)->As<sem::Struct>();
+ auto* ty = TypeOf(call)->As<type::Struct>();
ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().Length(), 2u);
@@ -956,7 +956,7 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- auto* ty = TypeOf(call)->As<sem::Struct>();
+ auto* ty = TypeOf(call)->As<type::Struct>();
ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().Length(), 2u);
@@ -985,7 +985,7 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- auto* ty = TypeOf(call)->As<sem::Struct>();
+ auto* ty = TypeOf(call)->As<type::Struct>();
ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().Length(), 2u);
@@ -1020,7 +1020,7 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- auto* ty = TypeOf(call)->As<sem::Struct>();
+ auto* ty = TypeOf(call)->As<type::Struct>();
ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().Length(), 2u);
@@ -1174,7 +1174,7 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- auto* ty = TypeOf(call)->As<sem::Struct>();
+ auto* ty = TypeOf(call)->As<type::Struct>();
ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().Length(), 2u);
@@ -1205,7 +1205,7 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- auto* ty = TypeOf(call)->As<sem::Struct>();
+ auto* ty = TypeOf(call)->As<type::Struct>();
ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().Length(), 2u);
@@ -1234,7 +1234,7 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- auto* ty = TypeOf(call)->As<sem::Struct>();
+ auto* ty = TypeOf(call)->As<type::Struct>();
ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().Length(), 2u);
@@ -1269,7 +1269,7 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
- auto* ty = TypeOf(call)->As<sem::Struct>();
+ auto* ty = TypeOf(call)->As<type::Struct>();
ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().Length(), 2u);
diff --git a/src/tint/resolver/builtins_validation_test.cc b/src/tint/resolver/builtins_validation_test.cc
index a985a1d..d5f8c4f 100644
--- a/src/tint/resolver/builtins_validation_test.cc
+++ b/src/tint/resolver/builtins_validation_test.cc
@@ -948,7 +948,7 @@
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+ auto* res_ty = TypeOf(builtin)->As<type::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto members = res_ty->Members();
ASSERT_EQ(members.Length(), 2u);
@@ -961,7 +961,7 @@
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+ auto* res_ty = TypeOf(builtin)->As<type::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto members = res_ty->Members();
ASSERT_EQ(members.Length(), 2u);
@@ -978,7 +978,7 @@
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+ auto* res_ty = TypeOf(builtin)->As<type::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto members = res_ty->Members();
ASSERT_EQ(members.Length(), 2u);
@@ -995,7 +995,7 @@
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+ auto* res_ty = TypeOf(builtin)->As<type::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto members = res_ty->Members();
ASSERT_EQ(members.Length(), 2u);
@@ -1012,7 +1012,7 @@
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+ auto* res_ty = TypeOf(builtin)->As<type::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto members = res_ty->Members();
ASSERT_EQ(members.Length(), 2u);
@@ -1025,7 +1025,7 @@
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+ auto* res_ty = TypeOf(builtin)->As<type::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto members = res_ty->Members();
ASSERT_EQ(members.Length(), 2u);
@@ -1042,7 +1042,7 @@
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+ auto* res_ty = TypeOf(builtin)->As<type::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto members = res_ty->Members();
ASSERT_EQ(members.Length(), 2u);
@@ -1059,7 +1059,7 @@
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
- auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+ auto* res_ty = TypeOf(builtin)->As<type::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto members = res_ty->Members();
ASSERT_EQ(members.Length(), 2u);
diff --git a/src/tint/resolver/const_eval_builtin_test.cc b/src/tint/resolver/const_eval_builtin_test.cc
index 2cef1d1..7aecfac 100644
--- a/src/tint/resolver/const_eval_builtin_test.cc
+++ b/src/tint/resolver/const_eval_builtin_test.cc
@@ -166,7 +166,7 @@
ASSERT_NE(value, nullptr);
EXPECT_TYPE(value->Type(), sem->Type());
- if (value->Type()->Is<sem::Struct>()) {
+ if (value->Type()->Is<type::Struct>()) {
// The result type of the constant-evaluated expression is a structure.
// Compare each of the fields individually.
for (size_t i = 0; i < expected_case.values.Length(); i++) {
diff --git a/src/tint/resolver/const_eval_construction_test.cc b/src/tint/resolver/const_eval_construction_test.cc
index 361edbf..d8efe8e 100644
--- a/src/tint/resolver/const_eval_construction_test.cc
+++ b/src/tint/resolver/const_eval_construction_test.cc
@@ -1445,7 +1445,7 @@
ASSERT_NE(sem, nullptr);
auto* arr = sem->Type()->As<type::Array>();
ASSERT_NE(arr, nullptr);
- EXPECT_TRUE(arr->ElemType()->Is<sem::Struct>());
+ EXPECT_TRUE(arr->ElemType()->Is<type::Struct>());
EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
EXPECT_TRUE(sem->ConstantValue()->AnyZero());
EXPECT_TRUE(sem->ConstantValue()->AllZero());
@@ -1662,7 +1662,7 @@
ASSERT_NE(sem, nullptr);
auto* arr = sem->Type()->As<type::Array>();
ASSERT_NE(arr, nullptr);
- EXPECT_TRUE(arr->ElemType()->Is<sem::Struct>());
+ EXPECT_TRUE(arr->ElemType()->Is<type::Struct>());
EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
EXPECT_FALSE(sem->ConstantValue()->AnyZero());
EXPECT_FALSE(sem->ConstantValue()->AllZero());
@@ -1787,7 +1787,7 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
- auto* str = sem->Type()->As<sem::Struct>();
+ auto* str = sem->Type()->As<type::Struct>();
ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().Length(), 3u);
ASSERT_NE(sem->ConstantValue(), nullptr);
@@ -1828,7 +1828,7 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
- auto* str = sem->Type()->As<sem::Struct>();
+ auto* str = sem->Type()->As<type::Struct>();
ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().Length(), 5u);
ASSERT_NE(sem->ConstantValue(), nullptr);
@@ -1875,7 +1875,7 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
- auto* str = sem->Type()->As<sem::Struct>();
+ auto* str = sem->Type()->As<type::Struct>();
ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().Length(), 3u);
ASSERT_NE(sem->ConstantValue(), nullptr);
@@ -1928,7 +1928,7 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
- auto* str = sem->Type()->As<sem::Struct>();
+ auto* str = sem->Type()->As<type::Struct>();
ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().Length(), 5u);
ASSERT_NE(sem->ConstantValue(), nullptr);
@@ -1999,7 +1999,7 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
- auto* str = sem->Type()->As<sem::Struct>();
+ auto* str = sem->Type()->As<type::Struct>();
ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().Length(), 2u);
ASSERT_NE(sem->ConstantValue(), nullptr);
@@ -2009,14 +2009,14 @@
EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
- EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<sem::Struct>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<type::Struct>());
EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->ValueAs<i32>(), 0_i);
EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->ValueAs<u32>(), 0_u);
EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->ValueAs<f32>(), 0_f);
EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
- EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<sem::Struct>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<type::Struct>());
EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->ValueAs<i32>(), 0_i);
EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->ValueAs<u32>(), 0_u);
EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->ValueAs<f32>(), 0_f);
@@ -2039,7 +2039,7 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
- auto* str = sem->Type()->As<sem::Struct>();
+ auto* str = sem->Type()->As<type::Struct>();
ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().Length(), 5u);
ASSERT_NE(sem->ConstantValue(), nullptr);
@@ -2091,7 +2091,7 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
- auto* str = sem->Type()->As<sem::Struct>();
+ auto* str = sem->Type()->As<type::Struct>();
ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().Length(), 5u);
ASSERT_NE(sem->ConstantValue(), nullptr);
@@ -2163,7 +2163,7 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
- auto* str = sem->Type()->As<sem::Struct>();
+ auto* str = sem->Type()->As<type::Struct>();
ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().Length(), 2u);
ASSERT_NE(sem->ConstantValue(), nullptr);
@@ -2173,14 +2173,14 @@
EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
- EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<sem::Struct>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Type()->Is<type::Struct>());
EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->ValueAs<i32>(), 1_i);
EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->ValueAs<u32>(), 2_u);
EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->ValueAs<f32>(), 3_f);
EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
- EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<sem::Struct>());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Type()->Is<type::Struct>());
EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->ValueAs<i32>(), 4_i);
EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->ValueAs<u32>(), 0_u);
EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->ValueAs<f32>(), 6_f);
@@ -2199,7 +2199,7 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
- auto* str = sem->Type()->As<sem::Struct>();
+ auto* str = sem->Type()->As<type::Struct>();
ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().Length(), 2u);
ASSERT_NE(sem->ConstantValue(), nullptr);
diff --git a/src/tint/resolver/const_eval_member_access_test.cc b/src/tint/resolver/const_eval_member_access_test.cc
index 9a74e6c..ee92714 100644
--- a/src/tint/resolver/const_eval_member_access_test.cc
+++ b/src/tint/resolver/const_eval_member_access_test.cc
@@ -41,7 +41,7 @@
auto* outer = Sem().Get(outer_expr);
ASSERT_NE(outer, nullptr);
- auto* str = outer->Type()->As<sem::Struct>();
+ auto* str = outer->Type()->As<type::Struct>();
ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().Length(), 2u);
ASSERT_NE(outer->ConstantValue(), nullptr);
@@ -53,7 +53,7 @@
ASSERT_NE(o1->ConstantValue(), nullptr);
EXPECT_FALSE(o1->ConstantValue()->AnyZero());
EXPECT_FALSE(o1->ConstantValue()->AllZero());
- EXPECT_TRUE(o1->ConstantValue()->Type()->Is<sem::Struct>());
+ EXPECT_TRUE(o1->ConstantValue()->Type()->Is<type::Struct>());
EXPECT_EQ(o1->ConstantValue()->Index(0)->ValueAs<i32>(), 1_i);
EXPECT_EQ(o1->ConstantValue()->Index(1)->ValueAs<u32>(), 2_u);
EXPECT_EQ(o1->ConstantValue()->Index(2)->ValueAs<f32>(), 3_f);
diff --git a/src/tint/resolver/entry_point_validation_test.cc b/src/tint/resolver/entry_point_validation_test.cc
index dac6cd2..eb2d779 100644
--- a/src/tint/resolver/entry_point_validation_test.cc
+++ b/src/tint/resolver/entry_point_validation_test.cc
@@ -1084,7 +1084,7 @@
});
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: attribute is not valid for compute shader output)");
+ EXPECT_EQ(r()->error(), R"(12:34 error: @location is not valid for compute shader output)");
}
TEST_F(LocationAttributeTests, ComputeShaderLocation_Output) {
@@ -1099,7 +1099,7 @@
});
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), R"(12:34 error: attribute is not valid for compute shader inputs)");
+ EXPECT_EQ(r()->error(), R"(12:34 error: @location is not valid for compute shader inputs)");
}
TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Output) {
@@ -1119,7 +1119,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: attribute is not valid for compute shader output\n"
+ "12:34 error: @location is not valid for compute shader output\n"
"56:78 note: while analyzing entry point 'main'");
}
@@ -1138,7 +1138,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- "12:34 error: attribute is not valid for compute shader inputs\n"
+ "12:34 error: @location is not valid for compute shader inputs\n"
"56:78 note: while analyzing entry point 'main'");
}
diff --git a/src/tint/resolver/inferred_type_test.cc b/src/tint/resolver/inferred_type_test.cc
index ab2478b..4545419 100644
--- a/src/tint/resolver/inferred_type_test.cc
+++ b/src/tint/resolver/inferred_type_test.cc
@@ -151,9 +151,9 @@
auto* str = Structure("S", utils::Vector{member});
auto* expected_type = create<sem::Struct>(
- str, str->source, str->name->symbol,
- utils::Vector{create<sem::StructMember>(member, member->source, member->name->symbol,
- create<type::I32>(), 0u, 0u, 0u, 4u, std::nullopt)},
+ str, str->name->symbol,
+ utils::Vector{create<sem::StructMember>(member, member->name->symbol, create<type::I32>(),
+ 0u, 0u, 0u, 4u, type::StructMemberAttributes{})},
0u, 4u, 4u);
auto* ctor_expr = Call(ty.Of(str));
diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc
index fc226eb..4295bb3 100644
--- a/src/tint/resolver/intrinsic_table.cc
+++ b/src/tint/resolver/intrinsic_table.cc
@@ -20,6 +20,7 @@
#include "src/tint/ast/binary_expression.h"
#include "src/tint/program_builder.h"
+#include "src/tint/resolver/builtin_structs.h"
#include "src/tint/sem/evaluation_stage.h"
#include "src/tint/sem/pipeline_stage_set.h"
#include "src/tint/sem/value_constructor.h"
@@ -819,170 +820,26 @@
return false;
}
-struct NameAndType {
- std::string name;
- const type::Type* type;
-};
-sem::Struct* build_struct(ProgramBuilder& b,
- std::string name,
- std::initializer_list<NameAndType> member_names_and_types) {
- uint32_t offset = 0;
- uint32_t max_align = 0;
- utils::Vector<const sem::StructMember*, 4> members;
- for (auto& m : member_names_and_types) {
- uint32_t align = std::max<uint32_t>(m.type->Align(), 1);
- uint32_t size = m.type->Size();
- offset = utils::RoundUp(align, offset);
- max_align = std::max(max_align, align);
- members.Push(b.create<sem::StructMember>(
- /* declaration */ nullptr,
- /* source */ Source{},
- /* name */ b.Sym(m.name),
- /* type */ m.type,
- /* index */ static_cast<uint32_t>(members.Length()),
- /* offset */ offset,
- /* align */ align,
- /* size */ size,
- /* location */ std::nullopt));
- offset += size;
- }
- uint32_t size_without_padding = offset;
- uint32_t size_with_padding = utils::RoundUp(max_align, offset);
- return b.create<sem::Struct>(
- /* declaration */ nullptr,
- /* source */ Source{},
- /* name */ b.Sym(name),
- /* members */ std::move(members),
- /* align */ max_align,
- /* size */ size_with_padding,
- /* size_no_padding */ size_without_padding);
+const type::Struct* build_modf_result(MatchState& state, const type::Type* el) {
+ return CreateModfResult(state.builder, el);
}
-const sem::Struct* build_modf_result(MatchState& state, const type::Type* el) {
- auto build_f32 = [&] {
- auto* ty = state.builder.create<type::F32>();
- return build_struct(state.builder, "__modf_result_f32", {{"fract", ty}, {"whole", ty}});
- };
- auto build_f16 = [&] {
- auto* ty = state.builder.create<type::F16>();
- return build_struct(state.builder, "__modf_result_f16", {{"fract", ty}, {"whole", ty}});
- };
-
- return Switch(
- el, //
- [&](const type::F32*) { return build_f32(); }, //
- [&](const type::F16*) { return build_f16(); }, //
- [&](const type::AbstractFloat*) {
- auto* abstract = build_struct(state.builder, "__modf_result_abstract",
- {{"fract", el}, {"whole", el}});
- abstract->SetConcreteTypes(utils::Vector{build_f32(), build_f16()});
- return abstract;
- },
- [&](Default) {
- TINT_ICE(Resolver, state.builder.Diagnostics())
- << "unhandled modf type: " << state.builder.FriendlyName(el);
- return nullptr;
- });
+const type::Struct* build_modf_result_vec(MatchState& state, Number& n, const type::Type* el) {
+ auto* vec = state.builder.create<type::Vector>(el, n.Value());
+ return CreateModfResult(state.builder, vec);
}
-const sem::Struct* build_modf_result_vec(MatchState& state, Number& n, const type::Type* el) {
- auto prefix = "__modf_result_vec" + std::to_string(n.Value());
- auto build_f32 = [&] {
- auto* vec =
- state.builder.create<type::Vector>(state.builder.create<type::F32>(), n.Value());
- return build_struct(state.builder, prefix + "_f32", {{"fract", vec}, {"whole", vec}});
- };
- auto build_f16 = [&] {
- auto* vec =
- state.builder.create<type::Vector>(state.builder.create<type::F16>(), n.Value());
- return build_struct(state.builder, prefix + "_f16", {{"fract", vec}, {"whole", vec}});
- };
-
- return Switch(
- el, //
- [&](const type::F32*) { return build_f32(); }, //
- [&](const type::F16*) { return build_f16(); }, //
- [&](const type::AbstractFloat*) {
- auto* vec = state.builder.create<type::Vector>(el, n.Value());
- auto* abstract =
- build_struct(state.builder, prefix + "_abstract", {{"fract", vec}, {"whole", vec}});
- abstract->SetConcreteTypes(utils::Vector{build_f32(), build_f16()});
- return abstract;
- },
- [&](Default) {
- TINT_ICE(Resolver, state.builder.Diagnostics())
- << "unhandled modf type: " << state.builder.FriendlyName(el);
- return nullptr;
- });
+const type::Struct* build_frexp_result(MatchState& state, const type::Type* el) {
+ return CreateFrexpResult(state.builder, el);
}
-const sem::Struct* build_frexp_result(MatchState& state, const type::Type* el) {
- auto build_f32 = [&] {
- auto* f = state.builder.create<type::F32>();
- auto* i = state.builder.create<type::I32>();
- return build_struct(state.builder, "__frexp_result_f32", {{"fract", f}, {"exp", i}});
- };
- auto build_f16 = [&] {
- auto* f = state.builder.create<type::F16>();
- auto* i = state.builder.create<type::I32>();
- return build_struct(state.builder, "__frexp_result_f16", {{"fract", f}, {"exp", i}});
- };
-
- return Switch(
- el, //
- [&](const type::F32*) { return build_f32(); }, //
- [&](const type::F16*) { return build_f16(); }, //
- [&](const type::AbstractFloat*) {
- auto* i = state.builder.create<type::AbstractInt>();
- auto* abstract =
- build_struct(state.builder, "__frexp_result_abstract", {{"fract", el}, {"exp", i}});
- abstract->SetConcreteTypes(utils::Vector{build_f32(), build_f16()});
- return abstract;
- },
- [&](Default) {
- TINT_ICE(Resolver, state.builder.Diagnostics())
- << "unhandled frexp type: " << state.builder.FriendlyName(el);
- return nullptr;
- });
+const type::Struct* build_frexp_result_vec(MatchState& state, Number& n, const type::Type* el) {
+ auto* vec = state.builder.create<type::Vector>(el, n.Value());
+ return CreateFrexpResult(state.builder, vec);
}
-const sem::Struct* build_frexp_result_vec(MatchState& state, Number& n, const type::Type* el) {
- auto prefix = "__frexp_result_vec" + std::to_string(n.Value());
- auto build_f32 = [&] {
- auto* f = state.builder.create<type::Vector>(state.builder.create<type::F32>(), n.Value());
- auto* e = state.builder.create<type::Vector>(state.builder.create<type::I32>(), n.Value());
- return build_struct(state.builder, prefix + "_f32", {{"fract", f}, {"exp", e}});
- };
- auto build_f16 = [&] {
- auto* f = state.builder.create<type::Vector>(state.builder.create<type::F16>(), n.Value());
- auto* e = state.builder.create<type::Vector>(state.builder.create<type::I32>(), n.Value());
- return build_struct(state.builder, prefix + "_f16", {{"fract", f}, {"exp", e}});
- };
-
- return Switch(
- el, //
- [&](const type::F32*) { return build_f32(); }, //
- [&](const type::F16*) { return build_f16(); }, //
- [&](const type::AbstractFloat*) {
- auto* f = state.builder.create<type::Vector>(el, n.Value());
- auto* e = state.builder.create<type::Vector>(state.builder.create<type::AbstractInt>(),
- n.Value());
- auto* abstract =
- build_struct(state.builder, prefix + "_abstract", {{"fract", f}, {"exp", e}});
- abstract->SetConcreteTypes(utils::Vector{build_f32(), build_f16()});
- return abstract;
- },
- [&](Default) {
- TINT_ICE(Resolver, state.builder.Diagnostics())
- << "unhandled frexp type: " << state.builder.FriendlyName(el);
- return nullptr;
- });
-}
-
-const sem::Struct* build_atomic_compare_exchange_result(MatchState& state, const type::Type* ty) {
- return build_struct(state.builder, "__atomic_compare_exchange_result" + ty->FriendlyName(),
- {{"old_value", const_cast<type::Type*>(ty)},
- {"exchanged", state.builder.create<type::Bool>()}});
+const type::Struct* build_atomic_compare_exchange_result(MatchState& state, const type::Type* ty) {
+ return CreateAtomicCompareExchangeResult(state.builder, ty);
}
/// ParameterInfo describes a parameter
diff --git a/src/tint/resolver/materialize_test.cc b/src/tint/resolver/materialize_test.cc
index 6fa2010..94d916c 100644
--- a/src/tint/resolver/materialize_test.cc
+++ b/src/tint/resolver/materialize_test.cc
@@ -1253,11 +1253,11 @@
auto* sem = Sem().Get(call);
ASSERT_TRUE(sem->Is<sem::Materialize>());
auto* materialize = sem->As<sem::Materialize>();
- ASSERT_TRUE(materialize->Type()->Is<sem::Struct>());
- auto* concrete_str = materialize->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Type()->Is<type::Struct>());
+ auto* concrete_str = materialize->Type()->As<type::Struct>();
ASSERT_TRUE(concrete_str->Members()[0]->Type()->Is<type::F32>());
- ASSERT_TRUE(materialize->Expr()->Type()->Is<sem::Struct>());
- auto* abstract_str = materialize->Expr()->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Expr()->Type()->Is<type::Struct>());
+ auto* abstract_str = materialize->Expr()->Type()->As<type::Struct>();
ASSERT_TRUE(abstract_str->Members()[0]->Type()->Is<type::AbstractFloat>());
}
@@ -1269,12 +1269,12 @@
auto* sem = Sem().Get(call);
ASSERT_TRUE(sem->Is<sem::Materialize>());
auto* materialize = sem->As<sem::Materialize>();
- ASSERT_TRUE(materialize->Type()->Is<sem::Struct>());
- auto* concrete_str = materialize->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Type()->Is<type::Struct>());
+ auto* concrete_str = materialize->Type()->As<type::Struct>();
ASSERT_TRUE(concrete_str->Members()[0]->Type()->Is<type::Vector>());
ASSERT_TRUE(concrete_str->Members()[0]->Type()->As<type::Vector>()->type()->Is<type::F32>());
- ASSERT_TRUE(materialize->Expr()->Type()->Is<sem::Struct>());
- auto* abstract_str = materialize->Expr()->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Expr()->Type()->Is<type::Struct>());
+ auto* abstract_str = materialize->Expr()->Type()->As<type::Struct>();
ASSERT_TRUE(abstract_str->Members()[0]->Type()->Is<type::Vector>());
ASSERT_TRUE(
abstract_str->Members()[0]->Type()->As<type::Vector>()->type()->Is<type::AbstractFloat>());
@@ -1291,11 +1291,11 @@
auto* sem = Sem().Get(call);
ASSERT_TRUE(sem->Is<sem::Materialize>());
auto* materialize = sem->As<sem::Materialize>();
- ASSERT_TRUE(materialize->Type()->Is<sem::Struct>());
- auto* concrete_str = materialize->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Type()->Is<type::Struct>());
+ auto* concrete_str = materialize->Type()->As<type::Struct>();
ASSERT_TRUE(concrete_str->Members()[0]->Type()->Is<type::F16>());
- ASSERT_TRUE(materialize->Expr()->Type()->Is<sem::Struct>());
- auto* abstract_str = materialize->Expr()->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Expr()->Type()->Is<type::Struct>());
+ auto* abstract_str = materialize->Expr()->Type()->As<type::Struct>();
ASSERT_TRUE(abstract_str->Members()[0]->Type()->Is<type::AbstractFloat>());
}
@@ -1309,12 +1309,12 @@
auto* sem = Sem().Get(call);
ASSERT_TRUE(sem->Is<sem::Materialize>());
auto* materialize = sem->As<sem::Materialize>();
- ASSERT_TRUE(materialize->Type()->Is<sem::Struct>());
- auto* concrete_str = materialize->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Type()->Is<type::Struct>());
+ auto* concrete_str = materialize->Type()->As<type::Struct>();
ASSERT_TRUE(concrete_str->Members()[0]->Type()->Is<type::Vector>());
ASSERT_TRUE(concrete_str->Members()[0]->Type()->As<type::Vector>()->type()->Is<type::F16>());
- ASSERT_TRUE(materialize->Expr()->Type()->Is<sem::Struct>());
- auto* abstract_str = materialize->Expr()->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Expr()->Type()->Is<type::Struct>());
+ auto* abstract_str = materialize->Expr()->Type()->As<type::Struct>();
ASSERT_TRUE(abstract_str->Members()[0]->Type()->Is<type::Vector>());
ASSERT_TRUE(
abstract_str->Members()[0]->Type()->As<type::Vector>()->type()->Is<type::AbstractFloat>());
@@ -1328,12 +1328,12 @@
auto* sem = Sem().Get(call);
ASSERT_TRUE(sem->Is<sem::Materialize>());
auto* materialize = sem->As<sem::Materialize>();
- ASSERT_TRUE(materialize->Type()->Is<sem::Struct>());
- auto* concrete_str = materialize->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Type()->Is<type::Struct>());
+ auto* concrete_str = materialize->Type()->As<type::Struct>();
ASSERT_TRUE(concrete_str->Members()[0]->Type()->Is<type::F32>());
ASSERT_TRUE(concrete_str->Members()[1]->Type()->Is<type::I32>());
- ASSERT_TRUE(materialize->Expr()->Type()->Is<sem::Struct>());
- auto* abstract_str = materialize->Expr()->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Expr()->Type()->Is<type::Struct>());
+ auto* abstract_str = materialize->Expr()->Type()->As<type::Struct>();
ASSERT_TRUE(abstract_str->Members()[0]->Type()->Is<type::AbstractFloat>());
ASSERT_TRUE(abstract_str->Members()[1]->Type()->Is<type::AbstractInt>());
}
@@ -1346,14 +1346,14 @@
auto* sem = Sem().Get(call);
ASSERT_TRUE(sem->Is<sem::Materialize>());
auto* materialize = sem->As<sem::Materialize>();
- ASSERT_TRUE(materialize->Type()->Is<sem::Struct>());
- auto* concrete_str = materialize->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Type()->Is<type::Struct>());
+ auto* concrete_str = materialize->Type()->As<type::Struct>();
ASSERT_TRUE(concrete_str->Members()[0]->Type()->Is<type::Vector>());
ASSERT_TRUE(concrete_str->Members()[1]->Type()->Is<type::Vector>());
ASSERT_TRUE(concrete_str->Members()[0]->Type()->As<type::Vector>()->type()->Is<type::F32>());
ASSERT_TRUE(concrete_str->Members()[1]->Type()->As<type::Vector>()->type()->Is<type::I32>());
- ASSERT_TRUE(materialize->Expr()->Type()->Is<sem::Struct>());
- auto* abstract_str = materialize->Expr()->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Expr()->Type()->Is<type::Struct>());
+ auto* abstract_str = materialize->Expr()->Type()->As<type::Struct>();
ASSERT_TRUE(abstract_str->Members()[0]->Type()->Is<type::Vector>());
ASSERT_TRUE(
abstract_str->Members()[0]->Type()->As<type::Vector>()->type()->Is<type::AbstractFloat>());
@@ -1372,12 +1372,12 @@
auto* sem = Sem().Get(call);
ASSERT_TRUE(sem->Is<sem::Materialize>());
auto* materialize = sem->As<sem::Materialize>();
- ASSERT_TRUE(materialize->Type()->Is<sem::Struct>());
- auto* concrete_str = materialize->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Type()->Is<type::Struct>());
+ auto* concrete_str = materialize->Type()->As<type::Struct>();
ASSERT_TRUE(concrete_str->Members()[0]->Type()->Is<type::F16>());
ASSERT_TRUE(concrete_str->Members()[1]->Type()->Is<type::I32>());
- ASSERT_TRUE(materialize->Expr()->Type()->Is<sem::Struct>());
- auto* abstract_str = materialize->Expr()->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Expr()->Type()->Is<type::Struct>());
+ auto* abstract_str = materialize->Expr()->Type()->As<type::Struct>();
ASSERT_TRUE(abstract_str->Members()[0]->Type()->Is<type::AbstractFloat>());
ASSERT_TRUE(abstract_str->Members()[1]->Type()->Is<type::AbstractInt>());
}
@@ -1392,14 +1392,14 @@
auto* sem = Sem().Get(call);
ASSERT_TRUE(sem->Is<sem::Materialize>());
auto* materialize = sem->As<sem::Materialize>();
- ASSERT_TRUE(materialize->Type()->Is<sem::Struct>());
- auto* concrete_str = materialize->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Type()->Is<type::Struct>());
+ auto* concrete_str = materialize->Type()->As<type::Struct>();
ASSERT_TRUE(concrete_str->Members()[0]->Type()->Is<type::Vector>());
ASSERT_TRUE(concrete_str->Members()[1]->Type()->Is<type::Vector>());
ASSERT_TRUE(concrete_str->Members()[0]->Type()->As<type::Vector>()->type()->Is<type::F16>());
ASSERT_TRUE(concrete_str->Members()[1]->Type()->As<type::Vector>()->type()->Is<type::I32>());
- ASSERT_TRUE(materialize->Expr()->Type()->Is<sem::Struct>());
- auto* abstract_str = materialize->Expr()->Type()->As<sem::Struct>();
+ ASSERT_TRUE(materialize->Expr()->Type()->Is<type::Struct>());
+ auto* abstract_str = materialize->Expr()->Type()->As<type::Struct>();
ASSERT_TRUE(abstract_str->Members()[0]->Type()->Is<type::Vector>());
ASSERT_TRUE(
abstract_str->Members()[0]->Type()->As<type::Vector>()->type()->Is<type::AbstractFloat>());
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 58050b9..de29692 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -43,6 +43,7 @@
#include "src/tint/ast/while_statement.h"
#include "src/tint/ast/workgroup_attribute.h"
#include "src/tint/builtin/builtin.h"
+#include "src/tint/resolver/builtin_structs.h"
#include "src/tint/resolver/uniformity.h"
#include "src/tint/sem/break_if_statement.h"
#include "src/tint/sem/builtin_enum_expression.h"
@@ -246,6 +247,20 @@
}
}
+ for (auto* attribute : v->attributes) {
+ Mark(attribute);
+ bool ok = Switch(
+ attribute, //
+ [&](const ast::InternalAttribute* attr) -> bool { return InternalAttribute(attr); },
+ [&](Default) {
+ ErrorInvalidAttribute(attribute, "'let' declaration");
+ return false;
+ });
+ if (!ok) {
+ return nullptr;
+ }
+ }
+
if (!v->initializer) {
AddError("'let' declaration must have an initializer", v->source);
return nullptr;
@@ -339,37 +354,51 @@
/* constant_value */ nullptr, std::nullopt, std::nullopt);
sem->SetInitializer(rhs);
- if (auto* id_attr = ast::GetAttribute<ast::IdAttribute>(v->attributes)) {
- ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@id"};
- TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
+ for (auto* attribute : v->attributes) {
+ Mark(attribute);
+ bool ok = Switch(
+ attribute, //
+ [&](const ast::IdAttribute* attr) {
+ ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@id"};
+ TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
- auto* materialized = Materialize(ValueExpression(id_attr->expr));
- if (!materialized) {
+ auto* materialized = Materialize(ValueExpression(attr->expr));
+ if (!materialized) {
+ return false;
+ }
+ if (!materialized->Type()->IsAnyOf<type::I32, type::U32>()) {
+ AddError("@id must be an i32 or u32 value", attr->source);
+ return false;
+ }
+
+ auto const_value = materialized->ConstantValue();
+ auto value = const_value->ValueAs<AInt>();
+ if (value < 0) {
+ AddError("@id value must be non-negative", attr->source);
+ return false;
+ }
+ if (value > std::numeric_limits<decltype(OverrideId::value)>::max()) {
+ AddError(
+ "@id value must be between 0 and " +
+ std::to_string(std::numeric_limits<decltype(OverrideId::value)>::max()),
+ attr->source);
+ return false;
+ }
+
+ auto o = OverrideId{static_cast<decltype(OverrideId::value)>(value)};
+ sem->SetOverrideId(o);
+
+ // Track the constant IDs that are specified in the shader.
+ override_ids_.Add(o, sem);
+ return true;
+ },
+ [&](Default) {
+ ErrorInvalidAttribute(attribute, "'override' declaration");
+ return false;
+ });
+ if (!ok) {
return nullptr;
}
- if (!materialized->Type()->IsAnyOf<type::I32, type::U32>()) {
- AddError("@id must be an i32 or u32 value", id_attr->source);
- return nullptr;
- }
-
- auto const_value = materialized->ConstantValue();
- auto value = const_value->ValueAs<AInt>();
- if (value < 0) {
- AddError("@id value must be non-negative", id_attr->source);
- return nullptr;
- }
- if (value > std::numeric_limits<decltype(OverrideId::value)>::max()) {
- AddError("@id value must be between 0 and " +
- std::to_string(std::numeric_limits<decltype(OverrideId::value)>::max()),
- id_attr->source);
- return nullptr;
- }
-
- auto o = OverrideId{static_cast<decltype(OverrideId::value)>(value)};
- sem->SetOverrideId(o);
-
- // Track the constant IDs that are specified in the shader.
- override_ids_.Add(o, sem);
}
builder_->Sem().Add(v, sem);
@@ -392,6 +421,18 @@
return nullptr;
}
+ for (auto* attribute : c->attributes) {
+ Mark(attribute);
+ bool ok = Switch(attribute, //
+ [&](Default) {
+ ErrorInvalidAttribute(attribute, "'const' declaration");
+ return false;
+ });
+ if (!ok) {
+ return nullptr;
+ }
+ }
+
const sem::ValueExpression* rhs = nullptr;
{
ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "const initializer"};
@@ -528,72 +569,98 @@
sem::Variable* sem = nullptr;
if (is_global) {
+ bool has_io_address_space = address_space == builtin::AddressSpace::kIn ||
+ address_space == builtin::AddressSpace::kOut;
+
+ std::optional<uint32_t> group, binding, location;
+ for (auto* attribute : var->attributes) {
+ Mark(attribute);
+ enum Status { kSuccess, kErrored, kInvalid };
+ auto res = Switch(
+ attribute, //
+ [&](const ast::BindingAttribute* attr) {
+ auto value = BindingAttribute(attr);
+ if (!value) {
+ return kErrored;
+ }
+ binding = value.Get();
+ return kSuccess;
+ },
+ [&](const ast::GroupAttribute* attr) {
+ auto value = GroupAttribute(attr);
+ if (!value) {
+ return kErrored;
+ }
+ group = value.Get();
+ return kSuccess;
+ },
+ [&](const ast::LocationAttribute* attr) {
+ if (!has_io_address_space) {
+ return kInvalid;
+ }
+ auto value = LocationAttribute(attr);
+ if (!value) {
+ return kErrored;
+ }
+ location = value.Get();
+ return kSuccess;
+ },
+ [&](const ast::BuiltinAttribute* attr) {
+ if (!has_io_address_space) {
+ return kInvalid;
+ }
+ return BuiltinAttribute(attr) ? kSuccess : kErrored;
+ },
+ [&](const ast::InterpolateAttribute* attr) {
+ if (!has_io_address_space) {
+ return kInvalid;
+ }
+ return InterpolateAttribute(attr) ? kSuccess : kErrored;
+ },
+ [&](const ast::InvariantAttribute* attr) {
+ if (!has_io_address_space) {
+ return kInvalid;
+ }
+ return InvariantAttribute(attr) ? kSuccess : kErrored;
+ },
+ [&](const ast::InternalAttribute* attr) {
+ return InternalAttribute(attr) ? kSuccess : kErrored;
+ },
+ [&](Default) { return kInvalid; });
+
+ switch (res) {
+ case kSuccess:
+ break;
+ case kErrored:
+ return nullptr;
+ case kInvalid:
+ ErrorInvalidAttribute(attribute, "module-scope 'var'");
+ return nullptr;
+ }
+ }
+
std::optional<sem::BindingPoint> binding_point;
- if (var->HasBindingPoint()) {
- uint32_t binding = 0;
- {
- ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@binding"};
- TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
-
- auto* attr = ast::GetAttribute<ast::BindingAttribute>(var->attributes);
- auto* materialized = Materialize(ValueExpression(attr->expr));
- if (!materialized) {
- return nullptr;
- }
- if (!materialized->Type()->IsAnyOf<type::I32, type::U32>()) {
- AddError("@binding must be an i32 or u32 value", attr->source);
- return nullptr;
- }
-
- auto const_value = materialized->ConstantValue();
- auto value = const_value->ValueAs<AInt>();
- if (value < 0) {
- AddError("@binding value must be non-negative", attr->source);
- return nullptr;
- }
- binding = u32(value);
- }
-
- uint32_t group = 0;
- {
- ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@group"};
- TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
-
- auto* attr = ast::GetAttribute<ast::GroupAttribute>(var->attributes);
- auto* materialized = Materialize(ValueExpression(attr->expr));
- if (!materialized) {
- return nullptr;
- }
- if (!materialized->Type()->IsAnyOf<type::I32, type::U32>()) {
- AddError("@group must be an i32 or u32 value", attr->source);
- return nullptr;
- }
-
- auto const_value = materialized->ConstantValue();
- auto value = const_value->ValueAs<AInt>();
- if (value < 0) {
- AddError("@group value must be non-negative", attr->source);
- return nullptr;
- }
- group = u32(value);
- }
- binding_point = {group, binding};
+ if (group && binding) {
+ binding_point = sem::BindingPoint{group.value(), binding.value()};
}
-
- std::optional<uint32_t> location;
- if (auto* attr = ast::GetAttribute<ast::LocationAttribute>(var->attributes)) {
- auto value = LocationAttribute(attr);
- if (!value) {
- return nullptr;
- }
- location = value.Get();
- }
-
sem = builder_->create<sem::GlobalVariable>(
var, var_ty, sem::EvaluationStage::kRuntime, address_space, access,
/* constant_value */ nullptr, binding_point, location);
} else {
+ for (auto* attribute : var->attributes) {
+ Mark(attribute);
+ bool ok = Switch(
+ attribute,
+ [&](const ast::InternalAttribute* attr) { return InternalAttribute(attr); },
+ [&](Default) {
+ ErrorInvalidAttribute(attribute, "function-scope 'var'");
+ return false;
+ });
+ if (!ok) {
+ return nullptr;
+ }
+ }
sem = builder_->create<sem::LocalVariable>(var, var_ty, sem::EvaluationStage::kRuntime,
address_space, access, current_statement_,
/* constant_value */ nullptr);
@@ -604,18 +671,93 @@
return sem;
}
-sem::Parameter* Resolver::Parameter(const ast::Parameter* param, uint32_t index) {
+sem::Parameter* Resolver::Parameter(const ast::Parameter* param,
+ const ast::Function* func,
+ uint32_t index) {
Mark(param->name);
auto add_note = [&] {
AddNote("while instantiating parameter " + param->name->symbol.Name(), param->source);
};
- for (auto* attr : param->attributes) {
- if (!Attribute(attr)) {
- return nullptr;
+ std::optional<uint32_t> location, group, binding;
+
+ if (func->IsEntryPoint()) {
+ for (auto* attribute : param->attributes) {
+ Mark(attribute);
+ bool ok = Switch(
+ attribute, //
+ [&](const ast::LocationAttribute* attr) {
+ auto value = LocationAttribute(attr);
+ if (!value) {
+ return false;
+ }
+ location = value.Get();
+ return true;
+ },
+ [&](const ast::BuiltinAttribute* attr) -> bool { return BuiltinAttribute(attr); },
+ [&](const ast::InvariantAttribute* attr) -> bool {
+ return InvariantAttribute(attr);
+ },
+ [&](const ast::InterpolateAttribute* attr) -> bool {
+ return InterpolateAttribute(attr);
+ },
+ [&](const ast::InternalAttribute* attr) -> bool { return InternalAttribute(attr); },
+ [&](const ast::GroupAttribute* attr) -> bool {
+ if (validator_.IsValidationEnabled(
+ param->attributes, ast::DisabledValidation::kEntryPointParameter)) {
+ ErrorInvalidAttribute(attribute, "function parameters");
+ return false;
+ }
+ auto value = GroupAttribute(attr);
+ if (!value) {
+ return false;
+ }
+ group = value.Get();
+ return true;
+ },
+ [&](const ast::BindingAttribute* attr) -> bool {
+ if (validator_.IsValidationEnabled(
+ param->attributes, ast::DisabledValidation::kEntryPointParameter)) {
+ ErrorInvalidAttribute(attribute, "function parameters");
+ return false;
+ }
+ auto value = BindingAttribute(attr);
+ if (!value) {
+ return false;
+ }
+ binding = value.Get();
+ return true;
+ },
+ [&](Default) {
+ ErrorInvalidAttribute(attribute, "function parameters");
+ return false;
+ });
+ if (!ok) {
+ return nullptr;
+ }
+ }
+ } else {
+ for (auto* attribute : param->attributes) {
+ Mark(attribute);
+ bool ok = Switch(
+ attribute, //
+ [&](const ast::InternalAttribute* attr) -> bool { return InternalAttribute(attr); },
+ [&](Default) {
+ if (attribute->IsAnyOf<ast::LocationAttribute, ast::BuiltinAttribute,
+ ast::InvariantAttribute, ast::InterpolateAttribute>()) {
+ ErrorInvalidAttribute(attribute, "non-entry point function parameters");
+ } else {
+ ErrorInvalidAttribute(attribute, "function parameters");
+ }
+ return false;
+ });
+ if (!ok) {
+ return nullptr;
+ }
}
}
+
if (!validator_.NoDuplicateAttributes(param->attributes)) {
return nullptr;
}
@@ -641,72 +783,22 @@
}
std::optional<sem::BindingPoint> binding_point;
- if (param->HasBindingPoint()) {
- binding_point = sem::BindingPoint{};
- {
- ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@binding value"};
- TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
-
- auto* attr = ast::GetAttribute<ast::BindingAttribute>(param->attributes);
- auto* materialized = Materialize(ValueExpression(attr->expr));
- if (!materialized) {
- return nullptr;
- }
- binding_point->binding = materialized->ConstantValue()->ValueAs<u32>();
- }
- {
- ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@group value"};
- TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
-
- auto* attr = ast::GetAttribute<ast::GroupAttribute>(param->attributes);
- auto* materialized = Materialize(ValueExpression(attr->expr));
- if (!materialized) {
- return nullptr;
- }
- binding_point->group = materialized->ConstantValue()->ValueAs<u32>();
- }
- }
-
- std::optional<uint32_t> location;
- if (auto* attr = ast::GetAttribute<ast::LocationAttribute>(param->attributes)) {
- auto value = LocationAttribute(attr);
- if (!value) {
- return nullptr;
- }
- location = value.Get();
+ if (group && binding) {
+ binding_point = sem::BindingPoint{group.value(), binding.value()};
}
auto* sem = builder_->create<sem::Parameter>(
param, index, ty, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined,
sem::ParameterUsage::kNone, binding_point, location);
builder_->Sem().Add(param, sem);
+
+ if (!validator_.Parameter(sem)) {
+ return nullptr;
+ }
+
return sem;
}
-utils::Result<uint32_t> Resolver::LocationAttribute(const ast::LocationAttribute* attr) {
- ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@location value"};
- TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
-
- auto* materialized = Materialize(ValueExpression(attr->expr));
- if (!materialized) {
- return utils::Failure;
- }
-
- if (!materialized->Type()->IsAnyOf<type::I32, type::U32>()) {
- AddError("@location must be an i32 or u32 value", attr->source);
- return utils::Failure;
- }
-
- auto const_value = materialized->ConstantValue();
- auto value = const_value->ValueAs<AInt>();
- if (value < 0) {
- AddError("@location value must be non-negative", attr->source);
- return utils::Failure;
- }
-
- return static_cast<uint32_t>(value);
-}
-
builtin::Access Resolver::DefaultAccessForAddressSpace(builtin::AddressSpace address_space) {
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
switch (address_space) {
@@ -795,12 +887,6 @@
return nullptr;
}
- for (auto* attr : v->attributes) {
- if (!Attribute(attr)) {
- return nullptr;
- }
- }
-
if (!validator_.NoDuplicateAttributes(v->attributes)) {
return nullptr;
}
@@ -859,8 +945,28 @@
validator_.DiagnosticFilters().Push();
TINT_DEFER(validator_.DiagnosticFilters().Pop());
- for (auto* attr : decl->attributes) {
- if (!Attribute(attr)) {
+
+ for (auto* attribute : decl->attributes) {
+ Mark(attribute);
+ bool ok = Switch(
+ attribute,
+ [&](const ast::DiagnosticAttribute* attr) { return DiagnosticAttribute(attr); },
+ [&](const ast::StageAttribute* attr) { return StageAttribute(attr); },
+ [&](const ast::MustUseAttribute* attr) { return MustUseAttribute(attr); },
+ [&](const ast::WorkgroupAttribute* attr) {
+ auto value = WorkgroupAttribute(attr);
+ if (!value) {
+ return false;
+ }
+ func->SetWorkgroupSize(value.Get());
+ return true;
+ },
+ [&](const ast::InternalAttribute* attr) { return InternalAttribute(attr); },
+ [&](Default) {
+ ErrorInvalidAttribute(attribute, "functions");
+ return false;
+ });
+ if (!ok) {
return nullptr;
}
}
@@ -883,19 +989,15 @@
}
}
- auto* p = Parameter(param, parameter_index++);
+ auto* p = Parameter(param, decl, parameter_index++);
if (!p) {
return nullptr;
}
- if (!validator_.Parameter(decl, p)) {
- return nullptr;
- }
-
func->AddParameter(p);
auto* p_ty = const_cast<type::Type*>(p->Type());
- if (auto* str = p_ty->As<sem::Struct>()) {
+ if (auto* str = p_ty->As<type::Struct>()) {
switch (decl->PipelineStage()) {
case ast::PipelineStage::kVertex:
str->AddUsage(type::PipelineStageUsage::kVertexInput);
@@ -924,22 +1026,77 @@
}
func->SetReturnType(return_type);
- // Determine if the return type has a location
- for (auto* attr : decl->return_type_attributes) {
- if (!Attribute(attr)) {
- return nullptr;
- }
+ if (decl->IsEntryPoint()) {
+ // Determine if the return type has a location
+ bool permissive = validator_.IsValidationDisabled(
+ decl->attributes, ast::DisabledValidation::kEntryPointParameter) ||
+ validator_.IsValidationDisabled(
+ decl->attributes, ast::DisabledValidation::kFunctionParameter);
+ for (auto* attribute : decl->return_type_attributes) {
+ Mark(attribute);
+ enum Status { kSuccess, kErrored, kInvalid };
+ auto res = Switch(
+ attribute, //
+ [&](const ast::LocationAttribute* attr) {
+ auto value = LocationAttribute(attr);
+ if (!value) {
+ return kErrored;
+ }
+ func->SetReturnLocation(value.Get());
+ return kSuccess;
+ },
+ [&](const ast::BuiltinAttribute* attr) {
+ return BuiltinAttribute(attr) ? kSuccess : kErrored;
+ },
+ [&](const ast::InternalAttribute* attr) {
+ return InternalAttribute(attr) ? kSuccess : kErrored;
+ },
+ [&](const ast::InterpolateAttribute* attr) {
+ return InterpolateAttribute(attr) ? kSuccess : kErrored;
+ },
+ [&](const ast::InvariantAttribute* attr) {
+ return InvariantAttribute(attr) ? kSuccess : kErrored;
+ },
+ [&](const ast::BindingAttribute* attr) {
+ if (!permissive) {
+ return kInvalid;
+ }
+ return BindingAttribute(attr) ? kSuccess : kErrored;
+ },
+ [&](const ast::GroupAttribute* attr) {
+ if (!permissive) {
+ return kInvalid;
+ }
+ return GroupAttribute(attr) ? kSuccess : kErrored;
+ },
+ [&](Default) { return kInvalid; });
- if (auto* loc_attr = attr->As<ast::LocationAttribute>()) {
- auto value = LocationAttribute(loc_attr);
- if (!value) {
+ switch (res) {
+ case kSuccess:
+ break;
+ case kErrored:
+ return nullptr;
+ case kInvalid:
+ ErrorInvalidAttribute(attribute, "entry point return types");
+ return nullptr;
+ }
+ }
+ } else {
+ for (auto* attribute : decl->return_type_attributes) {
+ Mark(attribute);
+ bool ok = Switch(attribute, //
+ [&](Default) {
+ ErrorInvalidAttribute(attribute,
+ "non-entry point function return types");
+ return false;
+ });
+ if (!ok) {
return nullptr;
}
- func->SetReturnLocation(value.Get());
}
}
- if (auto* str = return_type->As<sem::Struct>()) {
+ if (auto* str = return_type->As<type::Struct>()) {
if (!ApplyAddressSpaceUsageToType(builtin::AddressSpace::kUndefined, str, decl->source)) {
AddNote("while instantiating return type for " + decl->name->symbol.Name(),
decl->source);
@@ -963,10 +1120,6 @@
ApplyDiagnosticSeverities(func);
- if (!WorkgroupSize(decl)) {
- return nullptr;
- }
-
if (decl->IsEntryPoint()) {
entry_points_.Push(func);
}
@@ -1015,94 +1168,6 @@
return func;
}
-bool Resolver::WorkgroupSize(const ast::Function* func) {
- // Set work-group size defaults.
- sem::WorkgroupSize ws;
- for (size_t i = 0; i < 3; i++) {
- ws[i] = 1;
- }
-
- auto* attr = ast::GetAttribute<ast::WorkgroupAttribute>(func->attributes);
- if (!attr) {
- return true;
- }
-
- auto values = attr->Values();
- utils::Vector<const sem::ValueExpression*, 3> args;
- utils::Vector<const type::Type*, 3> arg_tys;
-
- constexpr const char* kErrBadExpr =
- "workgroup_size argument must be a constant or override-expression of type "
- "abstract-integer, i32 or u32";
-
- for (size_t i = 0; i < 3; i++) {
- // Each argument to this attribute can either be a literal, an identifier for a
- // module-scope constants, a const-expression, or nullptr if not specified.
- auto* value = values[i];
- if (!value) {
- break;
- }
- const auto* expr = ValueExpression(value);
- if (!expr) {
- return false;
- }
- auto* ty = expr->Type();
- if (!ty->IsAnyOf<type::I32, type::U32, type::AbstractInt>()) {
- AddError(kErrBadExpr, value->source);
- return false;
- }
-
- if (expr->Stage() != sem::EvaluationStage::kConstant &&
- expr->Stage() != sem::EvaluationStage::kOverride) {
- AddError(kErrBadExpr, value->source);
- return false;
- }
-
- args.Push(expr);
- arg_tys.Push(ty);
- }
-
- auto* common_ty = type::Type::Common(arg_tys);
- if (!common_ty) {
- AddError("workgroup_size arguments must be of the same type, either i32 or u32",
- attr->source);
- return false;
- }
-
- // If all arguments are abstract-integers, then materialize to i32.
- if (common_ty->Is<type::AbstractInt>()) {
- common_ty = builder_->create<type::I32>();
- }
-
- for (size_t i = 0; i < args.Length(); i++) {
- auto* materialized = Materialize(args[i], common_ty);
- if (!materialized) {
- return false;
- }
- if (auto* value = materialized->ConstantValue()) {
- if (value->ValueAs<AInt>() < 1) {
- AddError("workgroup_size argument must be at least 1", values[i]->source);
- return false;
- }
- ws[i] = value->ValueAs<u32>();
- } else {
- ws[i] = std::nullopt;
- }
- }
-
- uint64_t total_size = static_cast<uint64_t>(ws[0].value_or(1));
- for (size_t i = 1; i < 3; i++) {
- total_size *= static_cast<uint64_t>(ws[i].value_or(1));
- if (total_size > 0xffffffff) {
- AddError("total workgroup grid size cannot exceed 0xffffffff", values[i]->source);
- return false;
- }
- }
-
- current_function_->SetWorkgroupSize(std::move(ws));
- return true;
-}
-
bool Resolver::Statements(utils::VectorRef<const ast::Statement*> stmts) {
sem::Behaviors behaviors{sem::Behavior::kNext};
@@ -1696,7 +1761,7 @@
}
return nullptr;
},
- [&](const sem::Struct* s) -> const type::Type* {
+ [&](const type::Struct* s) -> const type::Type* {
if (auto tys = s->ConcreteTypes(); !tys.IsEmpty()) {
return target_ty ? target_ty : tys[0];
}
@@ -2078,7 +2143,7 @@
}
return call;
},
- [&](const sem::Struct* str) -> sem::Call* {
+ [&](const type::Struct* str) -> sem::Call* {
auto* call_target = struct_ctors_.GetOrCreate(
StructConstructorSig{{str, args.Length(), args_stage}},
[&]() -> sem::ValueConstructor* {
@@ -2336,6 +2401,7 @@
auto check_no_tmpl_args = [&](type::Type* ty) -> type::Type* {
return TINT_LIKELY(CheckNotTemplated("type", ident)) ? ty : nullptr;
};
+ auto af = [&] { return b.create<type::AbstractFloat>(); };
auto f32 = [&] { return b.create<type::F32>(); };
auto i32 = [&] { return b.create<type::I32>(); };
auto u32 = [&] { return b.create<type::U32>(); };
@@ -2586,9 +2652,6 @@
return nullptr;
}
- if (TINT_UNLIKELY(!el_ty)) {
- return nullptr;
- }
if (TINT_UNLIKELY(!validator_.Vector(el_ty, ident->source))) {
return nullptr;
}
@@ -2740,9 +2803,60 @@
return storage_texture(type::TextureDimension::k2dArray);
case builtin::Builtin::kTextureStorage3D:
return storage_texture(type::TextureDimension::k3d);
- case builtin::Builtin::kPackedVec3: {
+ case builtin::Builtin::kPackedVec3:
return packed_vec3_t();
- }
+ case builtin::Builtin::kAtomicCompareExchangeResultI32:
+ return CreateAtomicCompareExchangeResult(*builder_, i32());
+ case builtin::Builtin::kAtomicCompareExchangeResultU32:
+ return CreateAtomicCompareExchangeResult(*builder_, u32());
+ case builtin::Builtin::kFrexpResultAbstract:
+ return CreateFrexpResult(*builder_, af());
+ case builtin::Builtin::kFrexpResultF16:
+ return CreateFrexpResult(*builder_, f16());
+ case builtin::Builtin::kFrexpResultF32:
+ return CreateFrexpResult(*builder_, f32());
+ case builtin::Builtin::kFrexpResultVec2Abstract:
+ return CreateFrexpResult(*builder_, vec(af(), 2));
+ case builtin::Builtin::kFrexpResultVec2F16:
+ return CreateFrexpResult(*builder_, vec(f16(), 2));
+ case builtin::Builtin::kFrexpResultVec2F32:
+ return CreateFrexpResult(*builder_, vec(f32(), 2));
+ case builtin::Builtin::kFrexpResultVec3Abstract:
+ return CreateFrexpResult(*builder_, vec(af(), 3));
+ case builtin::Builtin::kFrexpResultVec3F16:
+ return CreateFrexpResult(*builder_, vec(f16(), 3));
+ case builtin::Builtin::kFrexpResultVec3F32:
+ return CreateFrexpResult(*builder_, vec(f32(), 3));
+ case builtin::Builtin::kFrexpResultVec4Abstract:
+ return CreateFrexpResult(*builder_, vec(af(), 4));
+ case builtin::Builtin::kFrexpResultVec4F16:
+ return CreateFrexpResult(*builder_, vec(f16(), 4));
+ case builtin::Builtin::kFrexpResultVec4F32:
+ return CreateFrexpResult(*builder_, vec(f32(), 4));
+ case builtin::Builtin::kModfResultAbstract:
+ return CreateModfResult(*builder_, af());
+ case builtin::Builtin::kModfResultF16:
+ return CreateModfResult(*builder_, f16());
+ case builtin::Builtin::kModfResultF32:
+ return CreateModfResult(*builder_, f32());
+ case builtin::Builtin::kModfResultVec2Abstract:
+ return CreateModfResult(*builder_, vec(af(), 2));
+ case builtin::Builtin::kModfResultVec2F16:
+ return CreateModfResult(*builder_, vec(f16(), 2));
+ case builtin::Builtin::kModfResultVec2F32:
+ return CreateModfResult(*builder_, vec(f32(), 2));
+ case builtin::Builtin::kModfResultVec3Abstract:
+ return CreateModfResult(*builder_, vec(af(), 3));
+ case builtin::Builtin::kModfResultVec3F16:
+ return CreateModfResult(*builder_, vec(f16(), 3));
+ case builtin::Builtin::kModfResultVec3F32:
+ return CreateModfResult(*builder_, vec(f32(), 3));
+ case builtin::Builtin::kModfResultVec4Abstract:
+ return CreateModfResult(*builder_, vec(af(), 4));
+ case builtin::Builtin::kModfResultVec4F16:
+ return CreateModfResult(*builder_, vec(f16(), 4));
+ case builtin::Builtin::kModfResultVec4F32:
+ return CreateModfResult(*builder_, vec(f32(), 4));
case builtin::Builtin::kUndefined:
break;
}
@@ -3134,10 +3248,10 @@
return Switch(
storage_ty, //
- [&](const sem::Struct* str) -> sem::ValueExpression* {
+ [&](const type::Struct* str) -> sem::ValueExpression* {
auto symbol = expr->member->symbol;
- const sem::StructMember* member = nullptr;
+ const type::StructMember* member = nullptr;
for (auto* m : str->Members()) {
if (m->Name() == symbol) {
member = m;
@@ -3424,38 +3538,207 @@
return sem;
}
-bool Resolver::Attribute(const ast::Attribute* attr) {
- Mark(attr);
- return Switch(
- attr, //
- [&](const ast::BuiltinAttribute* b) { return BuiltinAttribute(b); },
- [&](const ast::DiagnosticAttribute* d) { return DiagnosticControl(d->control); },
- [&](const ast::InterpolateAttribute* i) { return InterpolateAttribute(i); },
- [&](const ast::InternalAttribute* i) { return InternalAttribute(i); },
- [&](Default) { return true; });
+utils::Result<uint32_t> Resolver::LocationAttribute(const ast::LocationAttribute* attr) {
+ ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@location value"};
+ TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
+
+ auto* materialized = Materialize(ValueExpression(attr->expr));
+ if (!materialized) {
+ return utils::Failure;
+ }
+
+ if (!materialized->Type()->IsAnyOf<type::I32, type::U32>()) {
+ AddError("@location must be an i32 or u32 value", attr->source);
+ return utils::Failure;
+ }
+
+ auto const_value = materialized->ConstantValue();
+ auto value = const_value->ValueAs<AInt>();
+ if (value < 0) {
+ AddError("@location value must be non-negative", attr->source);
+ return utils::Failure;
+ }
+
+ return static_cast<uint32_t>(value);
}
-bool Resolver::BuiltinAttribute(const ast::BuiltinAttribute* attr) {
+utils::Result<uint32_t> Resolver::BindingAttribute(const ast::BindingAttribute* attr) {
+ ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@binding"};
+ TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
+
+ auto* materialized = Materialize(ValueExpression(attr->expr));
+ if (!materialized) {
+ return utils::Failure;
+ }
+ if (!materialized->Type()->IsAnyOf<type::I32, type::U32>()) {
+ AddError("@binding must be an i32 or u32 value", attr->source);
+ return utils::Failure;
+ }
+
+ auto const_value = materialized->ConstantValue();
+ auto value = const_value->ValueAs<AInt>();
+ if (value < 0) {
+ AddError("@binding value must be non-negative", attr->source);
+ return utils::Failure;
+ }
+ return static_cast<uint32_t>(value);
+}
+
+utils::Result<uint32_t> Resolver::GroupAttribute(const ast::GroupAttribute* attr) {
+ ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@group"};
+ TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
+
+ auto* materialized = Materialize(ValueExpression(attr->expr));
+ if (!materialized) {
+ return utils::Failure;
+ }
+ if (!materialized->Type()->IsAnyOf<type::I32, type::U32>()) {
+ AddError("@group must be an i32 or u32 value", attr->source);
+ return utils::Failure;
+ }
+
+ auto const_value = materialized->ConstantValue();
+ auto value = const_value->ValueAs<AInt>();
+ if (value < 0) {
+ AddError("@group value must be non-negative", attr->source);
+ return utils::Failure;
+ }
+ return static_cast<uint32_t>(value);
+}
+
+utils::Result<sem::WorkgroupSize> Resolver::WorkgroupAttribute(
+ const ast::WorkgroupAttribute* attr) {
+ // Set work-group size defaults.
+ sem::WorkgroupSize ws;
+ for (size_t i = 0; i < 3; i++) {
+ ws[i] = 1;
+ }
+
+ auto values = attr->Values();
+ utils::Vector<const sem::ValueExpression*, 3> args;
+ utils::Vector<const type::Type*, 3> arg_tys;
+
+ constexpr const char* kErrBadExpr =
+ "workgroup_size argument must be a constant or override-expression of type "
+ "abstract-integer, i32 or u32";
+
+ for (size_t i = 0; i < 3; i++) {
+ // Each argument to this attribute can either be a literal, an identifier for a
+ // module-scope constants, a const-expression, or nullptr if not specified.
+ auto* value = values[i];
+ if (!value) {
+ break;
+ }
+ const auto* expr = ValueExpression(value);
+ if (!expr) {
+ return utils::Failure;
+ }
+ auto* ty = expr->Type();
+ if (!ty->IsAnyOf<type::I32, type::U32, type::AbstractInt>()) {
+ AddError(kErrBadExpr, value->source);
+ return utils::Failure;
+ }
+
+ if (expr->Stage() != sem::EvaluationStage::kConstant &&
+ expr->Stage() != sem::EvaluationStage::kOverride) {
+ AddError(kErrBadExpr, value->source);
+ return utils::Failure;
+ }
+
+ args.Push(expr);
+ arg_tys.Push(ty);
+ }
+
+ auto* common_ty = type::Type::Common(arg_tys);
+ if (!common_ty) {
+ AddError("workgroup_size arguments must be of the same type, either i32 or u32",
+ attr->source);
+ return utils::Failure;
+ }
+
+ // If all arguments are abstract-integers, then materialize to i32.
+ if (common_ty->Is<type::AbstractInt>()) {
+ common_ty = builder_->create<type::I32>();
+ }
+
+ for (size_t i = 0; i < args.Length(); i++) {
+ auto* materialized = Materialize(args[i], common_ty);
+ if (!materialized) {
+ return utils::Failure;
+ }
+ if (auto* value = materialized->ConstantValue()) {
+ if (value->ValueAs<AInt>() < 1) {
+ AddError("workgroup_size argument must be at least 1", values[i]->source);
+ return utils::Failure;
+ }
+ ws[i] = value->ValueAs<u32>();
+ } else {
+ ws[i] = std::nullopt;
+ }
+ }
+
+ uint64_t total_size = static_cast<uint64_t>(ws[0].value_or(1));
+ for (size_t i = 1; i < 3; i++) {
+ total_size *= static_cast<uint64_t>(ws[i].value_or(1));
+ if (total_size > 0xffffffff) {
+ AddError("total workgroup grid size cannot exceed 0xffffffff", values[i]->source);
+ return utils::Failure;
+ }
+ }
+
+ return ws;
+}
+
+utils::Result<tint::builtin::BuiltinValue> Resolver::BuiltinAttribute(
+ const ast::BuiltinAttribute* attr) {
auto* builtin_expr = BuiltinValueExpression(attr->builtin);
if (!builtin_expr) {
- return false;
+ return utils::Failure;
}
// Apply the resolved tint::sem::BuiltinEnumExpression<tint::builtin::BuiltinValue> to the
// attribute.
builder_->Sem().Add(attr, builtin_expr);
+ return builtin_expr->Value();
+}
+
+bool Resolver::DiagnosticAttribute(const ast::DiagnosticAttribute* attr) {
+ return DiagnosticControl(attr->control);
+}
+
+bool Resolver::StageAttribute(const ast::StageAttribute*) {
return true;
}
-bool Resolver::InterpolateAttribute(const ast::InterpolateAttribute* attr) {
- if (!InterpolationType(attr->type)) {
- return false;
- }
- if (attr->sampling && !InterpolationSampling(attr->sampling)) {
- return false;
- }
+bool Resolver::MustUseAttribute(const ast::MustUseAttribute*) {
return true;
}
+bool Resolver::InvariantAttribute(const ast::InvariantAttribute*) {
+ return true;
+}
+
+bool Resolver::StrideAttribute(const ast::StrideAttribute*) {
+ return true;
+}
+
+utils::Result<builtin::Interpolation> Resolver::InterpolateAttribute(
+ const ast::InterpolateAttribute* attr) {
+ builtin::Interpolation out;
+ auto* type = InterpolationType(attr->type);
+ if (!type) {
+ return utils::Failure;
+ }
+ out.type = type->Value();
+ if (attr->sampling) {
+ auto* sampling = InterpolationSampling(attr->sampling);
+ if (!sampling) {
+ return utils::Failure;
+ }
+ out.sampling = sampling->Value();
+ }
+ return out;
+}
+
bool Resolver::InternalAttribute(const ast::InternalAttribute* attr) {
for (auto* dep : attr->dependencies) {
if (!Expression(dep)) {
@@ -3576,24 +3859,30 @@
return false;
}
- for (auto* attr : attributes) {
- Mark(attr);
- if (auto* sd = attr->As<ast::StrideAttribute>()) {
- // If the element type is not plain, then el_ty->Align() may be 0, in which case we
- // could get a DBZ in ArrayStrideAttribute(). In this case, validation will error
- // about the invalid array element type (which is tested later), so this is just a
- // seatbelt.
- if (IsPlain(el_ty)) {
- explicit_stride = sd->stride;
- if (!validator_.ArrayStrideAttribute(sd, el_ty->Size(), el_ty->Align())) {
- return false;
+ for (auto* attribute : attributes) {
+ Mark(attribute);
+ bool ok = Switch(
+ attribute, //
+ [&](const ast::StrideAttribute* attr) {
+ // If the element type is not plain, then el_ty->Align() may be 0, in which case we
+ // could get a DBZ in ArrayStrideAttribute(). In this case, validation will error
+ // about the invalid array element type (which is tested later), so this is just a
+ // seatbelt.
+ if (IsPlain(el_ty)) {
+ explicit_stride = attr->stride;
+ if (!validator_.ArrayStrideAttribute(attr, el_ty->Size(), el_ty->Align())) {
+ return false;
+ }
}
- }
- continue;
+ return true;
+ },
+ [&](Default) {
+ ErrorInvalidAttribute(attribute, "array types");
+ return false;
+ });
+ if (!ok) {
+ return false;
}
-
- AddError("attribute is not valid for array types", attr->source);
- return false;
}
return true;
@@ -3677,8 +3966,18 @@
if (!validator_.NoDuplicateAttributes(str->attributes)) {
return nullptr;
}
- for (auto* attr : str->attributes) {
- Mark(attr);
+
+ for (auto* attribute : str->attributes) {
+ Mark(attribute);
+ bool ok = Switch(
+ attribute, [&](const ast::InternalAttribute* attr) { return InternalAttribute(attr); },
+ [&](Default) {
+ ErrorInvalidAttribute(attribute, "struct declarations");
+ return false;
+ });
+ if (!ok) {
+ return nullptr;
+ }
}
utils::Vector<const sem::StructMember*, 8> sem_members;
@@ -3730,89 +4029,88 @@
bool has_offset_attr = false;
bool has_align_attr = false;
bool has_size_attr = false;
- std::optional<uint32_t> location;
- for (auto* attr : member->attributes) {
- if (!Attribute(attr)) {
- return nullptr;
- }
+ type::StructMemberAttributes attributes;
+ for (auto* attribute : member->attributes) {
+ Mark(attribute);
bool ok = Switch(
- attr, //
- [&](const ast::StructMemberOffsetAttribute* o) {
- // Offset attributes are not part of the WGSL spec, but are emitted
- // by the SPIR-V reader.
+ attribute, //
+ [&](const ast::StructMemberOffsetAttribute* attr) {
+ // Offset attributes are not part of the WGSL spec, but are emitted by the
+ // SPIR-V reader.
+
ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant,
"@offset value"};
TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
- auto* materialized = Materialize(ValueExpression(o->expr));
+ auto* materialized = Materialize(ValueExpression(attr->expr));
if (!materialized) {
return false;
}
auto const_value = materialized->ConstantValue();
if (!const_value) {
- AddError("@offset must be constant expression", o->expr->source);
+ AddError("@offset must be constant expression", attr->expr->source);
return false;
}
offset = const_value->ValueAs<uint64_t>();
if (offset < struct_size) {
- AddError("offsets must be in ascending order", o->source);
+ AddError("offsets must be in ascending order", attr->source);
return false;
}
has_offset_attr = true;
return true;
},
- [&](const ast::StructMemberAlignAttribute* a) {
+ [&](const ast::StructMemberAlignAttribute* attr) {
ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@align"};
TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
- auto* materialized = Materialize(ValueExpression(a->expr));
+ auto* materialized = Materialize(ValueExpression(attr->expr));
if (!materialized) {
return false;
}
if (!materialized->Type()->IsAnyOf<type::I32, type::U32>()) {
- AddError("@align must be an i32 or u32 value", a->source);
+ AddError("@align must be an i32 or u32 value", attr->source);
return false;
}
auto const_value = materialized->ConstantValue();
if (!const_value) {
- AddError("@align must be constant expression", a->source);
+ AddError("@align must be constant expression", attr->source);
return false;
}
auto value = const_value->ValueAs<AInt>();
if (value <= 0 || !utils::IsPowerOfTwo(value)) {
AddError("@align value must be a positive, power-of-two integer",
- a->source);
+ attr->source);
return false;
}
align = u32(value);
has_align_attr = true;
return true;
},
- [&](const ast::StructMemberSizeAttribute* s) {
+ [&](const ast::StructMemberSizeAttribute* attr) {
ExprEvalStageConstraint constraint{sem::EvaluationStage::kConstant, "@size"};
TINT_SCOPED_ASSIGNMENT(expr_eval_stage_constraint_, constraint);
- auto* materialized = Materialize(ValueExpression(s->expr));
+ auto* materialized = Materialize(ValueExpression(attr->expr));
if (!materialized) {
return false;
}
if (!materialized->Type()->IsAnyOf<type::U32, type::I32>()) {
- AddError("@size must be an i32 or u32 value", s->source);
+ AddError("@size must be an i32 or u32 value", attr->source);
return false;
}
auto const_value = materialized->ConstantValue();
if (!const_value) {
- AddError("@size must be constant expression", s->expr->source);
+ AddError("@size must be constant expression", attr->expr->source);
return false;
}
{
auto value = const_value->ValueAs<AInt>();
if (value <= 0) {
- AddError("@size must be a positive integer", s->source);
+ AddError("@size must be a positive integer", attr->source);
return false;
}
}
@@ -3820,24 +4118,56 @@
if (value < size) {
AddError("@size must be at least as big as the type's size (" +
std::to_string(size) + ")",
- s->source);
+ attr->source);
return false;
}
size = u32(value);
has_size_attr = true;
return true;
},
- [&](const ast::LocationAttribute* loc_attr) {
- auto value = LocationAttribute(loc_attr);
+ [&](const ast::LocationAttribute* attr) {
+ auto value = LocationAttribute(attr);
if (!value) {
return false;
}
- location = value.Get();
+ attributes.location = value.Get();
return true;
},
- [&](Default) {
- // The validator will check attributes can be applied to the struct member.
+ [&](const ast::BuiltinAttribute* attr) {
+ auto value = BuiltinAttribute(attr);
+ if (!value) {
+ return false;
+ }
+ attributes.builtin = value.Get();
return true;
+ },
+ [&](const ast::InterpolateAttribute* attr) {
+ auto value = InterpolateAttribute(attr);
+ if (!value) {
+ return false;
+ }
+ attributes.interpolation = value.Get();
+ return true;
+ },
+ [&](const ast::InvariantAttribute* attr) {
+ if (!InvariantAttribute(attr)) {
+ return false;
+ }
+ attributes.invariant = true;
+ return true;
+ },
+ [&](const ast::StrideAttribute* attr) {
+ if (validator_.IsValidationEnabled(
+ member->attributes, ast::DisabledValidation::kIgnoreStrideAttribute)) {
+ ErrorInvalidAttribute(attribute, "struct members");
+ return false;
+ }
+ return StrideAttribute(attr);
+ },
+ [&](const ast::InternalAttribute* attr) { return InternalAttribute(attr); },
+ [&](Default) {
+ ErrorInvalidAttribute(attribute, "struct members");
+ return false;
});
if (!ok) {
return nullptr;
@@ -3859,9 +4189,9 @@
}
auto* sem_member = builder_->create<sem::StructMember>(
- member, member->source, member->name->symbol, type,
- static_cast<uint32_t>(sem_members.Length()), static_cast<uint32_t>(offset),
- static_cast<uint32_t>(align), static_cast<uint32_t>(size), location);
+ member, member->name->symbol, type, static_cast<uint32_t>(sem_members.Length()),
+ static_cast<uint32_t>(offset), static_cast<uint32_t>(align),
+ static_cast<uint32_t>(size), attributes);
builder_->Sem().Add(member, sem_member);
sem_members.Push(sem_member);
@@ -3884,14 +4214,13 @@
}
auto* out = builder_->create<sem::Struct>(
- str, str->source, str->name->symbol, std::move(sem_members),
- static_cast<uint32_t>(struct_align), static_cast<uint32_t>(struct_size),
- static_cast<uint32_t>(size_no_padding));
+ str, str->name->symbol, std::move(sem_members), static_cast<uint32_t>(struct_align),
+ static_cast<uint32_t>(struct_size), static_cast<uint32_t>(size_no_padding));
for (size_t i = 0; i < sem_members.Length(); i++) {
auto* mem_type = sem_members[i]->Type();
if (mem_type->Is<type::Atomic>()) {
- atomic_composite_info_.Add(out, &sem_members[i]->Source());
+ atomic_composite_info_.Add(out, &sem_members[i]->Declaration()->source);
break;
} else {
if (auto found = atomic_composite_info_.Get(mem_type)) {
@@ -3999,14 +4328,16 @@
}
// Handle switch body attributes.
- for (auto* attr : stmt->body_attributes) {
- Mark(attr);
- if (auto* dc = attr->As<ast::DiagnosticAttribute>()) {
- if (!DiagnosticControl(dc->control)) {
+ for (auto* attribute : stmt->body_attributes) {
+ Mark(attribute);
+ bool ok = Switch(
+ attribute,
+ [&](const ast::DiagnosticAttribute* attr) { return DiagnosticAttribute(attr); },
+ [&](Default) {
+ ErrorInvalidAttribute(attribute, "switch body");
return false;
- }
- } else {
- AddError("attribute is not valid for switch body", attr->source);
+ });
+ if (!ok) {
return false;
}
}
@@ -4049,14 +4380,6 @@
return false;
}
- for (auto* attr : stmt->variable->attributes) {
- Mark(attr);
- if (!attr->Is<ast::InternalAttribute>()) {
- AddError("attributes are not valid on local variables", attr->source);
- return false;
- }
- }
-
current_compound_statement_->AddDecl(variable->As<sem::LocalVariable>());
if (auto* ctor = variable->Initializer()) {
@@ -4242,7 +4565,7 @@
utils::StringStream err;
err << "while analyzing structure member " << sem_.TypeNameOf(str) << "."
<< member->Name().Name();
- AddNote(err.str(), member->Source());
+ AddNote(err.str(), member->Declaration()->source);
return false;
}
}
@@ -4289,16 +4612,16 @@
// Helper to handle attributes that are supported on certain types of statement.
auto handle_attributes = [&](auto* stmt, sem::Statement* sem_stmt, const char* use) {
- for (auto* attr : stmt->attributes) {
- Mark(attr);
- if (auto* dc = attr->template As<ast::DiagnosticAttribute>()) {
- if (!DiagnosticControl(dc->control)) {
+ for (auto* attribute : stmt->attributes) {
+ Mark(attribute);
+ bool ok = Switch(
+ attribute, //
+ [&](const ast::DiagnosticAttribute* attr) { return DiagnosticAttribute(attr); },
+ [&](Default) {
+ ErrorInvalidAttribute(attribute, use);
return false;
- }
- } else {
- utils::StringStream ss;
- ss << "attribute is not valid for " << use;
- AddError(ss.str(), attr->source);
+ });
+ if (!ok) {
return false;
}
}
@@ -4401,6 +4724,10 @@
sem_.NoteDeclarationSource(resolved.Node());
}
+void Resolver::ErrorInvalidAttribute(const ast::Attribute* attr, std::string_view use) {
+ AddError("@" + attr->Name() + " is not valid for " + std::string(use), attr->source);
+}
+
void Resolver::AddError(const std::string& msg, const Source& source) const {
diagnostics_.add_error(diag::System::Resolver, msg, source);
}
diff --git a/src/tint/resolver/resolver.h b/src/tint/resolver/resolver.h
index edc088a..5d13d25 100644
--- a/src/tint/resolver/resolver.h
+++ b/src/tint/resolver/resolver.h
@@ -312,17 +312,50 @@
/// current_function_
bool WorkgroupSize(const ast::Function*);
- /// Resolves the attribute @p attr
- /// @returns true on success, false on failure
- bool Attribute(const ast::Attribute* attr);
-
/// Resolves the `@builtin` attribute @p attr
+ /// @returns the builtin value on success
+ utils::Result<tint::builtin::BuiltinValue> BuiltinAttribute(const ast::BuiltinAttribute* attr);
+
+ /// Resolves the `@location` attribute @p attr
+ /// @returns the location value on success.
+ utils::Result<uint32_t> LocationAttribute(const ast::LocationAttribute* attr);
+
+ /// Resolves the `@binding` attribute @p attr
+ /// @returns the binding value on success.
+ utils::Result<uint32_t> BindingAttribute(const ast::BindingAttribute* attr);
+
+ /// Resolves the `@group` attribute @p attr
+ /// @returns the group value on success.
+ utils::Result<uint32_t> GroupAttribute(const ast::GroupAttribute* attr);
+
+ /// Resolves the `@workgroup_size` attribute @p attr
+ /// @returns the workgroup size on success.
+ utils::Result<sem::WorkgroupSize> WorkgroupAttribute(const ast::WorkgroupAttribute* attr);
+
+ /// Resolves the `@diagnostic` attribute @p attr
/// @returns true on success, false on failure
- bool BuiltinAttribute(const ast::BuiltinAttribute* attr);
+ bool DiagnosticAttribute(const ast::DiagnosticAttribute* attr);
+
+ /// Resolves the stage attribute @p attr
+ /// @returns true on success, false on failure
+ bool StageAttribute(const ast::StageAttribute* attr);
+
+ /// Resolves the `@must_use` attribute @p attr
+ /// @returns true on success, false on failure
+ bool MustUseAttribute(const ast::MustUseAttribute* attr);
+
+ /// Resolves the `@invariant` attribute @p attr
+ /// @returns true on success, false on failure
+ bool InvariantAttribute(const ast::InvariantAttribute*);
+
+ /// Resolves the `@stride` attribute @p attr
+ /// @returns true on success, false on failure
+ bool StrideAttribute(const ast::StrideAttribute*);
/// Resolves the `@interpolate` attribute @p attr
/// @returns true on success, false on failure
- bool InterpolateAttribute(const ast::InterpolateAttribute* attr);
+ utils::Result<builtin::Interpolation> InterpolateAttribute(
+ const ast::InterpolateAttribute* attr);
/// Resolves the internal attribute @p attr
/// @returns true on success, false on failure
@@ -427,12 +460,11 @@
/// nullptr is returned.
/// @note the caller is expected to validate the parameter
/// @param param the AST parameter
+ /// @param func the AST function that owns the parameter
/// @param index the index of the parameter
- sem::Parameter* Parameter(const ast::Parameter* param, uint32_t index);
-
- /// @returns the location value for a `@location` attribute, validating the value's range and
- /// type.
- utils::Result<uint32_t> LocationAttribute(const ast::LocationAttribute* attr);
+ sem::Parameter* Parameter(const ast::Parameter* param,
+ const ast::Function* func,
+ uint32_t index);
/// Records the address space usage for the given type, and any transient
/// dependencies of the type. Validates that the type can be used for the
@@ -497,6 +529,11 @@
const ResolvedIdentifier& resolved,
std::string_view wanted);
+ /// Raises an error that the attribute is not valid for the given use.
+ /// @param attr the invalue attribute
+ /// @param use the thing that the attribute was applied to
+ void ErrorInvalidAttribute(const ast::Attribute* attr, std::string_view use);
+
/// Adds the given error message to the diagnostics
void AddError(const std::string& msg, const Source& source) const;
@@ -523,7 +560,7 @@
// It is a tuple of the structure type, number of arguments provided and earliest evaluation
// stage.
using StructConstructorSig =
- utils::UnorderedKeyWrapper<std::tuple<const sem::Struct*, size_t, sem::EvaluationStage>>;
+ utils::UnorderedKeyWrapper<std::tuple<const type::Struct*, size_t, sem::EvaluationStage>>;
/// ExprEvalStageConstraint describes a constraint on when expressions can be evaluated.
struct ExprEvalStageConstraint {
diff --git a/src/tint/resolver/resolver_test.cc b/src/tint/resolver/resolver_test.cc
index 5df2fae..dfe42ae 100644
--- a/src/tint/resolver/resolver_test.cc
+++ b/src/tint/resolver/resolver_test.cc
@@ -1265,7 +1265,7 @@
EXPECT_TRUE(sma->Member()->Type()->Is<type::F32>());
EXPECT_EQ(sma->Object()->Declaration(), mem->object);
EXPECT_EQ(sma->Member()->Index(), 1u);
- EXPECT_EQ(sma->Member()->Declaration()->name->symbol, Symbols().Get("second_member"));
+ EXPECT_EQ(sma->Member()->Name().Name(), "second_member");
}
TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
diff --git a/src/tint/resolver/struct_address_space_use_test.cc b/src/tint/resolver/struct_address_space_use_test.cc
index aeb5c31..e97a6ac 100644
--- a/src/tint/resolver/struct_address_space_use_test.cc
+++ b/src/tint/resolver/struct_address_space_use_test.cc
@@ -32,7 +32,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->AddressSpaceUsage().empty());
}
@@ -44,7 +44,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kUndefined));
}
@@ -56,7 +56,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kUndefined));
}
@@ -68,7 +68,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kPrivate));
}
@@ -80,7 +80,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kPrivate));
}
@@ -92,7 +92,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kPrivate));
}
@@ -104,7 +104,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kPrivate));
}
@@ -116,7 +116,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kFunction));
}
@@ -128,7 +128,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kFunction));
}
@@ -140,7 +140,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kFunction));
}
@@ -152,7 +152,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kFunction));
}
@@ -166,7 +166,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(builtin::AddressSpace::kUniform,
builtin::AddressSpace::kStorage,
diff --git a/src/tint/resolver/struct_pipeline_stage_use_test.cc b/src/tint/resolver/struct_pipeline_stage_use_test.cc
index 4707650..b4857f0 100644
--- a/src/tint/resolver/struct_pipeline_stage_use_test.cc
+++ b/src/tint/resolver/struct_pipeline_stage_use_test.cc
@@ -34,7 +34,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->PipelineStageUses().empty());
}
@@ -46,7 +46,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->PipelineStageUses().empty());
}
@@ -59,7 +59,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->PipelineStageUses().empty());
}
@@ -74,7 +74,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(type::PipelineStageUsage::kVertexInput));
@@ -90,7 +90,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(type::PipelineStageUsage::kVertexOutput));
@@ -104,7 +104,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(type::PipelineStageUsage::kFragmentInput));
@@ -118,7 +118,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(type::PipelineStageUsage::kFragmentOutput));
@@ -135,7 +135,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(type::PipelineStageUsage::kComputeInput));
@@ -154,7 +154,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(type::PipelineStageUsage::kVertexOutput,
@@ -170,7 +170,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(type::PipelineStageUsage::kFragmentInput));
@@ -184,10 +184,10 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
ASSERT_EQ(1u, sem->Members().Length());
- EXPECT_EQ(3u, sem->Members()[0]->Location());
+ EXPECT_EQ(3u, sem->Members()[0]->Attributes().location);
}
TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeViaAlias) {
@@ -200,7 +200,7 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(type::PipelineStageUsage::kFragmentOutput));
@@ -214,10 +214,10 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
- auto* sem = TypeOf(s)->As<sem::Struct>();
+ auto* sem = TypeOf(s)->As<type::Struct>();
ASSERT_NE(sem, nullptr);
ASSERT_EQ(1u, sem->Members().Length());
- EXPECT_EQ(3u, sem->Members()[0]->Location());
+ EXPECT_EQ(3u, sem->Members()[0]->Attributes().location);
}
} // namespace
diff --git a/src/tint/resolver/unresolved_identifier_test.cc b/src/tint/resolver/unresolved_identifier_test.cc
index e52b858..5802005 100644
--- a/src/tint/resolver/unresolved_identifier_test.cc
+++ b/src/tint/resolver/unresolved_identifier_test.cc
@@ -43,7 +43,7 @@
Func("f",
utils::Vector{
Param("p", ty.i32(), utils::Vector{Builtin(Expr(Source{{12, 34}}, "positon"))})},
- ty.void_(), utils::Empty);
+ ty.void_(), utils::Empty, utils::Vector{Stage(ast::PipelineStage::kVertex)});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: unresolved builtin value 'positon'
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
index 97eae88..63f2b4d 100644
--- a/src/tint/resolver/validator.cc
+++ b/src/tint/resolver/validator.cc
@@ -200,7 +200,7 @@
// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
bool Validator::IsPlain(const type::Type* type) const {
return type->is_scalar() ||
- type->IsAnyOf<type::Atomic, type::Vector, type::Matrix, type::Array, sem::Struct>();
+ type->IsAnyOf<type::Atomic, type::Vector, type::Matrix, type::Array, type::Struct>();
}
// https://gpuweb.github.io/gpuweb/wgsl/#fixed-footprint-types
@@ -214,7 +214,7 @@
return !arr->Count()->Is<type::RuntimeArrayCount>() &&
IsFixedFootprint(arr->ElemType());
},
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
for (auto* member : str->Members()) {
if (!IsFixedFootprint(member->Type())) {
return false;
@@ -235,7 +235,7 @@
[&](const type::Vector* vec) { return IsHostShareable(vec->type()); },
[&](const type::Matrix* mat) { return IsHostShareable(mat->type()); },
[&](const type::Array* arr) { return IsHostShareable(arr->ElemType()); },
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
for (auto* member : str->Members()) {
if (!IsHostShareable(member->Type())) {
return false;
@@ -397,11 +397,11 @@
auto is_uniform_struct_or_array = [address_space](const type::Type* ty) {
return address_space == builtin::AddressSpace::kUniform &&
- ty->IsAnyOf<type::Array, sem::Struct>();
+ ty->IsAnyOf<type::Array, type::Struct>();
};
auto is_uniform_struct = [address_space](const type::Type* ty) {
- return address_space == builtin::AddressSpace::kUniform && ty->Is<sem::Struct>();
+ return address_space == builtin::AddressSpace::kUniform && ty->Is<type::Struct>();
};
auto required_alignment_of = [&](const type::Type* ty) {
@@ -413,7 +413,7 @@
return required_align;
};
- auto member_name_of = [](const sem::StructMember* sm) { return sm->Name().Name(); };
+ auto member_name_of = [](const type::StructMember* sm) { return sm->Name().Name(); };
// Only validate the [type + address space] once
if (!valid_type_storage_layouts_.Add(TypeAndAddressSpace{store_ty, address_space})) {
@@ -445,7 +445,7 @@
// Recurse into the member type.
if (!AddressSpaceLayout(m->Type(), address_space, m->Declaration()->type->source)) {
- AddNote("see layout of struct:\n" + str->Layout(), str->Source());
+ AddNote("see layout of struct:\n" + str->Layout(), str->Declaration()->source);
note_usage();
return false;
}
@@ -461,13 +461,13 @@
"' is currently at offset " + std::to_string(m->Offset()) +
". Consider setting @align(" + std::to_string(required_align) +
") on this member",
- m->Source());
+ m->Declaration()->source);
- AddNote("see layout of struct:\n" + str->Layout(), str->Source());
+ AddNote("see layout of struct:\n" + str->Layout(), str->Declaration()->source);
if (auto* member_str = m->Type()->As<sem::Struct>()) {
AddNote("and layout of struct member:\n" + member_str->Layout(),
- member_str->Source());
+ member_str->Declaration()->source);
}
note_usage();
@@ -483,19 +483,19 @@
!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 "
- "member be a multiple of 16 bytes, but there are currently " +
+ "uniform storage requires that the number of bytes between the start of "
+ "the previous member of type struct and the current member be a multiple "
+ "of 16 bytes, but there are currently " +
std::to_string(prev_to_curr_offset) + " bytes between '" +
member_name_of(prev_member) + "' and '" + member_name_of(m) +
"'. Consider setting @align(16) on this member",
- m->Source());
+ m->Declaration()->source);
- AddNote("see layout of struct:\n" + str->Layout(), str->Source());
+ AddNote("see layout of struct:\n" + str->Layout(), str->Declaration()->source);
auto* prev_member_str = prev_member->Type()->As<sem::Struct>();
AddNote("and layout of previous member struct:\n" + prev_member_str->Layout(),
- prev_member_str->Source());
+ prev_member_str->Declaration()->source);
note_usage();
return false;
}
@@ -606,32 +606,10 @@
return false;
}
- for (auto* attr : decl->attributes) {
- bool is_shader_io_attribute =
- attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute,
- ast::InvariantAttribute, ast::LocationAttribute>();
- bool has_io_address_space = global->AddressSpace() == builtin::AddressSpace::kIn ||
- global->AddressSpace() == builtin::AddressSpace::kOut;
- if (!attr->IsAnyOf<ast::BindingAttribute, ast::GroupAttribute,
- ast::InternalAttribute>() &&
- (!is_shader_io_attribute || !has_io_address_space)) {
- AddError("attribute '" + attr->Name() + "' is not valid for module-scope 'var'",
- attr->source);
- return false;
- }
- }
-
return Var(global);
},
[&](const ast::Override*) { return Override(global, override_ids); },
- [&](const ast::Const*) {
- if (!decl->attributes.IsEmpty()) {
- AddError("attribute is not valid for module-scope 'const' declaration",
- decl->attributes[0]->source);
- return false;
- }
- return Const(global);
- },
+ [&](const ast::Const*) { return Const(global); },
[&](Default) {
TINT_ICE(Resolver, diagnostics_)
<< "Validator::GlobalVariable() called with a unknown variable type: "
@@ -773,9 +751,6 @@
ast::GetAttribute<ast::IdAttribute>((*var)->Declaration()->attributes)->source);
return false;
}
- } else {
- AddError("attribute is not valid for 'override' declaration", attr->source);
- return false;
}
}
@@ -792,28 +767,13 @@
return true;
}
-bool Validator::Parameter(const ast::Function* func, const sem::Variable* var) const {
+bool Validator::Parameter(const sem::Variable* var) const {
auto* decl = var->Declaration();
if (IsValidationDisabled(decl->attributes, ast::DisabledValidation::kFunctionParameter)) {
return true;
}
- for (auto* attr : decl->attributes) {
- if (!func->IsEntryPoint() && !attr->Is<ast::InternalAttribute>()) {
- AddError("attribute is not valid for non-entry point function parameters",
- attr->source);
- return false;
- }
- if (!attr->IsAnyOf<ast::BuiltinAttribute, ast::InvariantAttribute, ast::LocationAttribute,
- ast::InterpolateAttribute, ast::InternalAttribute>() &&
- (IsValidationEnabled(decl->attributes,
- ast::DisabledValidation::kEntryPointParameter))) {
- AddError("attribute is not valid for function parameters", attr->source);
- return false;
- }
- }
-
if (auto* ref = var->Type()->As<type::Pointer>()) {
if (IsValidationEnabled(decl->attributes, ast::DisabledValidation::kIgnoreAddressSpace)) {
bool ok = false;
@@ -1028,14 +988,7 @@
}
return true;
},
- [&](Default) {
- if (!attr->IsAnyOf<ast::DiagnosticAttribute, ast::StageAttribute,
- ast::InternalAttribute>()) {
- AddError("attribute is not valid for functions", attr->source);
- return false;
- }
- return true;
- });
+ [&](Default) { return true; });
if (!ok) {
return false;
}
@@ -1069,24 +1022,6 @@
TINT_ICE(Resolver, diagnostics_)
<< "Function " << decl->name->symbol.Name() << " has no body";
}
-
- for (auto* attr : decl->return_type_attributes) {
- if (!decl->IsEntryPoint()) {
- AddError("attribute is not valid for non-entry point function return types",
- attr->source);
- return false;
- }
- if (!attr->IsAnyOf<ast::BuiltinAttribute, ast::InternalAttribute,
- ast::LocationAttribute, ast::InterpolateAttribute,
- ast::InvariantAttribute>() &&
- (IsValidationEnabled(decl->attributes,
- ast::DisabledValidation::kEntryPointParameter) &&
- IsValidationEnabled(decl->attributes,
- ast::DisabledValidation::kFunctionParameter))) {
- AddError("attribute is not valid for entry point return types", attr->source);
- return false;
- }
- }
}
if (decl->IsEntryPoint()) {
@@ -1196,19 +1131,19 @@
if (is_invalid_compute_shader_attribute) {
std::string input_or_output =
param_or_ret == ParamOrRetType::kParameter ? "inputs" : "output";
- AddError("attribute is not valid for compute shader " + input_or_output,
+ AddError("@" + attr->Name() + " is not valid for compute shader " + input_or_output,
attr->source);
return false;
}
}
if (IsValidationEnabled(attrs, ast::DisabledValidation::kEntryPointParameter)) {
- if (is_struct_member && ty->Is<sem::Struct>()) {
+ if (is_struct_member && ty->Is<type::Struct>()) {
AddError("nested structures cannot be used for entry point IO", source);
return false;
}
- if (!ty->Is<sem::Struct>() && !pipeline_io_attribute) {
+ if (!ty->Is<type::Struct>() && !pipeline_io_attribute) {
std::string err = "missing entry point IO attribute";
if (!is_struct_member) {
err += (param_or_ret == ParamOrRetType::kParameter ? " on parameter"
@@ -1278,9 +1213,9 @@
if (auto* str = ty->As<sem::Struct>()) {
for (auto* member : str->Members()) {
if (!validate_entry_point_attributes_inner(
- member->Declaration()->attributes, member->Type(), member->Source(),
- param_or_ret,
- /*is_struct_member*/ true, member->Location())) {
+ member->Declaration()->attributes, member->Type(),
+ member->Declaration()->source, param_or_ret,
+ /*is_struct_member*/ true, member->Attributes().location)) {
AddNote("while analyzing entry point '" + decl->name->symbol.Name() + "'",
decl->source);
return false;
@@ -1828,7 +1763,7 @@
}
bool Validator::StructureInitializer(const ast::CallExpression* ctor,
- const sem::Struct* struct_type) const {
+ const type::Struct* struct_type) const {
if (!struct_type->IsConstructible()) {
AddError("structure constructor has non-constructible type", ctor->source);
return false;
@@ -2131,7 +2066,7 @@
bool Validator::Structure(const sem::Struct* str, ast::PipelineStage stage) const {
if (str->Members().IsEmpty()) {
- AddError("structures must have at least one member", str->Source());
+ AddError("structures must have at least one member", str->Declaration()->source);
return false;
}
@@ -2141,7 +2076,7 @@
if (r->Count()->Is<type::RuntimeArrayCount>()) {
if (member != str->Members().Back()) {
AddError("runtime arrays may only appear as the last member of a struct",
- member->Source());
+ member->Declaration()->source);
return false;
}
}
@@ -2153,7 +2088,7 @@
} else if (!IsFixedFootprint(member->Type())) {
AddError(
"a struct that contains a runtime array cannot be nested inside another struct",
- member->Source());
+ member->Declaration()->source);
return false;
}
@@ -2170,9 +2105,10 @@
},
[&](const ast::LocationAttribute* location) {
has_location = true;
- TINT_ASSERT(Resolver, member->Location().has_value());
- if (!LocationAttribute(location, member->Location().value(), member->Type(),
- locations, stage, member->Source())) {
+ TINT_ASSERT(Resolver, member->Attributes().location.has_value());
+ if (!LocationAttribute(location, member->Attributes().location.value(),
+ member->Type(), locations, stage,
+ member->Declaration()->source)) {
return false;
}
return true;
@@ -2205,24 +2141,7 @@
}
return true;
},
- [&](Default) {
- if (!attr->IsAnyOf<ast::BuiltinAttribute, //
- ast::InternalAttribute, //
- ast::InterpolateAttribute, //
- ast::InvariantAttribute, //
- ast::LocationAttribute, //
- ast::StructMemberOffsetAttribute, //
- ast::StructMemberAlignAttribute>()) {
- if (attr->Is<ast::StrideAttribute>() &&
- IsValidationDisabled(member->Declaration()->attributes,
- ast::DisabledValidation::kIgnoreStrideAttribute)) {
- return true;
- }
- AddError("attribute is not valid for structure members", attr->source);
- return false;
- }
- return true;
- });
+ [&](Default) { return true; });
if (!ok) {
return false;
}
@@ -2241,13 +2160,6 @@
}
}
- for (auto* attr : str->Declaration()->attributes) {
- if (!(attr->IsAnyOf<ast::InternalAttribute>())) {
- AddError("attribute is not valid for struct declarations", attr->source);
- return false;
- }
- }
-
return true;
}
@@ -2260,7 +2172,8 @@
const bool is_input) const {
std::string inputs_or_output = is_input ? "inputs" : "output";
if (stage == ast::PipelineStage::kCompute) {
- AddError("attribute is not valid for compute shader " + inputs_or_output, loc_attr->source);
+ AddError("@" + loc_attr->Name() + " is not valid for compute shader " + inputs_or_output,
+ loc_attr->source);
return false;
}
@@ -2652,8 +2565,8 @@
}
return true;
},
- [&](const sem::Struct*) { return check_sub_atomics(); }, //
- [&](const type::Array*) { return check_sub_atomics(); }, //
+ [&](const type::Struct*) { return check_sub_atomics(); }, //
+ [&](const type::Array*) { return check_sub_atomics(); }, //
[&](Default) { return true; });
}
diff --git a/src/tint/resolver/validator.h b/src/tint/resolver/validator.h
index e0e3051..999bc49 100644
--- a/src/tint/resolver/validator.h
+++ b/src/tint/resolver/validator.h
@@ -348,10 +348,9 @@
bool Matrix(const type::Type* el_ty, const Source& source) const;
/// Validates a function parameter
- /// @param func the function the variable is for
/// @param var the variable to validate
/// @returns true on success, false otherwise
- bool Parameter(const ast::Function* func, const sem::Variable* var) const;
+ bool Parameter(const sem::Variable* var) const;
/// Validates a return
/// @param ret the return statement to validate
@@ -398,7 +397,7 @@
/// @param struct_type the type of the structure
/// @returns true on success, false otherwise
bool StructureInitializer(const ast::CallExpression* ctor,
- const sem::Struct* struct_type) const;
+ const type::Struct* struct_type) const;
/// Validates a switch statement
/// @param s the switch to validate
diff --git a/src/tint/resolver/variable_test.cc b/src/tint/resolver/variable_test.cc
index 7af6027..5daee08 100644
--- a/src/tint/resolver/variable_test.cc
+++ b/src/tint/resolver/variable_test.cc
@@ -81,8 +81,8 @@
EXPECT_TRUE(TypeOf(f)->As<type::Reference>()->StoreType()->Is<type::F32>());
EXPECT_TRUE(TypeOf(h)->As<type::Reference>()->StoreType()->Is<type::F16>());
EXPECT_TRUE(TypeOf(b)->As<type::Reference>()->StoreType()->Is<type::Bool>());
- EXPECT_TRUE(TypeOf(s)->As<type::Reference>()->StoreType()->Is<sem::Struct>());
- EXPECT_TRUE(TypeOf(a)->As<type::Reference>()->StoreType()->Is<sem::Struct>());
+ EXPECT_TRUE(TypeOf(s)->As<type::Reference>()->StoreType()->Is<type::Struct>());
+ EXPECT_TRUE(TypeOf(a)->As<type::Reference>()->StoreType()->Is<type::Struct>());
EXPECT_EQ(Sem().Get(i)->Initializer(), nullptr);
EXPECT_EQ(Sem().Get(u)->Initializer(), nullptr);
@@ -161,8 +161,8 @@
EXPECT_TRUE(TypeOf(f)->As<type::Reference>()->StoreType()->Is<type::F32>());
EXPECT_TRUE(TypeOf(h)->As<type::Reference>()->StoreType()->Is<type::F16>());
EXPECT_TRUE(TypeOf(b)->As<type::Reference>()->StoreType()->Is<type::Bool>());
- EXPECT_TRUE(TypeOf(s)->As<type::Reference>()->StoreType()->Is<sem::Struct>());
- EXPECT_TRUE(TypeOf(a)->As<type::Reference>()->StoreType()->Is<sem::Struct>());
+ EXPECT_TRUE(TypeOf(s)->As<type::Reference>()->StoreType()->Is<type::Struct>());
+ EXPECT_TRUE(TypeOf(a)->As<type::Reference>()->StoreType()->Is<type::Struct>());
EXPECT_EQ(Sem().Get(i)->Initializer()->Declaration(), i_c);
EXPECT_EQ(Sem().Get(u)->Initializer()->Declaration(), u_c);
@@ -383,7 +383,7 @@
}
////////////////////////////////////////////////////////////////////////////////////////////////////
-// Function-scope 'let'
+// 'let' declaration
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_F(ResolverVariableTest, LocalLet) {
// struct S { i : i32; }
@@ -444,8 +444,8 @@
ASSERT_TRUE(TypeOf(f)->Is<type::F32>());
ASSERT_TRUE(TypeOf(h)->Is<type::F16>());
ASSERT_TRUE(TypeOf(b)->Is<type::Bool>());
- ASSERT_TRUE(TypeOf(s)->Is<sem::Struct>());
- ASSERT_TRUE(TypeOf(a)->Is<sem::Struct>());
+ ASSERT_TRUE(TypeOf(s)->Is<type::Struct>());
+ ASSERT_TRUE(TypeOf(a)->Is<type::Struct>());
ASSERT_TRUE(TypeOf(p)->Is<type::Pointer>());
ASSERT_TRUE(TypeOf(p)->As<type::Pointer>()->StoreType()->Is<type::I32>());
@@ -924,7 +924,7 @@
ASSERT_TRUE(TypeOf(c_vu32)->Is<type::Vector>());
ASSERT_TRUE(TypeOf(c_vf32)->Is<type::Vector>());
ASSERT_TRUE(TypeOf(c_mf32)->Is<type::Matrix>());
- ASSERT_TRUE(TypeOf(c_s)->Is<sem::Struct>());
+ ASSERT_TRUE(TypeOf(c_s)->Is<type::Struct>());
EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue()->AllZero());
EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue()->AllZero());
@@ -987,7 +987,7 @@
ASSERT_TRUE(TypeOf(c_vaf)->Is<type::Vector>());
ASSERT_TRUE(TypeOf(c_mf32)->Is<type::Matrix>());
ASSERT_TRUE(TypeOf(c_maf32)->Is<type::Matrix>());
- ASSERT_TRUE(TypeOf(c_s)->Is<sem::Struct>());
+ ASSERT_TRUE(TypeOf(c_s)->Is<type::Struct>());
EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue()->AllZero());
EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue()->AllZero());
diff --git a/src/tint/sem/member_accessor_expression.cc b/src/tint/sem/member_accessor_expression.cc
index 9ad15f0..573f670 100644
--- a/src/tint/sem/member_accessor_expression.cc
+++ b/src/tint/sem/member_accessor_expression.cc
@@ -41,7 +41,7 @@
const Statement* statement,
const constant::Value* constant,
const ValueExpression* object,
- const StructMember* member,
+ const type::StructMember* member,
bool has_side_effects,
const Variable* root_ident /* = nullptr */)
: Base(declaration,
diff --git a/src/tint/sem/member_accessor_expression.h b/src/tint/sem/member_accessor_expression.h
index cea9f2d..b2abdec 100644
--- a/src/tint/sem/member_accessor_expression.h
+++ b/src/tint/sem/member_accessor_expression.h
@@ -22,9 +22,9 @@
namespace tint::ast {
class MemberAccessorExpression;
} // namespace tint::ast
-namespace tint::sem {
+namespace tint::type {
class StructMember;
-} // namespace tint::sem
+} // namespace tint::type
namespace tint::sem {
@@ -81,7 +81,7 @@
const Statement* statement,
const constant::Value* constant,
const ValueExpression* object,
- const StructMember* member,
+ const type::StructMember* member,
bool has_side_effects,
const Variable* root_ident = nullptr);
@@ -89,10 +89,10 @@
~StructMemberAccess() override;
/// @returns the structure member
- StructMember const* Member() const { return member_; }
+ type::StructMember const* Member() const { return member_; }
private:
- StructMember const* const member_;
+ type::StructMember const* const member_;
};
/// Swizzle holds the semantic information for a ast::MemberAccessorExpression
diff --git a/src/tint/sem/struct.cc b/src/tint/sem/struct.cc
index 413231a..e6c0e73 100644
--- a/src/tint/sem/struct.cc
+++ b/src/tint/sem/struct.cc
@@ -22,26 +22,28 @@
namespace tint::sem {
Struct::Struct(const ast::Struct* declaration,
- tint::Source source,
Symbol name,
utils::VectorRef<const StructMember*> members,
uint32_t align,
uint32_t size,
uint32_t size_no_padding)
- : Base(source, name, members, align, size, size_no_padding), declaration_(declaration) {}
+ : Base(name, members, align, size, size_no_padding), declaration_(declaration) {
+ TINT_ASSERT(Semantic, declaration != nullptr);
+}
Struct::~Struct() = default;
StructMember::StructMember(const ast::StructMember* declaration,
- tint::Source source,
Symbol name,
const type::Type* type,
uint32_t index,
uint32_t offset,
uint32_t align,
uint32_t size,
- std::optional<uint32_t> location)
- : Base(source, name, type, index, offset, align, size, location), declaration_(declaration) {}
+ const type::StructMemberAttributes& attributes)
+ : Base(name, type, index, offset, align, size, attributes), declaration_(declaration) {
+ TINT_ASSERT(Semantic, declaration != nullptr);
+}
StructMember::~StructMember() = default;
diff --git a/src/tint/sem/struct.h b/src/tint/sem/struct.h
index 2b437af..fd59dcd 100644
--- a/src/tint/sem/struct.h
+++ b/src/tint/sem/struct.h
@@ -38,19 +38,17 @@
namespace tint::sem {
/// Struct holds the semantic information for structures.
+/// Unlike type::Struct, sem::Struct has an AST declaration node.
class Struct final : public utils::Castable<Struct, type::Struct> {
public:
/// Constructor
/// @param declaration the AST structure declaration
- /// @param source the source of the structure
/// @param name the name of the structure
/// @param members the structure members
/// @param align the byte alignment of the structure
/// @param size the byte size of the structure
- /// @param size_no_padding size of the members without the end of structure
- /// alignment padding
+ /// @param size_no_padding size of the members without the end of structure alignment padding
Struct(const ast::Struct* declaration,
- tint::Source source,
Symbol name,
utils::VectorRef<const StructMember*> members,
uint32_t align,
@@ -73,27 +71,26 @@
};
/// StructMember holds the semantic information for structure members.
+/// Unlike type::StructMember, sem::StructMember has an AST declaration node.
class StructMember final : public utils::Castable<StructMember, type::StructMember> {
public:
/// Constructor
/// @param declaration the AST declaration node
- /// @param source the source of the struct member
/// @param name the name of the structure member
/// @param type the type of the member
/// @param index the index of the member in the structure
/// @param offset the byte offset from the base of the structure
/// @param align the byte alignment of the member
/// @param size the byte size of the member
- /// @param location the location attribute, if present
+ /// @param attributes the optional attributes
StructMember(const ast::StructMember* declaration,
- tint::Source source,
Symbol name,
const type::Type* type,
uint32_t index,
uint32_t offset,
uint32_t align,
uint32_t size,
- std::optional<uint32_t> location);
+ const type::StructMemberAttributes& attributes);
/// Destructor
~StructMember() override;
diff --git a/src/tint/sem/struct_test.cc b/src/tint/sem/struct_test.cc
index 424930d..c267234 100644
--- a/src/tint/sem/struct_test.cc
+++ b/src/tint/sem/struct_test.cc
@@ -26,8 +26,8 @@
auto name = Sym("S");
auto* impl = create<ast::Struct>(Ident(name), utils::Empty, utils::Empty);
auto* ptr = impl;
- auto* s = create<sem::Struct>(impl, impl->source, impl->name->symbol, utils::Empty,
- 4u /* align */, 8u /* size */, 16u /* size_no_padding */);
+ auto* s = create<sem::Struct>(impl, impl->name->symbol, utils::Empty, 4u /* align */,
+ 8u /* size */, 16u /* size_no_padding */);
EXPECT_EQ(s->Declaration(), ptr);
EXPECT_EQ(s->Align(), 4u);
EXPECT_EQ(s->Size(), 8u);
@@ -36,11 +36,11 @@
TEST_F(SemStructTest, Equals) {
auto* a_impl = create<ast::Struct>(Ident("a"), utils::Empty, utils::Empty);
- auto* a = create<sem::Struct>(a_impl, a_impl->source, a_impl->name->symbol, utils::Empty,
- 4u /* align */, 4u /* size */, 4u /* size_no_padding */);
+ auto* a = create<sem::Struct>(a_impl, a_impl->name->symbol, utils::Empty, 4u /* align */,
+ 4u /* size */, 4u /* size_no_padding */);
auto* b_impl = create<ast::Struct>(Ident("b"), utils::Empty, utils::Empty);
- auto* b = create<sem::Struct>(b_impl, b_impl->source, b_impl->name->symbol, utils::Empty,
- 4u /* align */, 4u /* size */, 4u /* size_no_padding */);
+ auto* b = create<sem::Struct>(b_impl, b_impl->name->symbol, utils::Empty, 4u /* align */,
+ 4u /* size */, 4u /* size_no_padding */);
EXPECT_TRUE(a->Equals(*a));
EXPECT_FALSE(a->Equals(*b));
@@ -50,8 +50,8 @@
TEST_F(SemStructTest, FriendlyName) {
auto name = Sym("my_struct");
auto* impl = create<ast::Struct>(Ident(name), utils::Empty, utils::Empty);
- auto* s = create<sem::Struct>(impl, impl->source, impl->name->symbol, utils::Empty,
- 4u /* align */, 4u /* size */, 4u /* size_no_padding */);
+ auto* s = create<sem::Struct>(impl, impl->name->symbol, utils::Empty, 4u /* align */,
+ 4u /* size */, 4u /* size_no_padding */);
EXPECT_EQ(s->FriendlyName(), "my_struct");
}
diff --git a/src/tint/templates/enums.tmpl.inc b/src/tint/templates/enums.tmpl.inc
index ad46942..adc06e0 100644
--- a/src/tint/templates/enums.tmpl.inc
+++ b/src/tint/templates/enums.tmpl.inc
@@ -191,7 +191,7 @@
benchmark::DoNotOptimize(result);
}
}
-}
+} // NOLINT(readability/fn_size)
BENCHMARK({{$enum}}Parser);
{{- end -}}
diff --git a/src/tint/transform/array_length_from_uniform.cc b/src/tint/transform/array_length_from_uniform.cc
index 98d4a6b..1c88483 100644
--- a/src/tint/transform/array_length_from_uniform.cc
+++ b/src/tint/transform/array_length_from_uniform.cc
@@ -147,7 +147,7 @@
const ast::Expression* total_size = total_storage_buffer_size;
auto* storage_buffer_type = storage_buffer_sem->Type()->UnwrapRef();
const type::Array* array_type = nullptr;
- if (auto* str = storage_buffer_type->As<sem::Struct>()) {
+ if (auto* str = storage_buffer_type->As<type::Struct>()) {
// The variable is a struct, so subtract the byte offset of the array
// member.
auto* array_member_sem = str->Members().Back();
diff --git a/src/tint/transform/calculate_array_length.cc b/src/tint/transform/calculate_array_length.cc
index 743a992..4a3598d 100644
--- a/src/tint/transform/calculate_array_length.cc
+++ b/src/tint/transform/calculate_array_length.cc
@@ -204,7 +204,7 @@
const type::Array* array_type = Switch(
storage_buffer_type->StoreType(),
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
// The variable is a struct, so subtract the byte offset of
// the array member.
auto* array_member_sem = str->Members().Back();
diff --git a/src/tint/transform/canonicalize_entry_point_io.cc b/src/tint/transform/canonicalize_entry_point_io.cc
index 840f8ff..9e9368a 100644
--- a/src/tint/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/transform/canonicalize_entry_point_io.cc
@@ -371,7 +371,7 @@
// list to pass them through to the inner function.
utils::Vector<const ast::Expression*, 8> inner_struct_values;
for (auto* member : str->Members()) {
- if (TINT_UNLIKELY(member->Type()->Is<sem::Struct>())) {
+ if (TINT_UNLIKELY(member->Type()->Is<type::Struct>())) {
TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
continue;
}
@@ -380,8 +380,8 @@
auto attributes =
CloneShaderIOAttributes(member->Declaration()->attributes, do_interpolate);
- auto* input_expr =
- AddInput(name, member->Type(), member->Location(), std::move(attributes));
+ auto* input_expr = AddInput(name, member->Type(), member->Attributes().location,
+ std::move(attributes));
inner_struct_values.Push(input_expr);
}
@@ -400,7 +400,7 @@
bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kFragment;
if (auto* str = inner_ret_type->As<sem::Struct>()) {
for (auto* member : str->Members()) {
- if (TINT_UNLIKELY(member->Type()->Is<sem::Struct>())) {
+ if (TINT_UNLIKELY(member->Type()->Is<type::Struct>())) {
TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
continue;
}
@@ -410,8 +410,8 @@
CloneShaderIOAttributes(member->Declaration()->attributes, do_interpolate);
// Extract the original structure member.
- AddOutput(name, member->Type(), member->Location(), std::move(attributes),
- ctx.dst->MemberAccessor(original_result, name));
+ AddOutput(name, member->Type(), member->Attributes().location,
+ std::move(attributes), ctx.dst->MemberAccessor(original_result, name));
}
} else if (!inner_ret_type->Is<type::Void>()) {
auto attributes =
@@ -639,7 +639,7 @@
// aggregated into a single structure.
if (!func_sem->Parameters().IsEmpty()) {
for (auto* param : func_sem->Parameters()) {
- if (param->Type()->Is<sem::Struct>()) {
+ if (param->Type()->Is<type::Struct>()) {
ProcessStructParameter(param);
} else {
ProcessNonStructParameter(param);
diff --git a/src/tint/transform/decompose_memory_access.cc b/src/tint/transform/decompose_memory_access.cc
index 564451c..181518d 100644
--- a/src/tint/transform/decompose_memory_access.cc
+++ b/src/tint/transform/decompose_memory_access.cc
@@ -522,7 +522,7 @@
auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
values.Push(b.Call(load, offset));
}
- } else if (auto* str = el_ty->As<sem::Struct>()) {
+ } else if (auto* str = el_ty->As<type::Struct>()) {
for (auto* member : str->Members()) {
auto* offset = b.Add("offset", u32(member->Offset()));
Symbol load = LoadFunc(member->Type()->UnwrapRef(), address_space, buffer);
@@ -607,7 +607,7 @@
}
return stmts;
},
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
utils::Vector<const ast::Statement*, 8> stmts;
for (auto* member : str->Members()) {
auto* offset = b.Add("offset", u32(member->Offset()));
@@ -660,8 +660,8 @@
// For intrinsics that return a struct, there is no AST node for it, so create one now.
if (intrinsic->Type() == builtin::Function::kAtomicCompareExchangeWeak) {
- auto* str = intrinsic->ReturnType()->As<sem::Struct>();
- TINT_ASSERT(Transform, str && str->Declaration() == nullptr);
+ auto* str = intrinsic->ReturnType()->As<type::Struct>();
+ TINT_ASSERT(Transform, str);
utils::Vector<const ast::StructMember*, 8> ast_members;
ast_members.Reserve(str->Members().Length());
@@ -869,7 +869,7 @@
}
} else {
if (auto access = state.TakeAccess(accessor->object)) {
- auto* str_ty = access.type->As<sem::Struct>();
+ auto* str_ty = access.type->As<type::Struct>();
auto* member = str_ty->FindMember(accessor->member->symbol);
auto offset = member->Offset();
state.AddAccess(accessor, {
diff --git a/src/tint/transform/decompose_strided_matrix.cc b/src/tint/transform/decompose_strided_matrix.cc
index dd03dc2..6443095 100644
--- a/src/tint/transform/decompose_strided_matrix.cc
+++ b/src/tint/transform/decompose_strided_matrix.cc
@@ -70,7 +70,7 @@
// Scan the program for all storage and uniform structure matrix members with
// a custom stride attribute. Replace these matrices with an equivalent array,
// and populate the `decomposed` map with the members that have been replaced.
- utils::Hashmap<const ast::StructMember*, MatrixInfo, 8> decomposed;
+ utils::Hashmap<const type::StructMember*, MatrixInfo, 8> decomposed;
for (auto* node : src->ASTNodes().Objects()) {
if (auto* str = node->As<ast::Struct>()) {
auto* str_ty = src->Sem().Get(str);
@@ -98,7 +98,7 @@
auto* replacement =
b.Member(member->Offset(), ctx.Clone(member->Name()), info.array(ctx.dst));
ctx.Replace(member->Declaration(), replacement);
- decomposed.Add(member->Declaration(), info);
+ decomposed.Add(member, info);
}
}
}
@@ -114,7 +114,7 @@
ctx.ReplaceAll(
[&](const ast::IndexAccessorExpression* expr) -> const ast::IndexAccessorExpression* {
if (auto* access = src->Sem().Get<sem::StructMemberAccess>(expr->object)) {
- if (decomposed.Contains(access->Member()->Declaration())) {
+ if (decomposed.Contains(access->Member())) {
auto* obj = ctx.CloneWithoutTransform(expr->object);
auto* idx = ctx.Clone(expr->index);
return b.IndexAccessor(obj, idx);
@@ -131,7 +131,7 @@
std::unordered_map<MatrixInfo, Symbol, MatrixInfo::Hasher> mat_to_arr;
ctx.ReplaceAll([&](const ast::AssignmentStatement* stmt) -> const ast::Statement* {
if (auto* access = src->Sem().Get<sem::StructMemberAccess>(stmt->lhs)) {
- if (auto info = decomposed.Find(access->Member()->Declaration())) {
+ if (auto info = decomposed.Find(access->Member())) {
auto fn = utils::GetOrCreate(mat_to_arr, *info, [&] {
auto name =
b.Symbols().New("mat" + std::to_string(info->matrix->columns()) + "x" +
@@ -170,7 +170,7 @@
std::unordered_map<MatrixInfo, Symbol, MatrixInfo::Hasher> arr_to_mat;
ctx.ReplaceAll([&](const ast::MemberAccessorExpression* expr) -> const ast::Expression* {
if (auto* access = src->Sem().Get(expr)->UnwrapLoad()->As<sem::StructMemberAccess>()) {
- if (auto info = decomposed.Find(access->Member()->Declaration())) {
+ if (auto info = decomposed.Find(access->Member())) {
auto fn = utils::GetOrCreate(arr_to_mat, *info, [&] {
auto name =
b.Symbols().New("arr_to_mat" + std::to_string(info->matrix->columns()) +
diff --git a/src/tint/transform/demote_to_helper.cc b/src/tint/transform/demote_to_helper.cc
index c853ef0..46e9203 100644
--- a/src/tint/transform/demote_to_helper.cc
+++ b/src/tint/transform/demote_to_helper.cc
@@ -186,7 +186,7 @@
// original member values over to it.
// Declare a struct to hold the result values.
- auto* result_struct = sem_call->Type()->As<sem::Struct>();
+ auto* result_struct = sem_call->Type()->As<type::Struct>();
auto* atomic_ty = result_struct->Members()[0]->Type();
result_ty = b.ty(
utils::GetOrCreate(atomic_cmpxchg_result_types, atomic_ty, [&]() {
diff --git a/src/tint/transform/first_index_offset.cc b/src/tint/transform/first_index_offset.cc
index 59588e2..c8d4a26 100644
--- a/src/tint/transform/first_index_offset.cc
+++ b/src/tint/transform/first_index_offset.cc
@@ -79,7 +79,7 @@
// Map of builtin usages
std::unordered_map<const sem::Variable*, const char*> builtin_vars;
- std::unordered_map<const sem::StructMember*, const char*> builtin_members;
+ std::unordered_map<const type::StructMember*, const char*> builtin_members;
bool has_vertex_or_instance_index = false;
diff --git a/src/tint/transform/localize_struct_array_assignment.cc b/src/tint/transform/localize_struct_array_assignment.cc
index f5f8744..775da6a 100644
--- a/src/tint/transform/localize_struct_array_assignment.cc
+++ b/src/tint/transform/localize_struct_array_assignment.cc
@@ -60,7 +60,7 @@
continue;
}
auto og = GetOriginatingTypeAndAddressSpace(assign_stmt);
- if (!(og.first->Is<sem::Struct>() &&
+ if (!(og.first->Is<type::Struct>() &&
(og.second == builtin::AddressSpace::kFunction ||
og.second == builtin::AddressSpace::kPrivate))) {
continue;
diff --git a/src/tint/transform/module_scope_var_to_entry_point_param.cc b/src/tint/transform/module_scope_var_to_entry_point_param.cc
index a394ef6..14e16bb 100644
--- a/src/tint/transform/module_scope_var_to_entry_point_param.cc
+++ b/src/tint/transform/module_scope_var_to_entry_point_param.cc
@@ -54,7 +54,7 @@
return true;
} else if (auto* ary = type->As<type::Array>()) {
return ContainsMatrix(ary->ElemType());
- } else if (auto* str = type->As<sem::Struct>()) {
+ } else if (auto* str = type->As<type::Struct>()) {
for (auto* member : str->Members()) {
if (ContainsMatrix(member->Type())) {
return true;
@@ -85,11 +85,6 @@
return;
}
- if (!str->Declaration()) {
- // The struct is a built-in structure that we do not need to declare.
- return;
- }
-
// Recurse into members.
for (auto* member : str->Members()) {
CloneStructTypes(member->Type());
diff --git a/src/tint/transform/num_workgroups_from_uniform.cc b/src/tint/transform/num_workgroups_from_uniform.cc
index 18889f4..60e9a72 100644
--- a/src/tint/transform/num_workgroups_from_uniform.cc
+++ b/src/tint/transform/num_workgroups_from_uniform.cc
@@ -99,10 +99,7 @@
}
for (auto* member : str->Members()) {
- auto* builtin =
- ast::GetAttribute<ast::BuiltinAttribute>(member->Declaration()->attributes);
- if (!builtin ||
- src->Sem().Get(builtin)->Value() != builtin::BuiltinValue::kNumWorkgroups) {
+ if (member->Attributes().builtin != builtin::BuiltinValue::kNumWorkgroups) {
continue;
}
diff --git a/src/tint/transform/packed_vec3.cc b/src/tint/transform/packed_vec3.cc
index 9ef78a6..16d8af4 100644
--- a/src/tint/transform/packed_vec3.cc
+++ b/src/tint/transform/packed_vec3.cc
@@ -159,7 +159,7 @@
}
return {};
},
- [&](const sem::Struct* str) -> ast::Type {
+ [&](const type::Struct* str) -> ast::Type {
if (ContainsVec3(str)) {
auto name = rewritten_structs.GetOrCreate(str, [&]() {
utils::Vector<const ast::StructMember*, 4> members;
@@ -170,12 +170,14 @@
// 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;
+ if (auto* sem_mem = member->As<sem::StructMember>()) {
+ for (auto* attr : sem_mem->Declaration()->attributes) {
+ if (attr->IsAnyOf<ast::StructMemberAlignAttribute,
+ ast::StructMemberOffsetAttribute>()) {
+ needs_align = false;
+ }
+ attributes.Push(ctx.Clone(attr));
}
- 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
@@ -187,12 +189,17 @@
std::move(attributes)));
} else {
// No vec3s, just clone the member as is.
- members.Push(ctx.Clone(member->Declaration()));
+ if (auto* sem_mem = member->As<sem::StructMember>()) {
+ members.Push(ctx.Clone(sem_mem->Declaration()));
+ } else {
+ members.Push(b.Member(ctx.Clone(member->Name()), new_type,
+ utils::Empty));
+ }
}
}
// Create the new structure.
- auto struct_name = b.Symbols().New(str->Declaration()->name->symbol.Name() +
- "_tint_packed_vec3");
+ auto struct_name =
+ b.Symbols().New(str->Name().Name() + "_tint_packed_vec3");
b.Structure(struct_name, std::move(members));
return struct_name;
});
@@ -246,7 +253,7 @@
[&](const type::Matrix* mat) {
copy_array_elements(mat->columns(), mat->ColumnType());
},
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
// Copy the struct members over one at a time, packing/unpacking as necessary.
for (auto* member : str->Members()) {
const ast::Expression* element =
diff --git a/src/tint/transform/packed_vec3_test.cc b/src/tint/transform/packed_vec3_test.cc
index dbc28f7..a7f829f 100644
--- a/src/tint/transform/packed_vec3_test.cc
+++ b/src/tint/transform/packed_vec3_test.cc
@@ -4328,7 +4328,7 @@
// 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>();
+ auto* str_ty = sem_str->Type()->UnwrapRef()->As<type::Struct>();
ASSERT_NE(str_ty, nullptr);
ASSERT_EQ(str_ty->Members().Length(), 2u);
EXPECT_EQ(str_ty->Members()[0]->Align(), 16u);
diff --git a/src/tint/transform/pad_structs.cc b/src/tint/transform/pad_structs.cc
index 90f2e59..cfa8c90 100644
--- a/src/tint/transform/pad_structs.cc
+++ b/src/tint/transform/pad_structs.cc
@@ -84,7 +84,7 @@
new_members.Push(b.Member(name, type));
uint32_t size = ty->Size();
- if (ty->Is<sem::Struct>() && str->UsedAs(builtin::AddressSpace::kUniform)) {
+ if (ty->Is<type::Struct>() && str->UsedAs(builtin::AddressSpace::kUniform)) {
// std140 structs should be padded out to 16 bytes.
size = utils::RoundUp(16u, size);
} else if (auto* array_ty = ty->As<type::Array>()) {
diff --git a/src/tint/transform/preserve_padding.cc b/src/tint/transform/preserve_padding.cc
index 6df1a1c..0e4daee 100644
--- a/src/tint/transform/preserve_padding.cc
+++ b/src/tint/transform/preserve_padding.cc
@@ -160,12 +160,12 @@
return body;
});
},
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
// Call a helper function that assigns each member separately.
return call_helper([&]() {
utils::Vector<const ast::Statement*, 8> body;
for (auto member : str->Members()) {
- auto name = member->Declaration()->name->symbol.Name();
+ auto name = member->Name().Name();
body.Push(MakeAssignment(member->Type(),
b.MemberAccessor(b.Deref(kDestParamName), name),
b.MemberAccessor(kValueParamName, name)));
@@ -199,7 +199,7 @@
}
return HasPadding(col_ty);
},
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
uint32_t current_offset = 0;
for (auto* member : str->Members()) {
if (member->Offset() > current_offset) {
diff --git a/src/tint/transform/renamer.cc b/src/tint/transform/renamer.cc
index 14b8c12..92589b1 100644
--- a/src/tint/transform/renamer.cc
+++ b/src/tint/transform/renamer.cc
@@ -1281,8 +1281,8 @@
if (sem->Is<sem::Swizzle>()) {
preserved_identifiers.Add(accessor->member);
} else if (auto* str_expr = src->Sem().GetVal(accessor->object)) {
- if (auto* ty = str_expr->Type()->UnwrapRef()->As<sem::Struct>()) {
- if (ty->Declaration() == nullptr) { // Builtin structure
+ if (auto* ty = str_expr->Type()->UnwrapRef()->As<type::Struct>()) {
+ if (!ty->Is<sem::Struct>()) { // Builtin structure
preserved_identifiers.Add(accessor->member);
}
}
diff --git a/src/tint/transform/spirv_atomic.cc b/src/tint/transform/spirv_atomic.cc
index 82b955c..d58d58b 100644
--- a/src/tint/transform/spirv_atomic.cc
+++ b/src/tint/transform/spirv_atomic.cc
@@ -53,7 +53,7 @@
ProgramBuilder b;
/// The clone context
CloneContext ctx = {&b, src, /* auto_clone_symbols */ true};
- std::unordered_map<const ast::Struct*, ForkedStruct> forked_structs;
+ std::unordered_map<const type::Struct*, ForkedStruct> forked_structs;
std::unordered_set<const sem::Variable*> atomic_variables;
utils::UniqueVector<const sem::ValueExpression*, 8> atomic_expressions;
@@ -123,7 +123,8 @@
if (!forked_structs.empty()) {
ctx.ReplaceAll([&](const ast::Struct* str) {
// Is `str` a structure we need to fork?
- if (auto it = forked_structs.find(str); it != forked_structs.end()) {
+ auto* str_ty = ctx.src->Sem().Get(str);
+ if (auto it = forked_structs.find(str_ty); it != forked_structs.end()) {
const auto& forked = it->second;
// Re-create the structure swapping in the atomic-flavoured members
@@ -154,10 +155,10 @@
}
private:
- ForkedStruct& Fork(const ast::Struct* str) {
+ ForkedStruct& Fork(const type::Struct* str) {
auto& forked = forked_structs[str];
if (!forked.name.IsValid()) {
- forked.name = b.Symbols().New(str->name->symbol.Name() + "_atomic");
+ forked.name = b.Symbols().New(str->Name().Name() + "_atomic");
}
return forked;
}
@@ -179,7 +180,7 @@
// Fork the struct (the first time) and mark member(s) that need to be made
// atomic.
auto* member = access->Member();
- Fork(member->Struct()->Declaration()).atomic_members.emplace(member->Index());
+ Fork(member->Struct()).atomic_members.emplace(member->Index());
atomic_expressions.Add(access->Object());
},
[&](const sem::IndexAccessorExpression* index) {
@@ -198,7 +199,7 @@
ty, //
[&](const type::I32*) { return b.ty.atomic(CreateASTTypeFor(ctx, ty)); },
[&](const type::U32*) { return b.ty.atomic(CreateASTTypeFor(ctx, ty)); },
- [&](const sem::Struct* str) { return b.ty(Fork(str->Declaration()).name); },
+ [&](const type::Struct* str) { return b.ty(Fork(str).name); },
[&](const type::Array* arr) {
if (arr->Count()->Is<type::RuntimeArrayCount>()) {
return b.ty.array(AtomicTypeFor(arr->ElemType()));
@@ -231,7 +232,7 @@
(atomic_variables.count(e->RootIdentifier()) != 0)) {
// If it's a struct member, make sure it's one we marked as atomic
if (auto* ma = e->As<sem::StructMemberAccess>()) {
- auto it = forked_structs.find(ma->Member()->Struct()->Declaration());
+ auto it = forked_structs.find(ma->Member()->Struct());
if (it != forked_structs.end()) {
auto& forked = it->second;
return forked.atomic_members.count(ma->Member()->Index()) != 0;
diff --git a/src/tint/transform/std140.cc b/src/tint/transform/std140.cc
index b22a6e0..fa4fade 100644
--- a/src/tint/transform/std140.cc
+++ b/src/tint/transform/std140.cc
@@ -144,7 +144,7 @@
// Scan structures for members that need forking
for (auto* ty : src->Types()) {
- if (auto* str = ty->As<sem::Struct>()) {
+ if (auto* str = ty->As<type::Struct>()) {
if (str->UsedAs(builtin::AddressSpace::kUniform)) {
for (auto* member : str->Members()) {
if (needs_fork(member->Type())) {
@@ -226,11 +226,11 @@
utils::Hashset<const sem::Variable*, 8> std140_uniforms;
// Map of original structure to 'std140' forked structure
- utils::Hashmap<const sem::Struct*, Symbol, 8> std140_structs;
+ utils::Hashmap<const type::Struct*, Symbol, 8> std140_structs;
// Map of structure member in src of a matrix type, to list of decomposed column
// members in ctx.dst.
- utils::Hashmap<const sem::StructMember*, utils::Vector<const ast::StructMember*, 4>, 8>
+ utils::Hashmap<const type::StructMember*, utils::Vector<const ast::StructMember*, 4>, 8>
std140_mat_members;
/// Describes a matrix that has been forked to a std140-structure holding the decomposed column
@@ -403,7 +403,7 @@
ast::Type Std140Type(const type::Type* ty) {
return Switch(
ty, //
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
if (auto std140 = std140_structs.Find(str)) {
return b.ty(*std140);
}
@@ -631,7 +631,7 @@
const std::string ConvertSuffix(const type::Type* ty) {
return Switch(
ty, //
- [&](const sem::Struct* str) { return str->Name().Name(); },
+ [&](const type::Struct* str) { return str->Name().Name(); },
[&](const type::Array* arr) {
auto count = arr->ConstantCount();
if (TINT_UNLIKELY(!count)) {
@@ -694,7 +694,7 @@
Switch(
ty, //
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
// Convert each of the structure members using either a converter function
// call, or by reassembling a std140 matrix from column vector members.
utils::Vector<const ast::Expression*, 8> args;
@@ -832,7 +832,7 @@
// As this is accessing only part of the matrix, we just need to pick the right column
// vector member.
auto column_idx = std::get<u32>(chain.indices[std140_mat_idx + 1]);
- if (auto* str = tint::As<sem::Struct>(ty)) {
+ if (auto* str = tint::As<type::Struct>(ty)) {
// Structure member matrix. The columns are decomposed into the structure.
auto mat_member_idx = std::get<u32>(chain.indices[std140_mat_idx]);
auto* mat_member = str->Members()[mat_member_idx];
@@ -913,7 +913,7 @@
}
}
- if (auto* str = tint::As<sem::Struct>(ty)) {
+ if (auto* str = tint::As<type::Struct>(ty)) {
// Structure member matrix. The columns are decomposed into the structure.
auto mat_member_idx = std::get<u32>(chain.indices[std140_mat_idx]);
auto* mat_member = str->Members()[mat_member_idx];
@@ -1012,7 +1012,7 @@
stmts.Push(b.Decl(let));
utils::Vector<const ast::MemberAccessorExpression*, 4> columns;
- if (auto* str = tint::As<sem::Struct>(ty)) {
+ if (auto* str = tint::As<type::Struct>(ty)) {
// Structure member matrix. The columns are decomposed into the structure.
auto mat_member_idx = std::get<u32>(chain.indices[std140_mat_idx]);
auto* mat_member = str->Members()[mat_member_idx];
@@ -1133,7 +1133,7 @@
auto idx = std::get<u32>(access);
return Switch(
ty, //
- [&](const sem::Struct* str) -> ExprTypeName {
+ [&](const type::Struct* str) -> ExprTypeName {
auto* member = str->Members()[idx];
auto member_name = member->Name().Name();
auto* expr = b.MemberAccessor(lhs, member_name);
diff --git a/src/tint/transform/transform.cc b/src/tint/transform/transform.cc
index 2002d02..453768f 100644
--- a/src/tint/transform/transform.cc
+++ b/src/tint/transform/transform.cc
@@ -143,7 +143,7 @@
}
return ctx.dst->ty.array(el, u32(count.value()), std::move(attrs));
}
- if (auto* s = ty->As<sem::Struct>()) {
+ if (auto* s = ty->As<type::Struct>()) {
return ctx.dst->ty(ctx.Clone(s->Name()));
}
if (auto* s = ty->As<type::Reference>()) {
diff --git a/src/tint/transform/transform_test.cc b/src/tint/transform/transform_test.cc
index 1201e98..2da1ec5 100644
--- a/src/tint/transform/transform_test.cc
+++ b/src/tint/transform/transform_test.cc
@@ -120,8 +120,8 @@
TEST_F(CreateASTTypeForTest, Struct) {
auto str = create([](ProgramBuilder& b) {
auto* decl = b.Structure("S", {});
- return b.create<sem::Struct>(decl, decl->source, decl->name->symbol, utils::Empty,
- 4u /* align */, 4u /* size */, 4u /* size_no_padding */);
+ return b.create<sem::Struct>(decl, decl->name->symbol, utils::Empty, 4u /* align */,
+ 4u /* size */, 4u /* size_no_padding */);
});
ast::CheckIdentifier(str, "S");
diff --git a/src/tint/transform/truncate_interstage_variables.cc b/src/tint/transform/truncate_interstage_variables.cc
index 33c5cf7..1fc0050 100644
--- a/src/tint/transform/truncate_interstage_variables.cc
+++ b/src/tint/transform/truncate_interstage_variables.cc
@@ -83,6 +83,8 @@
auto* func_sem = sem.Get(func_ast);
auto* str = func_sem->ReturnType()->As<sem::Struct>();
+ // This transform is run after CanonicalizeEntryPointIO transform,
+ // So it is guaranteed that entry point inputs are already grouped in a struct.
if (TINT_UNLIKELY(!str)) {
TINT_ICE(Transform, ctx.dst->Diagnostics())
<< "Entrypoint function return type is non-struct.\n"
@@ -91,20 +93,14 @@
continue;
}
- // This transform is run after CanonicalizeEntryPointIO transform,
- // So it is guaranteed that entry point inputs are already grouped in a struct.
- const ast::Struct* struct_ty = str->Declaration();
-
// A prepass to check if any interstage variable locations in the entry point needs
// truncating. If not we don't really need to handle this entry point.
utils::Hashset<const sem::StructMember*, 16u> omit_members;
- for (auto* member : struct_ty->members) {
- if (ast::GetAttribute<ast::LocationAttribute>(member->attributes)) {
- auto* m = sem.Get(member);
- uint32_t location = m->Location().value();
- if (!data->interstage_locations.test(location)) {
- omit_members.Add(m);
+ for (auto* member : str->Members()) {
+ if (auto location = member->Attributes().location) {
+ if (!data->interstage_locations.test(location.value())) {
+ omit_members.Add(member);
}
}
}
diff --git a/src/tint/transform/vertex_pulling.cc b/src/tint/transform/vertex_pulling.cc
index 064be00..5f704de 100644
--- a/src/tint/transform/vertex_pulling.cc
+++ b/src/tint/transform/vertex_pulling.cc
@@ -826,8 +826,8 @@
auto* sem = src->Sem().Get(member);
info.type = sem->Type();
- TINT_ASSERT(Transform, sem->Location().has_value());
- location_info[sem->Location().value()] = info;
+ TINT_ASSERT(Transform, sem->Attributes().location.has_value());
+ location_info[sem->Attributes().location.value()] = info;
has_locations = true;
} else {
auto* builtin_attr = ast::GetAttribute<ast::BuiltinAttribute>(member->attributes);
diff --git a/src/tint/transform/zero_init_workgroup_memory.cc b/src/tint/transform/zero_init_workgroup_memory.cc
index 8572ef2..ec4a869 100644
--- a/src/tint/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/transform/zero_init_workgroup_memory.cc
@@ -168,19 +168,16 @@
}
}
- if (auto* str = sem.Get(param)->Type()->As<sem::Struct>()) {
+ if (auto* str = sem.Get(param)->Type()->As<type::Struct>()) {
for (auto* member : str->Members()) {
- if (auto* builtin_attr = ast::GetAttribute<ast::BuiltinAttribute>(
- member->Declaration()->attributes)) {
- auto builtin = sem.Get(builtin_attr)->Value();
- if (builtin == builtin::BuiltinValue::kLocalInvocationIndex) {
- local_index = [=] {
- auto* param_expr = b.Expr(ctx.Clone(param->name->symbol));
- auto* member_name = ctx.Clone(member->Declaration()->name);
- return b.MemberAccessor(param_expr, member_name);
- };
- break;
- }
+ if (member->Attributes().builtin ==
+ builtin::BuiltinValue::kLocalInvocationIndex) {
+ local_index = [=] {
+ auto* param_expr = b.Expr(ctx.Clone(param->name->symbol));
+ auto member_name = ctx.Clone(member->Name());
+ return b.MemberAccessor(param_expr, member_name);
+ };
+ break;
}
}
}
@@ -318,9 +315,9 @@
return true;
}
- if (auto* str = ty->As<sem::Struct>()) {
+ if (auto* str = ty->As<type::Struct>()) {
for (auto* member : str->Members()) {
- auto name = ctx.Clone(member->Declaration()->name->symbol);
+ auto name = ctx.Clone(member->Name());
auto get_member = [&](uint32_t num_values) {
auto s = get_expr(num_values);
if (!s) {
@@ -444,7 +441,7 @@
if (ty->Is<type::Atomic>()) {
return false;
}
- if (auto* str = ty->As<sem::Struct>()) {
+ if (auto* str = ty->As<type::Struct>()) {
for (auto* member : str->Members()) {
if (!CanTriviallyZero(member->Type())) {
return false;
diff --git a/src/tint/type/struct.cc b/src/tint/type/struct.cc
index e5c8d4c..c9864cb 100644
--- a/src/tint/type/struct.cc
+++ b/src/tint/type/struct.cc
@@ -52,14 +52,12 @@
} // namespace
-Struct::Struct(tint::Source source,
- Symbol name,
+Struct::Struct(Symbol name,
utils::VectorRef<const StructMember*> members,
uint32_t align,
uint32_t size,
uint32_t size_no_padding)
: Base(utils::Hash(utils::TypeInfo::Of<Struct>().full_hashcode, name), FlagsFrom(members)),
- source_(source),
name_(name),
members_(std::move(members)),
align_(align),
@@ -169,33 +167,30 @@
for (const auto& mem : members_) {
members.Push(mem->Clone(ctx));
}
- return ctx.dst.mgr->Get<Struct>(source_, sym, members, align_, size_, size_no_padding_);
+ return ctx.dst.mgr->Get<Struct>(sym, members, align_, size_, size_no_padding_);
}
-StructMember::StructMember(tint::Source source,
- Symbol name,
+StructMember::StructMember(Symbol name,
const type::Type* type,
uint32_t index,
uint32_t offset,
uint32_t align,
uint32_t size,
- std::optional<uint32_t> location)
- : source_(source),
- name_(name),
+ const StructMemberAttributes& attributes)
+ : name_(name),
type_(type),
index_(index),
offset_(offset),
align_(align),
size_(size),
- location_(location) {}
+ attributes_(attributes) {}
StructMember::~StructMember() = default;
StructMember* StructMember::Clone(CloneContext& ctx) const {
auto sym = ctx.dst.st->Register(name_.Name());
auto* ty = type_->Clone(ctx);
- return ctx.dst.mgr->Get<StructMember>(source_, sym, ty, index_, offset_, align_, size_,
- location_);
+ return ctx.dst.mgr->Get<StructMember>(sym, ty, index_, offset_, align_, size_, attributes_);
}
} // namespace tint::type
diff --git a/src/tint/type/struct.h b/src/tint/type/struct.h
index ea459f5..08119d0 100644
--- a/src/tint/type/struct.h
+++ b/src/tint/type/struct.h
@@ -22,6 +22,7 @@
#include <unordered_set>
#include "src/tint/builtin/address_space.h"
+#include "src/tint/builtin/interpolation.h"
#include "src/tint/symbol.h"
#include "src/tint/type/node.h"
#include "src/tint/type/type.h"
@@ -48,15 +49,13 @@
class Struct : public utils::Castable<Struct, Type> {
public:
/// Constructor
- /// @param source the source of the structure
/// @param name the name of the structure
/// @param members the structure members
/// @param align the byte alignment of the structure
/// @param size the byte size of the structure
/// @param size_no_padding size of the members without the end of structure
/// alignment padding
- Struct(tint::Source source,
- Symbol name,
+ Struct(Symbol name,
utils::VectorRef<const StructMember*> members,
uint32_t align,
uint32_t size,
@@ -69,9 +68,6 @@
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
- /// @returns the source of the structure
- tint::Source Source() const { return source_; }
-
/// @returns the name of the structure
Symbol Name() const { return name_; }
@@ -152,7 +148,6 @@
Struct* Clone(CloneContext& ctx) const override;
private:
- const tint::Source source_;
const Symbol name_;
const utils::Vector<const StructMember*, 4> members_;
const uint32_t align_;
@@ -163,33 +158,40 @@
utils::Vector<const Struct*, 2> concrete_types_;
};
+/// Attributes that can be applied to the StructMember
+struct StructMemberAttributes {
+ /// The value of a `@location` attribute
+ std::optional<uint32_t> location;
+ /// The value of a `@builtin` attribute
+ std::optional<builtin::BuiltinValue> builtin;
+ /// The values of a `@interpolate` attribute
+ std::optional<builtin::Interpolation> interpolation;
+ /// True if the member was annotated with `@invariant`
+ bool invariant = false;
+};
+
/// StructMember holds the type information for structure members.
class StructMember : public utils::Castable<StructMember, Node> {
public:
/// Constructor
- /// @param source the source of the struct member
/// @param name the name of the structure member
/// @param type the type of the member
/// @param index the index of the member in the structure
/// @param offset the byte offset from the base of the structure
/// @param align the byte alignment of the member
/// @param size the byte size of the member
- /// @param location the location attribute, if present
- StructMember(tint::Source source,
- Symbol name,
+ /// @param attributes the optional attributes
+ StructMember(Symbol name,
const type::Type* type,
uint32_t index,
uint32_t offset,
uint32_t align,
uint32_t size,
- std::optional<uint32_t> location);
+ const StructMemberAttributes& attributes);
/// Destructor
~StructMember() override;
- /// @returns the source the struct member
- const tint::Source& Source() const { return source_; }
-
/// @returns the name of the structure member
Symbol Name() const { return name_; }
@@ -215,15 +217,14 @@
/// @returns byte size
uint32_t Size() const { return size_; }
- /// @returns the location, if set
- std::optional<uint32_t> Location() const { return location_; }
+ /// @returns the optional attributes
+ const StructMemberAttributes& Attributes() const { return attributes_; }
/// @param ctx the clone context
/// @returns a clone of this struct member
StructMember* Clone(CloneContext& ctx) const;
private:
- const tint::Source source_;
const Symbol name_;
const type::Struct* struct_;
const type::Type* type_;
@@ -231,7 +232,7 @@
const uint32_t offset_;
const uint32_t align_;
const uint32_t size_;
- const std::optional<uint32_t> location_;
+ const StructMemberAttributes attributes_;
};
} // namespace tint::type
diff --git a/src/tint/type/struct_test.cc b/src/tint/type/struct_test.cc
index 7bfb437..bb88740 100644
--- a/src/tint/type/struct_test.cc
+++ b/src/tint/type/struct_test.cc
@@ -24,7 +24,7 @@
TEST_F(TypeStructTest, Creation) {
auto name = Sym("S");
- auto* s = create<Struct>(Source{}, name, utils::Empty, 4u /* align */, 8u /* size */,
+ auto* s = create<Struct>(name, utils::Empty, 4u /* align */, 8u /* size */,
16u /* size_no_padding */);
EXPECT_EQ(s->Align(), 4u);
EXPECT_EQ(s->Size(), 8u);
@@ -32,9 +32,9 @@
}
TEST_F(TypeStructTest, Equals) {
- auto* a = create<Struct>(Source{}, Sym("a"), utils::Empty, 4u /* align */, 4u /* size */,
+ auto* a = create<Struct>(Sym("a"), utils::Empty, 4u /* align */, 4u /* size */,
4u /* size_no_padding */);
- auto* b = create<Struct>(Source{}, Sym("b"), utils::Empty, 4u /* align */, 4u /* size */,
+ auto* b = create<Struct>(Sym("b"), utils::Empty, 4u /* align */, 4u /* size */,
4u /* size_no_padding */);
EXPECT_TRUE(a->Equals(*a));
@@ -44,8 +44,8 @@
TEST_F(TypeStructTest, FriendlyName) {
auto name = Sym("my_struct");
- auto* s = create<Struct>(Source{}, name, utils::Empty, 4u /* align */, 4u /* size */,
- 4u /* size_no_padding */);
+ auto* s =
+ create<Struct>(name, utils::Empty, 4u /* align */, 4u /* size */, 4u /* size_no_padding */);
EXPECT_EQ(s->FriendlyName(), "my_struct");
}
@@ -101,10 +101,8 @@
auto* sem = p.Sem().Get(st);
ASSERT_EQ(2u, sem->Members().Length());
- EXPECT_TRUE(sem->Members()[0]->Location().has_value());
- EXPECT_EQ(sem->Members()[0]->Location().value(), 1u);
-
- EXPECT_FALSE(sem->Members()[1]->Location().has_value());
+ EXPECT_EQ(sem->Members()[0]->Attributes().location, 1u);
+ EXPECT_FALSE(sem->Members()[1]->Attributes().location.has_value());
}
TEST_F(TypeStructTest, IsConstructable) {
@@ -207,12 +205,15 @@
}
TEST_F(TypeStructTest, Clone) {
+ type::StructMemberAttributes attrs_location_2;
+ attrs_location_2.location = 2;
+
auto* s = create<Struct>(
- Source{}, Sym("my_struct"),
- utils::Vector{create<StructMember>(Source{}, Sym("b"), create<Vector>(create<F32>(), 3u),
- 0u, 0u, 16u, 12u, std::optional<uint32_t>{2}),
- create<StructMember>(Source{}, Sym("a"), create<I32>(), 1u, 16u, 4u, 4u,
- std::optional<uint32_t>())},
+ Sym("my_struct"),
+ utils::Vector{create<StructMember>(Sym("b"), create<Vector>(create<F32>(), 3u), 0u, 0u, 16u,
+ 12u, attrs_location_2),
+ create<StructMember>(Sym("a"), create<I32>(), 1u, 16u, 4u, 4u,
+ type::StructMemberAttributes{})},
4u /* align */, 8u /* size */, 16u /* size_no_padding */);
ProgramID id;
diff --git a/src/tint/type/type_test.cc b/src/tint/type/type_test.cc
index 1565e10..b76a43a 100644
--- a/src/tint/type/type_test.cc
+++ b/src/tint/type/type_test.cc
@@ -45,50 +45,44 @@
const Matrix* mat4x3_af = create<Matrix>(vec3_af, 4u);
const Reference* ref_u32 =
create<Reference>(u32, builtin::AddressSpace::kPrivate, builtin::Access::kReadWrite);
- const Struct* str_f32 = create<Struct>(Source{},
- Sym("str_f32"),
+ const Struct* str_f32 = create<Struct>(Sym("str_f32"),
utils::Vector{
create<StructMember>(
- /* source */ Source{},
/* name */ Sym("x"),
/* type */ f32,
/* index */ 0u,
/* offset */ 0u,
/* align */ 4u,
/* size */ 4u,
- /* location */ std::nullopt),
+ /* attributes */ type::StructMemberAttributes{}),
},
/* align*/ 4u,
/* size*/ 4u,
/* size_no_padding*/ 4u);
- const Struct* str_f16 = create<Struct>(Source{},
- Sym("str_f16"),
+ const Struct* str_f16 = create<Struct>(Sym("str_f16"),
utils::Vector{
create<StructMember>(
- /* source */ Source{},
/* name */ Sym("x"),
/* type */ f16,
/* index */ 0u,
/* offset */ 0u,
/* align */ 4u,
/* size */ 4u,
- /* location */ std::nullopt),
+ /* attributes */ type::StructMemberAttributes{}),
},
/* align*/ 4u,
/* size*/ 4u,
/* size_no_padding*/ 4u);
- Struct* str_af = create<Struct>(Source{},
- Sym("str_af"),
+ Struct* str_af = create<Struct>(Sym("str_af"),
utils::Vector{
create<StructMember>(
- /* source */ Source{},
/* name */ Sym("x"),
/* type */ af,
/* index */ 0u,
/* offset */ 0u,
/* align */ 4u,
/* size */ 4u,
- /* location */ std::nullopt),
+ /* attributes */ type::StructMemberAttributes{}),
},
/* align*/ 4u,
/* size*/ 4u,
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index cd3834f..8fcdd3d 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -814,7 +814,7 @@
return;
}
case builtin::Function::kAtomicCompareExchangeWeak: {
- EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>());
+ EmitStructType(&helpers_, builtin->ReturnType()->As<type::Struct>());
auto* dest = expr->args[0];
auto* compare_value = expr->args[1];
@@ -1043,7 +1043,7 @@
[&](TextBuffer* b, const std::vector<std::string>& params) {
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
- EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>());
+ EmitStructType(&helpers_, builtin->ReturnType()->As<type::Struct>());
{
auto l = line(b);
@@ -1064,7 +1064,7 @@
[&](TextBuffer* b, const std::vector<std::string>& params) {
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
- EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>());
+ EmitStructType(&helpers_, builtin->ReturnType()->As<type::Struct>());
{
auto l = line(b);
@@ -1769,7 +1769,7 @@
void GeneratorImpl::EmitUniformVariable(const ast::Var* var, const sem::Variable* sem) {
auto* type = sem->Type()->UnwrapRef();
- auto* str = type->As<sem::Struct>();
+ auto* str = type->As<type::Struct>();
if (TINT_UNLIKELY(!str)) {
TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
return;
@@ -1788,7 +1788,7 @@
void GeneratorImpl::EmitStorageVariable(const ast::Var* var, const sem::Variable* sem) {
auto* type = sem->Type()->UnwrapRef();
- auto* str = type->As<sem::Struct>();
+ auto* str = type->As<type::Struct>();
if (TINT_UNLIKELY(!str)) {
TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
return;
@@ -2040,7 +2040,7 @@
for (auto* var : func->params) {
auto* sem = builder_.Sem().Get(var);
auto* type = sem->Type();
- if (TINT_UNLIKELY(!type->Is<sem::Struct>())) {
+ if (TINT_UNLIKELY(!type->Is<type::Struct>())) {
// ICE likely indicates that the CanonicalizeEntryPointIO transform was
// not run, or a builtin parameter was added after it was run.
TINT_ICE(Writer, diagnostics_) << "Unsupported non-struct entry point parameter";
@@ -2132,7 +2132,7 @@
EmitConstant(out, constant->Index(i));
}
},
- [&](const sem::Struct* s) {
+ [&](const type::Struct* s) {
EmitStructType(&helpers_, s);
out << StructName(s);
@@ -2210,7 +2210,7 @@
}
EmitZeroValue(out, mat->type());
}
- } else if (auto* str = type->As<sem::Struct>()) {
+ } else if (auto* str = type->As<type::Struct>()) {
EmitType(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kUndefined, "");
bool first = true;
ScopedParen sp(out);
@@ -2568,7 +2568,7 @@
TINT_ICE(Writer, diagnostics_) << "Attempting to emit pointer type. These should have been "
"removed with the SimplifyPointers transform";
} else if (type->Is<type::Sampler>()) {
- } else if (auto* str = type->As<sem::Struct>()) {
+ } else if (auto* str = type->As<type::Struct>()) {
out << StructName(str);
} else if (auto* tex = type->As<type::Texture>()) {
if (TINT_UNLIKELY(tex->Is<type::ExternalTexture>())) {
@@ -2669,7 +2669,7 @@
}
}
-void GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
+void GeneratorImpl::EmitStructType(TextBuffer* b, const type::Struct* str) {
auto it = emitted_structs_.emplace(str);
if (!it.second) {
return;
@@ -2682,7 +2682,7 @@
line(b);
}
-void GeneratorImpl::EmitStructMembers(TextBuffer* b, const sem::Struct* str) {
+void GeneratorImpl::EmitStructMembers(TextBuffer* b, const type::Struct* str) {
ScopedIndent si(b);
for (auto* mem : str->Members()) {
auto name = mem->Name().Name();
diff --git a/src/tint/writer/glsl/generator_impl.h b/src/tint/writer/glsl/generator_impl.h
index 0698d4f..5d74e37 100644
--- a/src/tint/writer/glsl/generator_impl.h
+++ b/src/tint/writer/glsl/generator_impl.h
@@ -383,11 +383,11 @@
/// this function will simply return `true` without emitting anything.
/// @param buffer the text buffer that the type declaration will be written to
/// @param ty the struct to generate
- void EmitStructType(TextBuffer* buffer, const sem::Struct* ty);
+ void EmitStructType(TextBuffer* buffer, const type::Struct* ty);
/// Handles generating the members of a structure
/// @param buffer the text buffer that the struct members will be written to
/// @param ty the struct to generate
- void EmitStructMembers(TextBuffer* buffer, const sem::Struct* ty);
+ void EmitStructMembers(TextBuffer* buffer, const type::Struct* ty);
/// Handles a unary op expression
/// @param out the output of the expression stream
/// @param expr the expression to emit
@@ -399,7 +399,7 @@
/// Handles generating a 'var' declaration
/// @param var the variable to generate
void EmitVar(const ast::Var* var);
- /// Handles generating a function-scope 'let' declaration
+ /// Handles generating a 'let' declaration
/// @param let the variable to generate
void EmitLet(const ast::Let* let);
/// Handles generating a module-scope 'let' declaration
@@ -460,7 +460,7 @@
std::unordered_map<const type::Vector*, std::string> dynamic_vector_write_;
std::unordered_map<const type::Vector*, std::string> int_dot_funcs_;
std::unordered_map<BinaryOperandType, std::string> float_modulo_funcs_;
- std::unordered_set<const sem::Struct*> emitted_structs_;
+ std::unordered_set<const type::Struct*> emitted_structs_;
bool requires_oes_sample_variables_ = false;
bool requires_default_precision_qualifier_ = false;
bool requires_f16_extension_ = false;
diff --git a/src/tint/writer/glsl/generator_impl_type_test.cc b/src/tint/writer/glsl/generator_impl_type_test.cc
index 0e85155..5cec150 100644
--- a/src/tint/writer/glsl/generator_impl_type_test.cc
+++ b/src/tint/writer/glsl/generator_impl_type_test.cc
@@ -170,8 +170,8 @@
GeneratorImpl& gen = Build();
TextGenerator::TextBuffer buf;
- auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
- gen.EmitStructType(&buf, sem_s);
+ auto* str = program->TypeOf(s)->As<type::Struct>();
+ gen.EmitStructType(&buf, str);
EXPECT_THAT(gen.Diagnostics(), testing::IsEmpty());
EXPECT_EQ(buf.String(), R"(struct S {
int a;
@@ -190,9 +190,9 @@
GeneratorImpl& gen = Build();
- auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+ auto* str = program->TypeOf(s)->As<type::Struct>();
utils::StringStream out;
- gen.EmitType(out, sem_s, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, "");
+ gen.EmitType(out, str, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, "");
EXPECT_THAT(gen.Diagnostics(), testing::IsEmpty());
EXPECT_EQ(out.str(), "S");
}
@@ -224,8 +224,8 @@
GeneratorImpl& gen = Build();
TextGenerator::TextBuffer buf;
- auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
- gen.EmitStructType(&buf, sem_s);
+ auto* str = program->TypeOf(s)->As<type::Struct>();
+ gen.EmitStructType(&buf, str);
EXPECT_THAT(gen.Diagnostics(), testing::IsEmpty());
EXPECT_EQ(buf.String(), R"(struct S {
int a;
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 5cce6a1..ed86e9e 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -1094,7 +1094,7 @@
}
}
- bool brackets = type->IsAnyOf<type::Array, sem::Struct>();
+ bool brackets = type->IsAnyOf<type::Array, type::Struct>();
// For single-value vector initializers, swizzle the scalar to the right
// vector dimension using .x
@@ -1887,7 +1887,7 @@
return true;
}
case builtin::Function::kAtomicCompareExchangeWeak: {
- if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+ if (!EmitStructType(&helpers_, builtin->ReturnType()->As<type::Struct>())) {
return false;
}
@@ -2004,7 +2004,7 @@
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
- if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+ if (!EmitStructType(&helpers_, builtin->ReturnType()->As<type::Struct>())) {
return false;
}
@@ -2037,7 +2037,7 @@
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
- if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+ if (!EmitStructType(&helpers_, builtin->ReturnType()->As<type::Struct>())) {
return false;
}
@@ -3287,7 +3287,7 @@
for (auto* var : func->params) {
auto* sem = builder_.Sem().Get(var);
auto* type = sem->Type();
- if (TINT_UNLIKELY(!type->Is<sem::Struct>())) {
+ if (TINT_UNLIKELY(!type->Is<type::Struct>())) {
// ICE likely indicates that the CanonicalizeEntryPointIO transform was
// not run, or a builtin parameter was added after it was run.
TINT_ICE(Writer, diagnostics_) << "Unsupported non-struct entry point parameter";
@@ -3437,7 +3437,7 @@
return true;
},
- [&](const sem::Struct* s) {
+ [&](const type::Struct* s) {
if (!EmitStructType(&helpers_, s)) {
return false;
}
@@ -3580,7 +3580,7 @@
}
return true;
},
- [&](const sem::Struct*) {
+ [&](const type::Struct*) {
out << "(";
TINT_DEFER(out << ")" << value);
return EmitType(out, type, builtin::AddressSpace::kUndefined,
@@ -4077,7 +4077,7 @@
out << "State";
return true;
},
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
out << StructName(str);
return true;
},
@@ -4202,7 +4202,7 @@
return true;
}
-bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
+bool GeneratorImpl::EmitStructType(TextBuffer* b, const type::Struct* str) {
auto it = emitted_structs_.emplace(str);
if (!it.second) {
return true;
@@ -4216,73 +4216,48 @@
auto* ty = mem->Type();
auto out = line(b);
std::string pre, post;
- if (auto* decl = mem->Declaration()) {
- for (auto* attr : decl->attributes) {
- if (attr->Is<ast::LocationAttribute>()) {
- auto& pipeline_stage_uses = str->PipelineStageUses();
- if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
- TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
- }
- auto loc = mem->Location().value();
- if (pipeline_stage_uses.count(type::PipelineStageUsage::kVertexInput)) {
- post += " : TEXCOORD" + std::to_string(loc);
- } else if (pipeline_stage_uses.count(
- type::PipelineStageUsage::kVertexOutput)) {
- post += " : TEXCOORD" + std::to_string(loc);
- } else if (pipeline_stage_uses.count(
- type::PipelineStageUsage::kFragmentInput)) {
- post += " : TEXCOORD" + std::to_string(loc);
- } else if (TINT_LIKELY(pipeline_stage_uses.count(
- type::PipelineStageUsage::kFragmentOutput))) {
- post += " : SV_Target" + std::to_string(loc);
- } else {
- TINT_ICE(Writer, diagnostics_) << "invalid use of location attribute";
- }
- } else if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
- auto builtin = program_->Sem().Get(builtin_attr)->Value();
- auto name = builtin_to_attribute(builtin);
- if (name.empty()) {
- diagnostics_.add_error(diag::System::Writer, "unsupported builtin");
- return false;
- }
- post += " : " + name;
- } else if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
- auto& sem = program_->Sem();
- auto i_type =
- sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationType>>(
- interpolate->type)
- ->Value();
+ auto& attributes = mem->Attributes();
- auto i_smpl = builtin::InterpolationSampling::kUndefined;
- if (interpolate->sampling) {
- i_smpl =
- sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>(
- interpolate->sampling)
- ->Value();
- }
-
- auto mod = interpolation_to_modifiers(i_type, i_smpl);
- if (mod.empty()) {
- diagnostics_.add_error(diag::System::Writer,
- "unsupported interpolation");
- return false;
- }
- pre += mod;
-
- } else if (attr->Is<ast::InvariantAttribute>()) {
- // Note: `precise` is not exactly the same as `invariant`, but is
- // stricter and therefore provides the necessary guarantees.
- // See discussion here: https://github.com/gpuweb/gpuweb/issues/893
- pre += "precise ";
- } else if (TINT_UNLIKELY((!attr->IsAnyOf<ast::StructMemberAlignAttribute,
- ast::StructMemberOffsetAttribute,
- ast::StructMemberSizeAttribute>()))) {
- TINT_ICE(Writer, diagnostics_)
- << "unhandled struct member attribute: " << attr->Name();
- return false;
- }
+ if (auto location = attributes.location) {
+ auto& pipeline_stage_uses = str->PipelineStageUses();
+ if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
+ TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
}
+ if (pipeline_stage_uses.count(type::PipelineStageUsage::kVertexInput)) {
+ post += " : TEXCOORD" + std::to_string(location.value());
+ } else if (pipeline_stage_uses.count(type::PipelineStageUsage::kVertexOutput)) {
+ post += " : TEXCOORD" + std::to_string(location.value());
+ } else if (pipeline_stage_uses.count(type::PipelineStageUsage::kFragmentInput)) {
+ post += " : TEXCOORD" + std::to_string(location.value());
+ } else if (TINT_LIKELY(pipeline_stage_uses.count(
+ type::PipelineStageUsage::kFragmentOutput))) {
+ post += " : SV_Target" + std::to_string(location.value());
+ } else {
+ TINT_ICE(Writer, diagnostics_) << "invalid use of location attribute";
+ }
+ }
+ if (auto builtin = attributes.builtin) {
+ auto name = builtin_to_attribute(builtin.value());
+ if (name.empty()) {
+ diagnostics_.add_error(diag::System::Writer, "unsupported builtin");
+ return false;
+ }
+ post += " : " + name;
+ }
+ if (auto interpolation = attributes.interpolation) {
+ auto mod = interpolation_to_modifiers(interpolation->type, interpolation->sampling);
+ if (mod.empty()) {
+ diagnostics_.add_error(diag::System::Writer, "unsupported interpolation");
+ return false;
+ }
+ pre += mod;
+ }
+ if (attributes.invariant) {
+ // Note: `precise` is not exactly the same as `invariant`, but is
+ // stricter and therefore provides the necessary guarantees.
+ // See discussion here: https://github.com/gpuweb/gpuweb/issues/893
+ pre += "precise ";
}
out << pre;
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index 103e355..f52d58f 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -449,7 +449,7 @@
/// @param buffer the text buffer that the type declaration will be written to
/// @param ty the struct to generate
/// @returns true if the struct is emitted
- bool EmitStructType(TextBuffer* buffer, const sem::Struct* ty);
+ bool EmitStructType(TextBuffer* buffer, const type::Struct* ty);
/// Handles a unary op expression
/// @param out the output of the expression stream
/// @param expr the expression to emit
@@ -470,7 +470,7 @@
/// @param var the variable to generate
/// @returns true if the variable was emitted
bool EmitVar(const ast::Var* var);
- /// Handles generating a function-scope 'let' declaration
+ /// Handles generating a 'let' declaration
/// @param let the variable to generate
/// @returns true if the variable was emitted
bool EmitLet(const ast::Let* let);
@@ -568,7 +568,7 @@
std::unordered_map<const type::Matrix*, std::string> dynamic_matrix_vector_write_;
std::unordered_map<const type::Matrix*, std::string> dynamic_matrix_scalar_write_;
std::unordered_map<const type::Type*, std::string> value_or_one_if_zero_;
- std::unordered_set<const sem::Struct*> emitted_structs_;
+ std::unordered_set<const type::Struct*> emitted_structs_;
};
} // namespace tint::writer::hlsl
diff --git a/src/tint/writer/hlsl/generator_impl_type_test.cc b/src/tint/writer/hlsl/generator_impl_type_test.cc
index d93d8e3..337b26b 100644
--- a/src/tint/writer/hlsl/generator_impl_type_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_type_test.cc
@@ -171,8 +171,8 @@
GeneratorImpl& gen = Build();
TextGenerator::TextBuffer buf;
- auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
- ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.Diagnostics();
+ auto* str = program->TypeOf(s)->As<type::Struct>();
+ ASSERT_TRUE(gen.EmitStructType(&buf, str)) << gen.Diagnostics();
EXPECT_EQ(buf.String(), R"(struct S {
int a;
float b;
@@ -203,10 +203,10 @@
GeneratorImpl& gen = Build();
- auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+ auto* str = program->TypeOf(s)->As<type::Struct>();
utils::StringStream out;
- ASSERT_TRUE(gen.EmitType(out, sem_s, builtin::AddressSpace::kUndefined,
- builtin::Access::kReadWrite, ""))
+ ASSERT_TRUE(
+ gen.EmitType(out, str, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
<< gen.Diagnostics();
EXPECT_EQ(out.str(), "S");
}
@@ -238,8 +238,8 @@
GeneratorImpl& gen = Build();
TextGenerator::TextBuffer buf;
- auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
- ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.Diagnostics();
+ auto* str = program->TypeOf(s)->As<type::Struct>();
+ ASSERT_TRUE(gen.EmitStructType(&buf, str)) << gen.Diagnostics();
EXPECT_EQ(buf.String(), R"(struct S {
int a;
float b;
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 0435918..14288ee 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -363,7 +363,7 @@
}
bool GeneratorImpl::EmitTypeDecl(const type::Type* ty) {
- if (auto* str = ty->As<sem::Struct>()) {
+ if (auto* str = ty->As<type::Struct>()) {
if (!EmitStructType(current_buffer_, str)) {
return false;
}
@@ -826,7 +826,7 @@
terminator = "}";
return true;
},
- [&](const sem::Struct*) {
+ [&](const type::Struct*) {
out << "{";
terminator = "}";
return true;
@@ -848,10 +848,9 @@
out << ", ";
}
- if (auto* struct_ty = type->As<sem::Struct>()) {
+ if (auto* struct_ty = type->As<type::Struct>()) {
// Emit field designators for structures to account for padding members.
- auto* member = struct_ty->Members()[i]->Declaration();
- auto name = member->name->symbol.Name();
+ auto name = struct_ty->Members()[i]->Name().Name();
out << "." << name << "=";
}
@@ -922,11 +921,11 @@
case builtin::Function::kAtomicCompareExchangeWeak: {
auto* ptr_ty = TypeOf(expr->args[0])->UnwrapRef()->As<type::Pointer>();
auto sc = ptr_ty->AddressSpace();
- auto* str = builtin->ReturnType()->As<sem::Struct>();
+ auto* str = builtin->ReturnType()->As<type::Struct>();
auto func = utils::GetOrCreate(
atomicCompareExchangeWeak_, ACEWKeyType{{sc, str}}, [&]() -> std::string {
- if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+ if (!EmitStructType(&helpers_, builtin->ReturnType()->As<type::Struct>())) {
return "";
}
@@ -937,7 +936,7 @@
{
auto f = line(&buf);
- auto str_name = StructName(builtin->ReturnType()->As<sem::Struct>());
+ auto str_name = StructName(builtin->ReturnType()->As<type::Struct>());
f << str_name << " " << name << "(";
if (!EmitTypeAndName(f, atomic_ty, "atomic")) {
return "";
@@ -1361,11 +1360,11 @@
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
- if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+ if (!EmitStructType(&helpers_, builtin->ReturnType()->As<type::Struct>())) {
return false;
}
- line(b) << StructName(builtin->ReturnType()->As<sem::Struct>()) << " result;";
+ line(b) << StructName(builtin->ReturnType()->As<type::Struct>()) << " result;";
line(b) << "result.fract = modf(" << in << ", result.whole);";
line(b) << "return result;";
return true;
@@ -1387,11 +1386,11 @@
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
- if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+ if (!EmitStructType(&helpers_, builtin->ReturnType()->As<type::Struct>())) {
return false;
}
- line(b) << StructName(builtin->ReturnType()->As<sem::Struct>()) << " result;";
+ line(b) << StructName(builtin->ReturnType()->As<type::Struct>()) << " result;";
line(b) << "result.fract = frexp(" << in << ", result.exp);";
line(b) << "return result;";
return true;
@@ -1658,7 +1657,7 @@
out << "{}";
return true;
},
- [&](const sem::Struct*) {
+ [&](const type::Struct*) {
out << "{}";
return true;
},
@@ -1763,7 +1762,7 @@
return true;
},
- [&](const sem::Struct* s) {
+ [&](const type::Struct* s) {
if (!EmitStructType(&helpers_, s)) {
return false;
}
@@ -2636,7 +2635,7 @@
out << "sampler";
return true;
},
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
// The struct type emits as just the name. The declaration would be
// emitted as part of emitting the declared types.
out << StructName(str);
@@ -2791,7 +2790,7 @@
return false;
}
-bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
+bool GeneratorImpl::EmitStructType(TextBuffer* b, const type::Struct* str) {
auto it = emitted_structs_.emplace(str);
if (!it.second) {
return true;
@@ -2852,88 +2851,51 @@
out << " " << mem_name;
// Emit attributes
- if (auto* decl = mem->Declaration()) {
- for (auto* attr : decl->attributes) {
- bool ok = Switch(
- attr,
- [&](const ast::BuiltinAttribute* builtin_attr) {
- auto builtin = program_->Sem().Get(builtin_attr)->Value();
- auto name = builtin_to_attribute(builtin);
- if (name.empty()) {
- diagnostics_.add_error(diag::System::Writer, "unknown builtin");
- return false;
- }
- out << " [[" << name << "]]";
- return true;
- },
- [&](const ast::LocationAttribute*) {
- auto& pipeline_stage_uses = str->PipelineStageUses();
- if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
- TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
- return false;
- }
+ auto& attributes = mem->Attributes();
- uint32_t loc = mem->Location().value();
- if (pipeline_stage_uses.count(type::PipelineStageUsage::kVertexInput)) {
- out << " [[attribute(" + std::to_string(loc) + ")]]";
- } else if (pipeline_stage_uses.count(
- type::PipelineStageUsage::kVertexOutput)) {
- out << " [[user(locn" + std::to_string(loc) + ")]]";
- } else if (pipeline_stage_uses.count(
- type::PipelineStageUsage::kFragmentInput)) {
- out << " [[user(locn" + std::to_string(loc) + ")]]";
- } else if (TINT_LIKELY(pipeline_stage_uses.count(
- type::PipelineStageUsage::kFragmentOutput))) {
- out << " [[color(" + std::to_string(loc) + ")]]";
- } else {
- TINT_ICE(Writer, diagnostics_) << "invalid use of location decoration";
- return false;
- }
- return true;
- },
- [&](const ast::InterpolateAttribute* interpolate) {
- auto& sem = program_->Sem();
- auto i_type =
- sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationType>>(
- interpolate->type)
- ->Value();
-
- auto i_smpl = builtin::InterpolationSampling::kUndefined;
- if (interpolate->sampling) {
- i_smpl =
- sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>(
- interpolate->sampling)
- ->Value();
- }
-
- auto name = interpolation_to_attribute(i_type, i_smpl);
- if (name.empty()) {
- diagnostics_.add_error(diag::System::Writer,
- "unknown interpolation attribute");
- return false;
- }
- out << " [[" << name << "]]";
- return true;
- },
- [&](const ast::InvariantAttribute*) {
- if (invariant_define_name_.empty()) {
- invariant_define_name_ = UniqueIdentifier("TINT_INVARIANT");
- }
- out << " " << invariant_define_name_;
- return true;
- },
- [&](const ast::StructMemberOffsetAttribute*) { return true; },
- [&](const ast::StructMemberAlignAttribute*) { return true; },
- [&](const ast::StructMemberSizeAttribute*) { return true; },
- [&](Default) {
- TINT_ICE(Writer, diagnostics_)
- << "unhandled struct member attribute: " << attr->Name();
- return false;
- });
- if (!ok) {
- return false;
- }
+ if (auto builtin = attributes.builtin) {
+ auto name = builtin_to_attribute(builtin.value());
+ if (name.empty()) {
+ diagnostics_.add_error(diag::System::Writer, "unknown builtin");
+ return false;
}
+ out << " [[" << name << "]]";
+ }
+
+ if (auto location = attributes.location) {
+ auto& pipeline_stage_uses = str->PipelineStageUses();
+ if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
+ TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
+ return false;
+ }
+
+ if (pipeline_stage_uses.count(type::PipelineStageUsage::kVertexInput)) {
+ out << " [[attribute(" + std::to_string(location.value()) + ")]]";
+ } else if (pipeline_stage_uses.count(type::PipelineStageUsage::kVertexOutput)) {
+ out << " [[user(locn" + std::to_string(location.value()) + ")]]";
+ } else if (pipeline_stage_uses.count(type::PipelineStageUsage::kFragmentInput)) {
+ out << " [[user(locn" + std::to_string(location.value()) + ")]]";
+ } else if (TINT_LIKELY(
+ pipeline_stage_uses.count(type::PipelineStageUsage::kFragmentOutput))) {
+ out << " [[color(" + std::to_string(location.value()) + ")]]";
+ } else {
+ TINT_ICE(Writer, diagnostics_) << "invalid use of location decoration";
+ return false;
+ }
+ }
+
+ if (auto interpolation = attributes.interpolation) {
+ auto name = interpolation_to_attribute(interpolation->type, interpolation->sampling);
+ if (name.empty()) {
+ diagnostics_.add_error(diag::System::Writer, "unknown interpolation attribute");
+ return false;
+ }
+ out << " [[" << name << "]]";
+ }
+
+ if (attributes.invariant) {
+ invariant_define_name_ = UniqueIdentifier("TINT_INVARIANT");
+ out << " " << invariant_define_name_;
}
out << ";";
@@ -3223,7 +3185,7 @@
return SizeAndAlign{};
},
- [&](const sem::Struct* str) {
+ [&](const type::Struct* str) {
// TODO(crbug.com/tint/650): There's an assumption here that MSL's
// default structure size and alignment matches WGSL's. We need to
// confirm this.
diff --git a/src/tint/writer/msl/generator_impl.h b/src/tint/writer/msl/generator_impl.h
index 5699242..0be80be 100644
--- a/src/tint/writer/msl/generator_impl.h
+++ b/src/tint/writer/msl/generator_impl.h
@@ -340,7 +340,7 @@
/// @param buffer the text buffer that the type declaration will be written to
/// @param str the struct to generate
/// @returns true if the struct is emitted
- bool EmitStructType(TextBuffer* buffer, const sem::Struct* str);
+ bool EmitStructType(TextBuffer* buffer, const type::Struct* str);
/// Handles a unary op expression
/// @param out the output of the expression stream
/// @param expr the expression to emit
@@ -350,7 +350,7 @@
/// @param var the variable to generate
/// @returns true if the variable was emitted
bool EmitVar(const ast::Var* var);
- /// Handles generating a function-scope 'let' declaration
+ /// Handles generating a 'let' declaration
/// @param let the variable to generate
/// @returns true if the variable was emitted
bool EmitLet(const ast::Let* let);
@@ -418,7 +418,7 @@
/// Name of atomicCompareExchangeWeak() helper for the given pointer storage
/// class and struct return type
using ACEWKeyType =
- utils::UnorderedKeyWrapper<std::tuple<builtin::AddressSpace, const sem::Struct*>>;
+ utils::UnorderedKeyWrapper<std::tuple<builtin::AddressSpace, const type::Struct*>>;
std::unordered_map<ACEWKeyType, std::string> atomicCompareExchangeWeak_;
/// Unique name of the 'TINT_INVARIANT' preprocessor define.
@@ -440,7 +440,7 @@
std::unordered_map<const sem::Builtin*, std::string> builtins_;
std::unordered_map<const type::Type*, std::string> unary_minus_funcs_;
std::unordered_map<uint32_t, std::string> int_dot_funcs_;
- std::unordered_set<const sem::Struct*> emitted_structs_;
+ std::unordered_set<const type::Struct*> emitted_structs_;
};
} // namespace tint::writer::msl
diff --git a/src/tint/writer/msl/generator_impl_type_test.cc b/src/tint/writer/msl/generator_impl_type_test.cc
index 3208708..3b9b652 100644
--- a/src/tint/writer/msl/generator_impl_type_test.cc
+++ b/src/tint/writer/msl/generator_impl_type_test.cc
@@ -245,8 +245,8 @@
GeneratorImpl& gen = Build();
TextGenerator::TextBuffer buf;
- auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
- ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.Diagnostics();
+ auto* str = program->TypeOf(s)->As<type::Struct>();
+ ASSERT_TRUE(gen.EmitStructType(&buf, str)) << gen.Diagnostics();
EXPECT_EQ(buf.String(), R"(struct S {
int a;
float b;
@@ -292,8 +292,8 @@
GeneratorImpl& gen = Build();
TextGenerator::TextBuffer buf;
- auto* sem_s = program->TypeOf(type)->As<sem::Struct>();
- ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.Diagnostics();
+ auto* str = program->TypeOf(type)->As<type::Struct>();
+ ASSERT_TRUE(gen.EmitStructType(&buf, str)) << gen.Diagnostics();
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, ARRAY_COUNT, NAME)
// for each field of the structure s.
@@ -401,8 +401,8 @@
GeneratorImpl& gen = Build();
TextGenerator::TextBuffer buf;
- auto* sem_s = program->TypeOf(type)->As<sem::Struct>();
- ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.Diagnostics();
+ auto* str = program->TypeOf(type)->As<type::Struct>();
+ ASSERT_TRUE(gen.EmitStructType(&buf, str)) << gen.Diagnostics();
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, ARRAY_COUNT, NAME)
// for each field of the structure s.
@@ -493,8 +493,8 @@
GeneratorImpl& gen = Build();
TextGenerator::TextBuffer buf;
- auto* sem_s = program->TypeOf(type)->As<sem::Struct>();
- ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.Diagnostics();
+ auto* str = program->TypeOf(type)->As<type::Struct>();
+ ASSERT_TRUE(gen.EmitStructType(&buf, str)) << gen.Diagnostics();
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, ARRAY_COUNT, NAME)
// for each field of the structure s.
@@ -577,8 +577,8 @@
GeneratorImpl& gen = Build();
TextGenerator::TextBuffer buf;
- auto* sem_s = program->TypeOf(type)->As<sem::Struct>();
- ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.Diagnostics();
+ auto* str = program->TypeOf(type)->As<type::Struct>();
+ ASSERT_TRUE(gen.EmitStructType(&buf, str)) << gen.Diagnostics();
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, ARRAY_COUNT, NAME)
// for each field of the structure s.
@@ -639,8 +639,8 @@
GeneratorImpl& gen = Build();
TextGenerator::TextBuffer buf;
- auto* sem_s = program->TypeOf(type)->As<sem::Struct>();
- ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.Diagnostics();
+ auto* str = program->TypeOf(type)->As<type::Struct>();
+ ASSERT_TRUE(gen.EmitStructType(&buf, str)) << gen.Diagnostics();
EXPECT_EQ(buf.String(), R"(struct S {
/* 0x0000 */ int tint_pad_2;
/* 0x0004 */ tint_array<int8_t, 124> tint_pad_10;
@@ -698,8 +698,8 @@
GeneratorImpl& gen = Build();
TextGenerator::TextBuffer buf;
- auto* sem_s = program->TypeOf(type)->As<sem::Struct>();
- ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.Diagnostics();
+ auto* str = program->TypeOf(type)->As<type::Struct>();
+ ASSERT_TRUE(gen.EmitStructType(&buf, str)) << gen.Diagnostics();
EXPECT_EQ(buf.String(), R"(struct S {
/* 0x0000 */ int a;
/* 0x0004 */ float b;
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index 4a5c90b..972ba7c 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -790,8 +790,8 @@
ops.push_back(Operand(init_id));
} else {
auto* st = type->As<type::StorageTexture>();
- if (st || type->Is<sem::Struct>()) {
- // type is a sem::Struct or a type::StorageTexture
+ if (st || type->Is<type::Struct>()) {
+ // type is a type::Struct or a type::StorageTexture
auto access = st ? st->access() : sem->Access();
switch (access) {
case builtin::Access::kWrite:
@@ -1353,7 +1353,7 @@
// If the result is not a vector then we should have validated that the
// value type is a correctly sized vector so we can just use it directly.
if (result_type == value_type || result_type->Is<type::Matrix>() ||
- result_type->Is<type::Array>() || result_type->Is<sem::Struct>()) {
+ result_type->Is<type::Array>() || result_type->Is<type::Struct>()) {
ops.push_back(Operand(id));
continue;
}
@@ -1715,7 +1715,7 @@
}
return composite(count.value());
},
- [&](const sem::Struct* s) { return composite(s->Members().Length()); },
+ [&](const type::Struct* s) { return composite(s->Members().Length()); },
[&](Default) {
error_ = "unhandled constant type: " + builder_.FriendlyName(ty);
return 0;
@@ -2391,13 +2391,12 @@
params.push_back(Operand(struct_id));
auto* type = TypeOf(accessor->object)->UnwrapRef();
- if (!type->Is<sem::Struct>()) {
+ if (!type->Is<type::Struct>()) {
error_ = "invalid type (" + type->FriendlyName() + ") for runtime array length";
return 0;
}
// Runtime array must be the last member in the structure
- params.push_back(
- Operand(uint32_t(type->As<sem::Struct>()->Declaration()->members.Length() - 1)));
+ params.push_back(Operand(uint32_t(type->As<type::Struct>()->Members().Length() - 1)));
if (!push_function_inst(spv::Op::OpArrayLength, params)) {
return 0;
@@ -3702,7 +3701,7 @@
[&](const type::Reference* ref) { //
return GenerateReferenceType(ref, result);
},
- [&](const sem::Struct* str) { //
+ [&](const type::Struct* str) { //
return GenerateStructType(str, result);
},
[&](const type::U32*) {
@@ -3914,7 +3913,7 @@
return true;
}
-bool Builder::GenerateStructType(const sem::Struct* struct_type, const Operand& result) {
+bool Builder::GenerateStructType(const type::Struct* struct_type, const Operand& result) {
auto struct_id = std::get<uint32_t>(result);
if (struct_type->Name().IsValid()) {
@@ -3924,9 +3923,11 @@
OperandList ops;
ops.push_back(result);
- auto* decl = struct_type->Declaration();
- if (decl && ast::HasAttribute<transform::AddBlockAttribute::BlockAttribute>(decl->attributes)) {
- push_annot(spv::Op::OpDecorate, {Operand(struct_id), U32Operand(SpvDecorationBlock)});
+ if (auto* sem_str = struct_type->As<sem::Struct>()) {
+ auto* decl = sem_str->Declaration();
+ if (ast::HasAttribute<transform::AddBlockAttribute::BlockAttribute>(decl->attributes)) {
+ push_annot(spv::Op::OpDecorate, {Operand(struct_id), U32Operand(SpvDecorationBlock)});
+ }
}
for (uint32_t i = 0; i < struct_type->Members().Length(); ++i) {
@@ -3944,7 +3945,7 @@
uint32_t Builder::GenerateStructMember(uint32_t struct_id,
uint32_t idx,
- const sem::StructMember* member) {
+ const type::StructMember* member) {
push_debug(spv::Op::OpMemberName,
{Operand(struct_id), Operand(idx), Operand(member->Name().Name())});
diff --git a/src/tint/writer/spirv/builder.h b/src/tint/writer/spirv/builder.h
index 53fb108..1bbffc8 100644
--- a/src/tint/writer/spirv/builder.h
+++ b/src/tint/writer/spirv/builder.h
@@ -496,7 +496,7 @@
/// @param struct_type the vector to generate
/// @param result the result operand
/// @returns true if the vector was successfully generated
- bool GenerateStructType(const sem::Struct* struct_type, const Operand& result);
+ bool GenerateStructType(const type::Struct* struct_type, const Operand& result);
/// Generates a struct member
/// @param struct_id the id of the parent structure
/// @param idx the index of the member
@@ -504,7 +504,7 @@
/// @returns the id of the struct member or 0 on error.
uint32_t GenerateStructMember(uint32_t struct_id,
uint32_t idx,
- const sem::StructMember* member);
+ const type::StructMember* member);
/// Generates a variable declaration statement
/// @param stmt the statement to generate
/// @returns true on successfull generation
diff --git a/src/tint/writer/text_generator.cc b/src/tint/writer/text_generator.cc
index 8d18b9a..13a75d5 100644
--- a/src/tint/writer/text_generator.cc
+++ b/src/tint/writer/text_generator.cc
@@ -30,7 +30,7 @@
return builder_.Symbols().New(prefix).Name();
}
-std::string TextGenerator::StructName(const sem::Struct* s) {
+std::string TextGenerator::StructName(const type::Struct* s) {
auto name = s->Name().Name();
if (name.size() > 1 && name[0] == '_' && name[1] == '_') {
name = utils::GetOrCreate(builtin_struct_names_, s,
diff --git a/src/tint/writer/text_generator.h b/src/tint/writer/text_generator.h
index 34b93d4..04fe785 100644
--- a/src/tint/writer/text_generator.h
+++ b/src/tint/writer/text_generator.h
@@ -112,7 +112,7 @@
/// structures that start with double underscores. If the structure is a
/// builtin, then the returned name will be a unique name without the leading
/// underscores.
- std::string StructName(const sem::Struct* s);
+ std::string StructName(const type::Struct* s);
/// @param str the string
/// @param suffix the suffix to remove
@@ -221,7 +221,7 @@
/// The primary text buffer that the generator will emit
TextBuffer main_buffer_;
/// Map of builtin structure to unique generated name
- std::unordered_map<const sem::Struct*, std::string> builtin_struct_names_;
+ std::unordered_map<const type::Struct*, std::string> builtin_struct_names_;
};
} // namespace tint::writer
diff --git a/tint_overrides_with_defaults.gni b/tint_overrides_with_defaults.gni
index c54915d..977e433 100644
--- a/tint_overrides_with_defaults.gni
+++ b/tint_overrides_with_defaults.gni
@@ -77,6 +77,11 @@
tint_build_syntax_tree_writer = false
}
+ # Build the Tint IR
+ if (!defined(tint_build_ir)) {
+ tint_build_ir = false
+ }
+
# Build unittests
if (!defined(tint_build_unittests)) {
tint_build_unittests = true