Import Tint changes from Dawn
Changes:
- 7e0d9e6843de383e721d2c269d6a64e3537a244b [tint] Handle empty tables in intrinsic table data template by Ben Clayton <bclayton@google.com>
- 3c54ba593c7811c6ddcf5f61f8610187d210aa16 [tint][wgsl] Move LanguageFeature to a separate target by Ben Clayton <bclayton@google.com>
- 2e26e7a6f8f48e67d099c3237f53da5708197fc6 [tint][msl][ir] Use ValueToLet IR transform by Ben Clayton <bclayton@google.com>
- d9ffa54c787dbd790f4896bd522121a5c40b4ef4 [tint][ir] Add ValueToLet transform by Ben Clayton <bclayton@google.com>
- e6d2cd002804c1543b3ca60a25715d04a4e76c98 [tint][spirv] Add a SPIR-V writer IR fuzzer. by Ben Clayton <bclayton@google.com>
- fb6a9bcd2ce8771d696ee86ec41753b9ab5600aa [tint][ir] Remove default parameters for Operand() and Re... by Ben Clayton <bclayton@google.com>
- da8a08aefec265090b9aedbbeaea919b81395904 [tint][ir] Change Instruction::Result() return type by Ben Clayton <bclayton@google.com>
- 08396a3b9ac5c58fc0e86e3c3b53869228c8d6f9 [tint][ir] Add Builder overloads that take the type as a ... by Ben Clayton <bclayton@google.com>
- 6a235972b207be3b9e6395d02aff71141562885b [tint][cmake] Pass -Wno-gnu-zero-variadic-macro-arguments by Ben Clayton <bclayton@google.com>
- 84cd0f83d5f3661bd4d2f10287775e778589c14e [tint][ir] Always emit ir::Let for WGSL lets by Ben Clayton <bclayton@google.com>
- 7e6e44fbf9d65645056e8759bddcff259884fa11 [tint][wgsl] Migrate IR roundtrip fuzzer to be an IR fuzzer by Ben Clayton <bclayton@google.com>
- 339941969ddb111159ba1696728fdfe6e01783d4 [tint][fuzz] Add an IR fuzzer framework by Ben Clayton <bclayton@google.com>
- bfa79963bcdda05644bce8857f13b980f76655b1 [tint][spirv] Add a SPIR-V writer fuzzer from AST by Ben Clayton <bclayton@google.com>
- 881eff88cf623325bbb891a0c07c1ef0e0a612d2 [tint][spirv] Add validate library by Ben Clayton <bclayton@google.com>
- 5ee5f187deed9ef125de1e6177d95fdf7beb2967 [ir][msl] Run existing transforms which are required. by dan sinclair <dsinclair@chromium.org>
- 571cc4420ff93b2ff9ed49ef2c076191563c87df Remove chromium_experimental_read_write_storage_texture f... by Jiawei Shao <jiawei.shao@intel.com>
- 2a21ac0c3b4f4b18afb69aefbf7a390915b13ef2 [ir][msl] Add support for fragment inputs by dan sinclair <dsinclair@chromium.org>
- 71da3e8aa054ec1e8d36f65a07b975ad8d02de0f [ir][msl] Add thread and threadgroup position. by dan sinclair <dsinclair@chromium.org>
- 9ffc1d92cb4b6a599dc8803a9d84f28821c5b27d [ir][msl] Fix const of non-entrypoint pointers by dan sinclair <dsinclair@chromium.org>
- b4697b7658625f704b18f25f291a7e7557e90537 [ir][msl] Emit some core builtins. by dan sinclair <dsinclair@chromium.org>
- 050f08c3f5c84ba3721b26a6765e6084ce497f1e Fix TINT_FOREACH_13, _14 and _15 by Jiawei Shao <jiawei.shao@intel.com>
- 9aa5b553322a54c0ecd3c9eb71bf2d12ad8932b6 [tint] Fix Bazel config_setting_group definition by André Cruz <andre@cabine.org>
- aa5190b63b384a21e1eab9769a7069fe850a72fc [ir] Lower IR before dumping. by dan sinclair <dsinclair@chromium.org>
- 9cad74f4170393ee91dead059cd57b86bce70cb4 [ir][msl] Emit swizzle, load/store vector element instruc... by dan sinclair <dsinclair@chromium.org>
- af2c7345c2db8227dd83558eeb0095eb5af20db8 [ir] Rename InstructionResult::Source. by dan sinclair <dsinclair@chromium.org>
- 2e2bf672c68214f87aec7b8dfdefef943d67c23a [ir][msl] Emit switch instructions by dan sinclair <dsinclair@chromium.org>
- 3b4bf191b3afa8902d3a39c21e1bca76a8246752 [ir][msl] Emit loops by dan sinclair <dsinclair@chromium.org>
- b4ec73fd56384fd586caec2ae80af3b0fa144776 [ir][msl] Emit unary instructions by dan sinclair <dsinclair@chromium.org>
- 99204da719f0f1f76b79afb306ac6d5fa81269e2 [ir][msl] Emit function parameters by dan sinclair <dsinclair@chromium.org>
- a5460d0c97c7c07a49e65fdbfeed1af6ff41f7e4 [tint][utils] Fix diagnostic initializer_list ctor by Ben Clayton <bclayton@google.com>
- 624e8dd3ae8c510f85929e5e17db8591e19e2fb6 Add user call tests by dan sinclair <dsinclair@chromium.org>
- 5c69ff44659e270f174e132064ac0a2eaaab5fb0 [tint] Add tint_build_is_<OS> defines and build flags by Ben Clayton <bclayton@google.com>
- 1cc545189477077687e73b77aed757ad341bef8a [ir][msl] Emit ir::UserCall by dan sinclair <dsinclair@chromium.org>
- 3505ed4c5fc1eb6532562b14a77627249839843e Add struct index accessor tests by dan sinclair <dsinclair@chromium.org>
- 48318cd9d31a766fa5f60bca330ae65cc53a3c9c [ir][msl] Emit ir::Access by dan sinclair <dsinclair@chromium.org>
- 3aaaaf476d6cdc5cd859c1ba3a8b924c91efd88c [tint][wgsl][fuzz] Parse base64 encoded comments by Ben Clayton <bclayton@google.com>
- c97af9022e8442a2dbdea6716e190a04f3c18028 [tint][utils] Add DecodeBase64FromComments() by Ben Clayton <bclayton@google.com>
- b421e4039ddf914ca55a1be0468b138bf7dc188c [tint][wgsl][fuzz] Fix static init ordering bug by Ben Clayton <bclayton@google.com>
- ff67199151e64f4dc1f13a96aea80dd50c43d669 [tint][spirv] Add GenerateBindings() overload for IR modu... by Ben Clayton <bclayton@google.com>
- f0973d594afb2563f044085764c448042ab6b1e1 [tint][utils] Add DecodeBase64() helper by Ben Clayton <bclayton@google.com>
- 63eb5c8c26eef4692a2e99698e0b902cea82ecd0 [tint][utils] Add byte decoder by Ben Clayton <bclayton@google.com>
- e988749ee42d12307483ea2fc6b89895845012e6 [tint][wgsl][lower] Skip over dead instructions by Ben Clayton <bclayton@google.com>
- b098803b006d7d1bb7797fa08644acc9d31b6e1b [tint] Rename wgsl/wgsl_fuzz.* -> wgsl/fuzz.* by Ben Clayton <bclayton@google.com>
- 1b48e6b4e1c7f0192554d3225959b26b524acc9d [tint][utils] Add byte reader utility by Ben Clayton <bclayton@google.com>
- cea718c62b756d4cfce155460d5e629ca6918cf8 [ir][msl] Emit bitcast by dan sinclair <dsinclair@chromium.org>
- 1fa6a4beb24243ad86bba906eca9c09e4cbb200d [ir][msl] Emit entry point stage name by dan sinclair <dsinclair@chromium.org>
- 5555694d23e1507c24c76827003d765f6593ecf2 [ir][msl] Fixup binary emission by dan sinclair <dsinclair@chromium.org>
- 24b81095d4bd758b87fb548c2ca1a3dcae2a2d74 [ir] Move use of IR decision higher in the stack. by dan sinclair <dsinclair@chromium.org>
- 58794b5dfa9d81ef14122e3fbc85382664541b20 [ir][msl] Simplify expression emission in MSL printer. by dan sinclair <dsinclair@chromium.org>
- 7bbe4c1696f2433d7228877d451b812e23c4adff [ir][msl] Add `construct` to MSL IR printer by dan sinclair <dsinclair@chromium.org>
- 019146fbc300c5bd704dae7e198714ff774236d3 [ir] Add an IR option into the ICE machinery. by dan sinclair <dsinclair@chromium.org>
- acef3106912878e0b93c0f969c80020853fcbbb1 [tint][ir] Add ConstPropagatingPtr - const-propagating ptr by Ben Clayton <bclayton@google.com>
- eee3ad04f703c90c7af1a8f0ea358231247f955a [ir][msl] Add `discard` to MSL IR printer by dan sinclair <dsinclair@chromium.org>
- 37e9d111b375bd014cb0e1236436b8eeea8da45a [tint] Namespace the strconv files by dan sinclair <dsinclair@chromium.org>
- 1e7b312706ad214eb09007f77521488f0a409991 [tint][ir] Use 'const' on non-mutating IR consumers by Ben Clayton <bclayton@google.com>
- c33fdbb0a4f4a8301551019596101c05e38249b3 Remove chromium_experimental_read_write_storage_texture by Jiawei Shao <jiawei.shao@intel.com>
- ead8a043e377273b24e6c788007e6a7d15cf1093 [tint][ir] Add 'const' accessors by Ben Clayton <bclayton@google.com>
- 1c483bfabb8685b5c1ff8c50b4d41677708b0d53 [spirv-writer] Fix atomics after discard by James Price <jrprice@google.com>
- 69298a3abdb3e788e05931e961cb2337aab70c23 [spirv-writer] Fix implicit blocks with results by James Price <jrprice@google.com>
- ffbcc3584f07dae21ff696bbdc9fdd26127e425f [tint][wgsl] Move RenameConflicts out of IrToProgram by Ben Clayton <bclayton@google.com>
- a166dcb470df81ce26f1fde0fc3bc071c90aca87 [tint][ir] Simplify ir::Switch case generation by Ben Clayton <bclayton@google.com>
- a89d6647f696b240bfd2861d79c7dba7d856dcb5 [tint][ir] Refactor Instruction result methods by Ben Clayton <bclayton@google.com>
- fb07fa9e8877d3f7934ec972a4e7bd3a44e0a78c [build] Add guards for protobuf by Ben Clayton <bclayton@google.com>
- e6744dbe784dbba68a866c3e6cf219ac616bfc40 [tint][utils] Add Vector(const Slice<const T>&) constructor by Ben Clayton <bclayton@google.com>
- 0e21d289202eea9f08d14ca32cf3cdfa2cac8cca [ir] Fix Std140 for non-decomposed matrices by James Price <jrprice@google.com>
- b9d3e1c8448ac3dc37fa2eac24d668dc1199b928 [tint][ir] Remove Block::HasTerminator() by Ben Clayton <bclayton@google.com>
- 2e4b301ab516935dd2afc7e6e161e628a7ab2c43 [tint][utils] Vector improvements by Ben Clayton <bclayton@google.com>
- 96687ce6fe09763f997a9ee5c345d04162a87451 [tint][ir] Remove Usage::Hasher by Ben Clayton <bclayton@google.com>
- a86a8230eab47ce501c4bb4eb01b6cad5a9f456f [tint][utils] Change SymbolTable::Wrap() to be a static m... by Ben Clayton <bclayton@google.com>
- 095c7c067792c0dc868a84f72b356723a43235d0 [tint][ir] Remove Module::disassembly_file by Ben Clayton <bclayton@google.com>
- f2de7ead699d34b1ef8aa43398d5488ba67f018b [tint] Add build support for protobufs by Ben Clayton <bclayton@google.com>
- 429e97b6d3f8caddd198154d0ad63c7ed5e96615 [tint][utils] Remove stray '+' by Ben Clayton <bclayton@google.com>
- d67c378f26a756649984b6bd0eda1d752377e7e1 Revert "[msl] Remove PixelLocal as printer supported exte... by Ben Clayton <bclayton@google.com>
- a87d06317a67c25c0676fc47fff87d9146622b5e Tint/HLSL: Support translating pixel local variables on H... by Jiawei Shao <jiawei.shao@intel.com>
- 5896e7501bf3a0dccb12f146949195d461d4a71e [tint] Namespace the socket files by dan sinclair <dsinclair@chromium.org>
- e5f014098bf1706bbf04f5a507ee8b8d04cbfba5 [msl] Remove PixelLocal as printer supported extension by Ben Clayton <bclayton@google.com>
- 99672e2bf1edb05cc52a2fa5e9128952fd3a93e8 Use result type to handle diagnostics by dan sinclair <dsinclair@chromium.org>
GitOrigin-RevId: 7e0d9e6843de383e721d2c269d6a64e3537a244b
Change-Id: Ic95378ba1d4e9efdc50c770088125baebd62efa5
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/161020
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index d083bef..6f78959 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -108,6 +108,24 @@
defines += [ "TINT_BUILD_SYNTAX_TREE_WRITER=0" ]
}
+ if (tint_build_is_win) {
+ defines += [ "TINT_BUILD_IS_WIN=1" ]
+ } else {
+ defines += [ "TINT_BUILD_IS_WIN=0" ]
+ }
+
+ if (tint_build_is_mac) {
+ defines += [ "TINT_BUILD_IS_MAC=1" ]
+ } else {
+ defines += [ "TINT_BUILD_IS_MAC=0" ]
+ }
+
+ if (tint_build_is_linux) {
+ defines += [ "TINT_BUILD_IS_LINUX=1" ]
+ } else {
+ defines += [ "TINT_BUILD_IS_LINUX=0" ]
+ }
+
include_dirs = [
"${tint_root_dir}/",
"${tint_root_dir}/include/",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 3a47bd1..208a231 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -30,14 +30,14 @@
################################################################################
if(NOT TINT_BUILD_AS_OTHER_OS)
if(APPLE) # Must come before UNIX
- set(IS_MAC TRUE)
- set(IS_MAC TRUE)
+ set(TINT_BUILD_IS_MAC TRUE)
+ set(TINT_BUILD_IS_MAC TRUE)
elseif(UNIX)
- set(IS_LINUX TRUE)
- set(IS_LINUX TRUE)
+ set(TINT_BUILD_IS_LINUX TRUE)
+ set(TINT_BUILD_IS_LINUX TRUE)
elseif(WIN32)
- set(IS_WIN TRUE)
- set(IS_WIN TRUE)
+ set(TINT_BUILD_IS_WIN TRUE)
+ set(TINT_BUILD_IS_WIN TRUE)
endif()
endif()
@@ -47,15 +47,19 @@
function(tint_core_compile_options TARGET)
target_include_directories(${TARGET} PUBLIC "${TINT_ROOT_SOURCE_DIR}")
target_include_directories(${TARGET} PUBLIC "${TINT_ROOT_SOURCE_DIR}/include")
- target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_SPV_READER=$<BOOL:${TINT_BUILD_SPV_READER}>)
- target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_WGSL_READER=$<BOOL:${TINT_BUILD_WGSL_READER}>)
- target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_GLSL_WRITER=$<BOOL:${TINT_BUILD_GLSL_WRITER}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_GLSL_VALIDATOR=$<BOOL:${TINT_BUILD_GLSL_VALIDATOR}>)
+ target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_GLSL_WRITER=$<BOOL:${TINT_BUILD_GLSL_WRITER}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_HLSL_WRITER=$<BOOL:${TINT_BUILD_HLSL_WRITER}>)
+ target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_IS_LINUX=$<BOOL:${TINT_BUILD_IS_LINUX}>)
+ target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_IS_MAC=$<BOOL:${TINT_BUILD_IS_MAC}>)
+ target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_IS_WIN=$<BOOL:${TINT_BUILD_IS_WIN}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_MSL_WRITER=$<BOOL:${TINT_BUILD_MSL_WRITER}>)
+ target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_SPV_READER=$<BOOL:${TINT_BUILD_SPV_READER}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_SPV_WRITER=$<BOOL:${TINT_BUILD_SPV_WRITER}>)
- target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_WGSL_WRITER=$<BOOL:${TINT_BUILD_WGSL_WRITER}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_SYNTAX_TREE_WRITER=$<BOOL:${TINT_BUILD_SYNTAX_TREE_WRITER}>)
+ target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_WGSL_READER=$<BOOL:${TINT_BUILD_WGSL_READER}>)
+ target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_WGSL_WRITER=$<BOOL:${TINT_BUILD_WGSL_WRITER}>)
+
if(TINT_BUILD_FUZZERS)
target_compile_options(${TARGET} PRIVATE "-fsanitize=fuzzer")
@@ -83,10 +87,11 @@
-Wno-c++98-compat
-Wno-c++98-compat-pedantic
-Wno-format-pedantic
+ -Wno-gnu-zero-variadic-macro-arguments
-Wno-poison-system-directories
-Wno-return-std-move-in-c++11
- -Wno-unknown-warning-option
-Wno-undefined-var-template
+ -Wno-unknown-warning-option
-Wno-unsafe-buffer-usage
-Wno-used-but-marked-unused
-Weverything
@@ -177,6 +182,26 @@
target_include_directories(${TARGET} PRIVATE "${TINT_SPIRV_TOOLS_DIR}/include")
endfunction()
+function(tint_lib_compile_options TARGET)
+ if (TINT_ENABLE_INSTALL)
+ install(TARGETS ${TARGET}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+ endif()
+ tint_default_compile_options(${TARGET})
+endfunction()
+
+function(tint_proto_compile_options TARGET)
+ if (TINT_ENABLE_INSTALL)
+ install(TARGETS ${TARGET}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+ endif()
+ tint_core_compile_options(${TARGET})
+endfunction()
+
function(tint_test_compile_options TARGET)
tint_default_compile_options(${TARGET})
set_target_properties(${TARGET} PROPERTIES FOLDER "Tests")
@@ -324,7 +349,7 @@
if(TINT_BUILD_CMD_TOOLS)
set(IS_ENABLED TRUE PARENT_SCOPE)
endif()
- elseif(${KIND} STREQUAL lib)
+ elseif((${KIND} STREQUAL lib) OR (${KIND} STREQUAL proto))
set(IS_ENABLED TRUE PARENT_SCOPE)
elseif((${KIND} STREQUAL test) OR (${KIND} STREQUAL test_cmd))
if(TINT_BUILD_TESTS)
@@ -363,13 +388,12 @@
if(${KIND} STREQUAL lib)
add_library(${TARGET} STATIC EXCLUDE_FROM_ALL)
- if (TINT_ENABLE_INSTALL)
- install(TARGETS ${TARGET}
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
- )
- endif()
- tint_default_compile_options(${TARGET})
+ tint_lib_compile_options(${TARGET})
+ elseif(${KIND} STREQUAL proto)
+ add_library(${TARGET} STATIC EXCLUDE_FROM_ALL)
+ list(APPEND TINT_PROTO_TARGETS ${TARGET})
+ set(TINT_PROTO_TARGETS ${TINT_PROTO_TARGETS} PARENT_SCOPE)
+ tint_proto_compile_options(${TARGET})
elseif(${KIND} STREQUAL cmd)
add_executable(${TARGET})
tint_default_compile_options(${TARGET})
@@ -611,6 +635,19 @@
################################################################################
+# Generate protobuf sources
+################################################################################
+foreach(PROTO_TARGET ${TINT_PROTO_TARGETS})
+ generate_protos(
+ TARGET ${PROTO_TARGET}
+ PROTOC_OUT_DIR "${DAWN_BUILD_GEN_DIR}/src/tint/")
+ target_include_directories(${PROTO_TARGET} PRIVATE "${DAWN_BUILD_GEN_DIR}/src/tint/")
+ target_include_directories(${PROTO_TARGET} PUBLIC "${DAWN_BUILD_GEN_DIR}")
+ target_link_libraries(${PROTO_TARGET} libprotobuf)
+endforeach()
+
+
+################################################################################
# Bespoke target settings
################################################################################
if (MSVC)
diff --git a/src/tint/api/BUILD.bazel b/src/tint/api/BUILD.bazel
index 8853b01..22d06eb 100644
--- a/src/tint/api/BUILD.bazel
+++ b/src/tint/api/BUILD.bazel
@@ -56,6 +56,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/api/BUILD.cmake b/src/tint/api/BUILD.cmake
index 570309b..dea891a 100644
--- a/src/tint/api/BUILD.cmake
+++ b/src/tint/api/BUILD.cmake
@@ -58,6 +58,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/api/BUILD.gn b/src/tint/api/BUILD.gn
index 87b72d7..4c3586f 100644
--- a/src/tint/api/BUILD.gn
+++ b/src/tint/api/BUILD.gn
@@ -55,6 +55,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/api/options/pixel_local.h b/src/tint/api/options/pixel_local.h
index 720fcb6..d8f22ce 100644
--- a/src/tint/api/options/pixel_local.h
+++ b/src/tint/api/options/pixel_local.h
@@ -39,8 +39,21 @@
/// Index of pixel_local structure member index to attachment index
std::unordered_map<uint32_t, uint32_t> attachments;
+ /// The supported pixel local storage attachment format
+ enum class TexelFormat : uint8_t {
+ kR32Sint,
+ kR32Uint,
+ kR32Float,
+ kUndefined,
+ };
+ /// Index of pixel_local structure member index to pixel local storage attachment format
+ std::unordered_map<uint32_t, TexelFormat> attachment_formats;
+
+ /// The bind group index of all pixel local storage attachments
+ uint32_t pixel_local_group_index;
+
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(attachments);
+ TINT_REFLECT(attachments, attachment_formats, pixel_local_group_index);
};
} // namespace tint
diff --git a/src/tint/cmd/bench/BUILD.bazel b/src/tint/cmd/bench/BUILD.bazel
index 9a81f43..df4a15f 100644
--- a/src/tint/cmd/bench/BUILD.bazel
+++ b/src/tint/cmd/bench/BUILD.bazel
@@ -53,6 +53,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/cmd/bench/BUILD.cmake b/src/tint/cmd/bench/BUILD.cmake
index 50d1d83..0af9aa2 100644
--- a/src/tint/cmd/bench/BUILD.cmake
+++ b/src/tint/cmd/bench/BUILD.cmake
@@ -129,6 +129,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/cmd/bench/BUILD.gn b/src/tint/cmd/bench/BUILD.gn
index ae16dad..5143ce9 100644
--- a/src/tint/cmd/bench/BUILD.gn
+++ b/src/tint/cmd/bench/BUILD.gn
@@ -58,6 +58,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/cmd/common/BUILD.bazel b/src/tint/cmd/common/BUILD.bazel
index b15b369..acade5c 100644
--- a/src/tint/cmd/common/BUILD.bazel
+++ b/src/tint/cmd/common/BUILD.bazel
@@ -57,6 +57,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/inspector",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
@@ -113,6 +114,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/cmd/common/BUILD.cmake b/src/tint/cmd/common/BUILD.cmake
index 7545e63..b795733 100644
--- a/src/tint/cmd/common/BUILD.cmake
+++ b/src/tint/cmd/common/BUILD.cmake
@@ -56,6 +56,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_inspector
tint_lang_wgsl_program
tint_lang_wgsl_sem
@@ -116,6 +117,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
diff --git a/src/tint/cmd/common/BUILD.gn b/src/tint/cmd/common/BUILD.gn
index a6980f0..99229d6 100644
--- a/src/tint/cmd/common/BUILD.gn
+++ b/src/tint/cmd/common/BUILD.gn
@@ -60,6 +60,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/inspector",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
@@ -111,6 +112,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/cmd/fuzz/BUILD.cmake b/src/tint/cmd/fuzz/BUILD.cmake
index 65795ac..65ca459 100644
--- a/src/tint/cmd/fuzz/BUILD.cmake
+++ b/src/tint/cmd/fuzz/BUILD.cmake
@@ -34,4 +34,5 @@
# Do not modify this file directly
################################################################################
+include(cmd/fuzz/ir/BUILD.cmake)
include(cmd/fuzz/wgsl/BUILD.cmake)
diff --git a/src/tint/cmd/fuzz/ir/BUILD.bazel b/src/tint/cmd/fuzz/ir/BUILD.bazel
new file mode 100644
index 0000000..7c71462
--- /dev/null
+++ b/src/tint/cmd/fuzz/ir/BUILD.bazel
@@ -0,0 +1,44 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+
+alias(
+ name = "tint_build_wgsl_reader",
+ actual = "//src/tint:tint_build_wgsl_reader_true",
+)
+
diff --git a/src/tint/cmd/fuzz/ir/BUILD.cmake b/src/tint/cmd/fuzz/ir/BUILD.cmake
new file mode 100644
index 0000000..96fbb4b
--- /dev/null
+++ b/src/tint/cmd/fuzz/ir/BUILD.cmake
@@ -0,0 +1,80 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+################################################################################
+# Target: tint_cmd_fuzz_ir_fuzz
+# Kind: fuzz
+################################################################################
+tint_add_target(tint_cmd_fuzz_ir_fuzz fuzz
+ cmd/fuzz/ir/fuzz.cc
+ cmd/fuzz/ir/fuzz.h
+)
+
+tint_target_add_dependencies(tint_cmd_fuzz_ir_fuzz fuzz
+ tint_api_common
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_ir
+ tint_lang_core_type
+ tint_lang_wgsl
+ tint_lang_wgsl_ast
+ tint_lang_wgsl_common
+ tint_lang_wgsl_features
+ tint_lang_wgsl_helpers
+ tint_lang_wgsl_program
+ tint_lang_wgsl_sem
+ tint_utils_bytes
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_symbol
+ tint_utils_text
+ tint_utils_traits
+)
+
+if(TINT_BUILD_WGSL_READER)
+ tint_target_add_dependencies(tint_cmd_fuzz_ir_fuzz fuzz
+ tint_cmd_fuzz_wgsl_fuzz
+ tint_lang_wgsl_reader
+ )
+endif(TINT_BUILD_WGSL_READER)
diff --git a/src/tint/cmd/fuzz/ir/BUILD.gn b/src/tint/cmd/fuzz/ir/BUILD.gn
new file mode 100644
index 0000000..9063f19
--- /dev/null
+++ b/src/tint/cmd/fuzz/ir/BUILD.gn
@@ -0,0 +1,81 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+import("../../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+
+tint_fuzz_source_set("fuzz") {
+ sources = [
+ "fuzz.cc",
+ "fuzz.h",
+ ]
+ deps = [
+ "${tint_src_dir}/api/common",
+ "${tint_src_dir}/lang/core",
+ "${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/lang/wgsl",
+ "${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
+ "${tint_src_dir}/lang/wgsl/helpers",
+ "${tint_src_dir}/lang/wgsl/program",
+ "${tint_src_dir}/lang/wgsl/sem",
+ "${tint_src_dir}/utils/bytes",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+
+ if (tint_build_wgsl_reader) {
+ deps += [
+ "${tint_src_dir}/cmd/fuzz/wgsl:fuzz",
+ "${tint_src_dir}/lang/wgsl/reader",
+ ]
+ }
+}
diff --git a/src/tint/cmd/fuzz/ir/fuzz.cc b/src/tint/cmd/fuzz/ir/fuzz.cc
new file mode 100644
index 0000000..fc96dcc
--- /dev/null
+++ b/src/tint/cmd/fuzz/ir/fuzz.cc
@@ -0,0 +1,100 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/cmd/fuzz/ir/fuzz.h"
+
+#include "src/tint/utils/containers/vector.h"
+
+#if TINT_BUILD_WGSL_READER
+#include "src/tint/cmd/fuzz/wgsl/fuzz.h"
+#include "src/tint/lang/wgsl/ast/enable.h"
+#include "src/tint/lang/wgsl/ast/module.h"
+#include "src/tint/lang/wgsl/helpers/apply_substitute_overrides.h"
+#include "src/tint/lang/wgsl/reader/reader.h"
+#endif
+
+#include "src/tint/lang/core/ir/validator.h"
+
+#if TINT_BUILD_WGSL_READER
+namespace tint::fuzz::ir {
+namespace {
+
+bool IsUnsupported(const ast::Enable* enable) {
+ for (auto ext : enable->extensions) {
+ switch (ext->name) {
+ case tint::wgsl::Extension::kChromiumExperimentalDp4A:
+ case tint::wgsl::Extension::kChromiumExperimentalFullPtrParameters:
+ case tint::wgsl::Extension::kChromiumExperimentalPixelLocal:
+ case tint::wgsl::Extension::kChromiumExperimentalPushConstant:
+ case tint::wgsl::Extension::kChromiumInternalDualSourceBlending:
+ case tint::wgsl::Extension::kChromiumInternalRelaxedUniformLayout:
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+void Register(const IRFuzzer& fuzzer) {
+ wgsl::Register({
+ fuzzer.name,
+ [fn = fuzzer.fn](const Program& program, Slice<const std::byte> data) {
+ if (program.AST().Enables().Any(IsUnsupported)) {
+ return;
+ }
+
+ auto transformed = tint::wgsl::ApplySubstituteOverrides(program);
+ auto& src = transformed ? transformed.value() : program;
+ if (!src.IsValid()) {
+ return;
+ }
+
+ auto ir = tint::wgsl::reader::ProgramToLoweredIR(src);
+ if (!ir) {
+ return;
+ }
+
+ if (auto val = core::ir::Validate(ir.Get()); !val) {
+ TINT_ICE() << val.Failure();
+ return;
+ }
+
+ return fn(ir.Get(), data);
+ },
+ });
+}
+
+} // namespace tint::fuzz::ir
+
+#else
+
+void tint::fuzz::ir::Register([[maybe_unused]] const IRFuzzer&) {}
+
+#endif
diff --git a/src/tint/cmd/fuzz/ir/fuzz.h b/src/tint/cmd/fuzz/ir/fuzz.h
new file mode 100644
index 0000000..897f6e1
--- /dev/null
+++ b/src/tint/cmd/fuzz/ir/fuzz.h
@@ -0,0 +1,89 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_CMD_FUZZ_IR_FUZZ_H_
+#define SRC_TINT_CMD_FUZZ_IR_FUZZ_H_
+
+#include <functional>
+#include <string>
+#include <tuple>
+#include <utility>
+
+#include "src/tint/utils/bytes/decoder.h"
+#include "src/tint/utils/containers/slice.h"
+#include "src/tint/utils/macros/static_init.h"
+
+namespace tint::core::ir {
+class Module;
+}
+
+namespace tint::fuzz::ir {
+
+/// IRFuzzer describes a fuzzer function that takes a IR module as input
+struct IRFuzzer {
+ /// @param name the name of the fuzzer
+ /// @param fn the fuzzer function
+ /// @returns an IRFuzzer that invokes the function @p fn with the IR module, along with any
+ /// additional arguments which are deserialized from the fuzzer input.
+ template <typename... ARGS>
+ static IRFuzzer Create(std::string_view name, void (*fn)(core::ir::Module&, ARGS...)) {
+ if constexpr (sizeof...(ARGS) > 0) {
+ auto fn_with_decode = [fn](core::ir::Module& module, Slice<const std::byte> data) {
+ bytes::Reader reader{data};
+ if (auto data_args = bytes::Decode<std::tuple<std::decay_t<ARGS>...>>(reader)) {
+ auto all_args =
+ std::tuple_cat(std::tuple<core::ir::Module&>{module}, data_args.Get());
+ std::apply(*fn, all_args);
+ }
+ };
+ return IRFuzzer{name, std::move(fn_with_decode)};
+ } else {
+ return IRFuzzer{
+ name,
+ [fn](core::ir::Module& module, Slice<const std::byte>) { fn(module); },
+ };
+ }
+ }
+
+ /// Name of the fuzzer function
+ std::string_view name;
+ /// The fuzzer function
+ std::function<void(core::ir::Module&, Slice<const std::byte> data)> fn;
+};
+
+/// Registers the fuzzer function with the IR fuzzer executable.
+/// @param fuzzer the fuzzer
+void Register(const IRFuzzer& fuzzer);
+
+/// TINT_IR_MODULE_FUZZER registers the fuzzer function.
+#define TINT_IR_MODULE_FUZZER(FUNCTION) \
+ TINT_STATIC_INIT( \
+ ::tint::fuzz::ir::Register(::tint::fuzz::ir::IRFuzzer::Create(#FUNCTION, FUNCTION)))
+
+} // namespace tint::fuzz::ir
+
+#endif // SRC_TINT_CMD_FUZZ_IR_FUZZ_H_
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.bazel b/src/tint/cmd/fuzz/wgsl/BUILD.bazel
index 4c77253..c3cbe15 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.bazel
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.bazel
@@ -38,6 +38,11 @@
load("@bazel_skylib//lib:selects.bzl", "selects")
alias(
+ name = "tint_build_spv_writer",
+ actual = "//src/tint:tint_build_spv_writer_true",
+)
+
+alias(
name = "tint_build_wgsl_reader",
actual = "//src/tint:tint_build_wgsl_reader_true",
)
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.cmake b/src/tint/cmd/fuzz/wgsl/BUILD.cmake
index eb85247..4da9274 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.cmake
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.cmake
@@ -45,6 +45,7 @@
)
tint_target_add_dependencies(tint_cmd_fuzz_wgsl_fuzz_cmd fuzz_cmd
+ tint_cmd_fuzz_ir_fuzz
tint_lang_core
tint_lang_core_constant
tint_lang_core_type
@@ -54,6 +55,7 @@
tint_lang_wgsl_program_fuzz
tint_lang_wgsl_sem
tint_lang_wgsl_fuzz
+ tint_utils_bytes
tint_utils_cli
tint_utils_containers
tint_utils_diagnostic
@@ -62,6 +64,7 @@
tint_utils_macros
tint_utils_math
tint_utils_memory
+ tint_utils_reflection
tint_utils_result
tint_utils_rtti
tint_utils_strconv
@@ -70,6 +73,12 @@
tint_utils_traits
)
+if(TINT_BUILD_SPV_WRITER)
+ tint_target_add_dependencies(tint_cmd_fuzz_wgsl_fuzz_cmd fuzz_cmd
+ tint_lang_spirv_writer_fuzz
+ )
+endif(TINT_BUILD_SPV_WRITER)
+
if(TINT_BUILD_WGSL_READER)
tint_target_add_dependencies(tint_cmd_fuzz_wgsl_fuzz_cmd fuzz_cmd
tint_cmd_fuzz_wgsl_fuzz
@@ -93,8 +102,8 @@
# Condition: TINT_BUILD_WGSL_READER
################################################################################
tint_add_target(tint_cmd_fuzz_wgsl_fuzz fuzz
- cmd/fuzz/wgsl/wgsl_fuzz.cc
- cmd/fuzz/wgsl/wgsl_fuzz.h
+ cmd/fuzz/wgsl/fuzz.cc
+ cmd/fuzz/wgsl/fuzz.h
)
tint_target_add_dependencies(tint_cmd_fuzz_wgsl_fuzz fuzz
@@ -106,8 +115,10 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
+ tint_utils_bytes
tint_utils_containers
tint_utils_diagnostic
tint_utils_ice
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.gn b/src/tint/cmd/fuzz/wgsl/BUILD.gn
index b55e57f..f4bec4d 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.gn
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.gn
@@ -40,8 +40,8 @@
if (tint_build_wgsl_reader) {
tint_fuzz_source_set("fuzz") {
sources = [
- "wgsl_fuzz.cc",
- "wgsl_fuzz.h",
+ "fuzz.cc",
+ "fuzz.h",
]
deps = [
"${tint_src_dir}:thread",
@@ -53,8 +53,10 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
+ "${tint_src_dir}/utils/bytes",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
"${tint_src_dir}/utils/ice",
@@ -80,6 +82,7 @@
output_name = "tint_wgsl_fuzzer"
sources = [ "main_fuzz.cc" ]
deps = [
+ "${tint_src_dir}/cmd/fuzz/ir:fuzz",
"${tint_src_dir}/lang/core",
"${tint_src_dir}/lang/core/constant",
"${tint_src_dir}/lang/core/type",
@@ -89,6 +92,7 @@
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/program:fuzz",
"${tint_src_dir}/lang/wgsl/sem",
+ "${tint_src_dir}/utils/bytes",
"${tint_src_dir}/utils/cli",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
@@ -97,6 +101,7 @@
"${tint_src_dir}/utils/macros",
"${tint_src_dir}/utils/math",
"${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
"${tint_src_dir}/utils/result",
"${tint_src_dir}/utils/rtti",
"${tint_src_dir}/utils/strconv",
@@ -105,6 +110,10 @@
"${tint_src_dir}/utils/traits",
]
+ if (tint_build_spv_writer) {
+ deps += [ "${tint_src_dir}/lang/spirv/writer:fuzz" ]
+ }
+
if (tint_build_wgsl_reader) {
deps += [
"${tint_src_dir}/cmd/fuzz/wgsl:fuzz",
diff --git a/src/tint/cmd/fuzz/wgsl/wgsl_fuzz.cc b/src/tint/cmd/fuzz/wgsl/fuzz.cc
similarity index 79%
rename from src/tint/cmd/fuzz/wgsl/wgsl_fuzz.cc
rename to src/tint/cmd/fuzz/wgsl/fuzz.cc
index 69d3587..d6b90ec 100644
--- a/src/tint/cmd/fuzz/wgsl/wgsl_fuzz.cc
+++ b/src/tint/cmd/fuzz/wgsl/fuzz.cc
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "src/tint/cmd/fuzz/wgsl/wgsl_fuzz.h"
+#include "src/tint/cmd/fuzz/wgsl/fuzz.h"
#include <iostream>
#include <thread>
@@ -38,7 +38,14 @@
namespace tint::fuzz::wgsl {
namespace {
-Vector<ProgramFuzzer, 32> fuzzers;
+/// @returns a reference to the static list of registered ProgramFuzzers.
+/// @note this is not a global, as the static initializers that register fuzzers may be called
+/// before this vector is constructed.
+Vector<ProgramFuzzer, 32>& Fuzzers() {
+ static Vector<ProgramFuzzer, 32> fuzzers;
+ return fuzzers;
+}
+
thread_local std::string_view currently_running;
[[noreturn]] void TintInternalCompilerErrorReporter(const tint::InternalCompilerError& err) {
@@ -50,15 +57,15 @@
} // namespace
void Register(const ProgramFuzzer& fuzzer) {
- fuzzers.Push(fuzzer);
+ Fuzzers().Push(fuzzer);
}
-void Run(std::string_view wgsl, const Options& options) {
+void Run(std::string_view wgsl, Slice<const std::byte> data, const Options& options) {
tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
// Ensure that fuzzers are sorted. Without this, the fuzzers may be registered in any order,
// leading to non-determinism, which we must avoid.
- TINT_STATIC_INIT(fuzzers.Sort([](auto& a, auto& b) { return a.name < b.name; }));
+ TINT_STATIC_INIT(Fuzzers().Sort([](auto& a, auto& b) { return a.name < b.name; }));
// Create a Source::File to hand to the parser.
tint::Source::File file("test.wgsl", wgsl);
@@ -71,14 +78,14 @@
// Run each of the program fuzzer functions
if (options.run_concurrently) {
- size_t n = fuzzers.Length();
+ size_t n = Fuzzers().Length();
tint::Vector<std::thread, 32> threads;
threads.Resize(n);
for (size_t i = 0; i < n; i++) {
- threads[i] = std::thread([i, &program] {
- auto& fuzzer = fuzzers[i];
+ threads[i] = std::thread([i, &program, &data] {
+ auto& fuzzer = Fuzzers()[i];
currently_running = fuzzer.name;
- fuzzer.fn(program);
+ fuzzer.fn(program, data);
});
}
for (auto& thread : threads) {
@@ -86,9 +93,9 @@
}
} else {
TINT_DEFER(currently_running = "");
- for (auto& fuzzer : fuzzers) {
+ for (auto& fuzzer : Fuzzers()) {
currently_running = fuzzer.name;
- fuzzer.fn(program);
+ fuzzer.fn(program, data);
}
}
}
diff --git a/src/tint/cmd/fuzz/wgsl/fuzz.h b/src/tint/cmd/fuzz/wgsl/fuzz.h
new file mode 100644
index 0000000..744ceb5
--- /dev/null
+++ b/src/tint/cmd/fuzz/wgsl/fuzz.h
@@ -0,0 +1,98 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_CMD_FUZZ_WGSL_FUZZ_H_
+#define SRC_TINT_CMD_FUZZ_WGSL_FUZZ_H_
+
+#include <string>
+#include <tuple>
+#include <utility>
+
+#include "src/tint/lang/wgsl/program/program.h"
+#include "src/tint/utils/bytes/decoder.h"
+#include "src/tint/utils/containers/slice.h"
+#include "src/tint/utils/macros/static_init.h"
+#include "src/tint/utils/reflection/reflection.h"
+
+namespace tint::fuzz::wgsl {
+
+/// ProgramFuzzer describes a fuzzer function that takes a WGSL program as input
+struct ProgramFuzzer {
+ /// @param name the name of the fuzzer
+ /// @param fn the fuzzer function
+ /// @returns a ProgramFuzzer that invokes the function @p fn with the Program, along with any
+ /// additional arguments which are deserialized from the fuzzer input.
+ template <typename... ARGS>
+ static ProgramFuzzer Create(std::string_view name, void (*fn)(const Program&, ARGS...)) {
+ if constexpr (sizeof...(ARGS) > 0) {
+ auto fn_with_decode = [fn](const Program& program, Slice<const std::byte> data) {
+ bytes::Reader reader{data};
+ if (auto data_args = bytes::Decode<std::tuple<std::decay_t<ARGS>...>>(reader)) {
+ auto all_args =
+ std::tuple_cat(std::tuple<const Program&>{program}, data_args.Get());
+ std::apply(*fn, all_args);
+ }
+ };
+ return ProgramFuzzer{name, std::move(fn_with_decode)};
+ } else {
+ return ProgramFuzzer{
+ name,
+ [fn](const Program& program, Slice<const std::byte>) { fn(program); },
+ };
+ }
+ }
+
+ /// Name of the fuzzer function
+ std::string_view name;
+ /// The fuzzer function
+ std::function<void(const Program&, Slice<const std::byte> data)> fn;
+};
+
+/// Options for Run()
+struct Options {
+ /// If true, the fuzzers will be run concurrently on separate threads.
+ bool run_concurrently = false;
+};
+
+/// Runs all the registered WGSL fuzzers with the supplied WGSL
+/// @param wgsl the input WGSL
+/// @param data additional data used for fuzzing
+/// @param options the options for running the fuzzers
+void Run(std::string_view wgsl, Slice<const std::byte> data, const Options& options);
+
+/// Registers the fuzzer function with the WGSL fuzzer executable.
+/// @param fuzzer the fuzzer
+void Register(const ProgramFuzzer& fuzzer);
+
+/// TINT_WGSL_PROGRAM_FUZZER registers the fuzzer function to run as part of `tint_wgsl_fuzzer`
+#define TINT_WGSL_PROGRAM_FUZZER(FUNCTION) \
+ TINT_STATIC_INIT(::tint::fuzz::wgsl::Register( \
+ ::tint::fuzz::wgsl::ProgramFuzzer::Create(#FUNCTION, FUNCTION)))
+
+} // namespace tint::fuzz::wgsl
+
+#endif // SRC_TINT_CMD_FUZZ_WGSL_FUZZ_H_
diff --git a/src/tint/cmd/fuzz/wgsl/main_fuzz.cc b/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
index fa27edc..1edcd04 100644
--- a/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
+++ b/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
@@ -27,19 +27,22 @@
#include <iostream>
-#include "src/tint/cmd/fuzz/wgsl/wgsl_fuzz.h"
+#include "src/tint/cmd/fuzz/wgsl/fuzz.h"
#include "src/tint/utils/cli/cli.h"
+#include "src/tint/utils/macros/defer.h"
+#include "src/tint/utils/text/base64.h"
namespace {
tint::fuzz::wgsl::Options options;
-}
+} // namespace
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* input, size_t size) {
if (size > 0) {
- std::string_view wgsl(reinterpret_cast<const char*>(data), size);
- tint::fuzz::wgsl::Run(wgsl, options);
+ std::string_view wgsl(reinterpret_cast<const char*>(input), size);
+ auto data = tint::DecodeBase64FromComments(wgsl);
+ tint::fuzz::wgsl::Run(wgsl, data.Slice(), options);
}
return 0;
}
diff --git a/src/tint/cmd/fuzz/wgsl/wgsl_fuzz.h b/src/tint/cmd/fuzz/wgsl/wgsl_fuzz.h
deleted file mode 100644
index 909c394..0000000
--- a/src/tint/cmd/fuzz/wgsl/wgsl_fuzz.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2023 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-// list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef SRC_TINT_CMD_FUZZ_WGSL_WGSL_FUZZ_H_
-#define SRC_TINT_CMD_FUZZ_WGSL_WGSL_FUZZ_H_
-
-#include <string>
-
-#include "src/tint/lang/wgsl/program/program.h"
-#include "src/tint/utils/containers/slice.h"
-#include "src/tint/utils/macros/static_init.h"
-
-namespace tint::fuzz::wgsl {
-
-/// ProgramFuzzer describes a fuzzer function that takes a WGSL program as input
-struct ProgramFuzzer {
- /// The function signature
- using Fn = void(const Program&);
-
- /// Name of the fuzzer function
- std::string_view name;
- /// The fuzzer function pointer
- Fn* fn = nullptr;
-};
-
-/// Options for Run()
-struct Options {
- /// If true, the fuzzers will be run concurrently on separate threads.
- bool run_concurrently = false;
-};
-
-/// Runs all the registered WGSL fuzzers with the supplied WGSL
-/// @param wgsl the input WGSL
-/// @param options the options for running the fuzzers
-void Run(std::string_view wgsl, const Options& options);
-
-/// Registers the fuzzer function with the WGSL fuzzer executable.
-/// @param fuzzer the fuzzer
-void Register(const ProgramFuzzer& fuzzer);
-
-/// TINT_WGSL_PROGRAM_FUZZER registers the fuzzer function to run as part of `tint_wgsl_fuzzer`
-#define TINT_WGSL_PROGRAM_FUZZER(FUNCTION) \
- TINT_STATIC_INIT(::tint::fuzz::wgsl::Register({#FUNCTION, FUNCTION}))
-
-} // namespace tint::fuzz::wgsl
-
-#endif // SRC_TINT_CMD_FUZZ_WGSL_WGSL_FUZZ_H_
diff --git a/src/tint/cmd/info/BUILD.bazel b/src/tint/cmd/info/BUILD.bazel
index a71fc36..c19a5da 100644
--- a/src/tint/cmd/info/BUILD.bazel
+++ b/src/tint/cmd/info/BUILD.bazel
@@ -51,6 +51,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/inspector",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/cmd/info/BUILD.cmake b/src/tint/cmd/info/BUILD.cmake
index 8da6ae4..74d28e0 100644
--- a/src/tint/cmd/info/BUILD.cmake
+++ b/src/tint/cmd/info/BUILD.cmake
@@ -52,6 +52,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_inspector
tint_lang_wgsl_program
tint_lang_wgsl_sem
diff --git a/src/tint/cmd/info/BUILD.gn b/src/tint/cmd/info/BUILD.gn
index ac7005b..6f3a945 100644
--- a/src/tint/cmd/info/BUILD.gn
+++ b/src/tint/cmd/info/BUILD.gn
@@ -51,6 +51,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/inspector",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/cmd/loopy/BUILD.bazel b/src/tint/cmd/loopy/BUILD.bazel
index 6054294..7d42293 100644
--- a/src/tint/cmd/loopy/BUILD.bazel
+++ b/src/tint/cmd/loopy/BUILD.bazel
@@ -55,6 +55,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/helpers",
"//src/tint/lang/wgsl/inspector",
"//src/tint/lang/wgsl/program",
diff --git a/src/tint/cmd/loopy/BUILD.cmake b/src/tint/cmd/loopy/BUILD.cmake
index af48744..f72d122 100644
--- a/src/tint/cmd/loopy/BUILD.cmake
+++ b/src/tint/cmd/loopy/BUILD.cmake
@@ -56,6 +56,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_helpers
tint_lang_wgsl_inspector
tint_lang_wgsl_program
diff --git a/src/tint/cmd/loopy/BUILD.gn b/src/tint/cmd/loopy/BUILD.gn
index 3e7fa3d..4879c29 100644
--- a/src/tint/cmd/loopy/BUILD.gn
+++ b/src/tint/cmd/loopy/BUILD.gn
@@ -55,6 +55,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/helpers",
"${tint_src_dir}/lang/wgsl/inspector",
"${tint_src_dir}/lang/wgsl/program",
diff --git a/src/tint/cmd/loopy/main.cc b/src/tint/cmd/loopy/main.cc
index 6cc2317..6fcd4ac 100644
--- a/src/tint/cmd/loopy/main.cc
+++ b/src/tint/cmd/loopy/main.cc
@@ -50,7 +50,7 @@
#endif // TINT_BUILD_SPV_READER
#if TINT_BUILD_SPV_WRITER
-#include "src/tint/lang/spirv/writer/helpers/generate_bindings.h"
+#include "src/tint/lang/spirv/writer/helpers/ast_generate_bindings.h"
#include "src/tint/lang/spirv/writer/writer.h"
#endif // TINT_BUILD_SPV_WRITER
diff --git a/src/tint/cmd/remote_compile/main.cc b/src/tint/cmd/remote_compile/main.cc
index 1cade2d..60a0464 100644
--- a/src/tint/cmd/remote_compile/main.cc
+++ b/src/tint/cmd/remote_compile/main.cc
@@ -83,14 +83,14 @@
constexpr uint32_t kProtocolVersion = 1;
/// Supported shader source languages
-enum SourceLanguage {
+enum SourceLanguage : uint8_t {
MSL,
};
/// Stream is a serialization wrapper around a socket
struct Stream {
/// The underlying socket
- Socket* const socket;
+ tint::socket::Socket* const socket;
/// Error state
std::string error;
@@ -187,7 +187,7 @@
/// Base class for all messages
struct Message {
/// The type of the message
- enum class Type {
+ enum class Type : uint8_t {
ConnectionRequest,
ConnectionResponse,
CompileRequest,
@@ -384,8 +384,7 @@
file = args[1];
break;
default:
- std::cerr << "expected 1 or 2 arguments, got " << args.size() << std::endl
- << std::endl;
+ std::cerr << "expected 1 or 2 arguments, got " << args.size() << "\n\n";
ShowUsage();
}
if (address.empty() || file.empty()) {
@@ -402,12 +401,12 @@
}
bool RunServer(std::string port) {
- auto server_socket = Socket::Listen("", port.c_str());
+ auto server_socket = tint::socket::Socket::Listen("", port.c_str());
if (!server_socket) {
- std::cout << "Failed to listen on port " << port << std::endl;
+ std::cout << "Failed to listen on port " << port << "\n";
return false;
}
- std::cout << "Listening on port " << port.c_str() << "..." << std::endl;
+ std::cout << "Listening on port " << port.c_str() << "...\n";
while (auto conn = server_socket->Accept()) {
std::thread([=] {
DEBUG("Client connected...");
@@ -472,16 +471,16 @@
// Read the file
std::ifstream input(file, std::ios::binary);
if (!input) {
- std::cerr << "Couldn't open '" << file << "'" << std::endl;
+ std::cerr << "Couldn't open '" << file << "'\n";
return false;
}
std::string source((std::istreambuf_iterator<char>(input)), std::istreambuf_iterator<char>());
constexpr const int timeout_ms = 10000;
DEBUG("Connecting to %s:%s...", address.c_str(), port.c_str());
- auto conn = Socket::Connect(address.c_str(), port.c_str(), timeout_ms);
+ auto conn = tint::socket::Socket::Connect(address.c_str(), port.c_str(), timeout_ms);
if (!conn) {
- std::cerr << "Connection failed" << std::endl;
+ std::cerr << "Connection failed\n";
return false;
}
@@ -490,22 +489,22 @@
DEBUG("Sending connection request...");
auto conn_resp = Send(stream, ConnectionRequest{kProtocolVersion});
if (!stream.error.empty()) {
- std::cerr << stream.error << std::endl;
+ std::cerr << stream.error << "\n";
return false;
}
if (!conn_resp.error.empty()) {
- std::cerr << conn_resp.error << std::endl;
+ std::cerr << conn_resp.error << "\n";
return false;
}
DEBUG("Connection established. Requesting compile...");
auto comp_resp =
Send(stream, CompileRequest{SourceLanguage::MSL, version_major, version_minor, source});
if (!stream.error.empty()) {
- std::cerr << stream.error << std::endl;
+ std::cerr << stream.error << "\n";
return false;
}
if (!comp_resp.error.empty()) {
- std::cerr << comp_resp.error << std::endl;
+ std::cerr << comp_resp.error << "\n";
return false;
}
DEBUG("Compilation successful");
diff --git a/src/tint/cmd/test/BUILD.bazel b/src/tint/cmd/test/BUILD.bazel
index c883c12..6f1e558 100644
--- a/src/tint/cmd/test/BUILD.bazel
+++ b/src/tint/cmd/test/BUILD.bazel
@@ -52,6 +52,7 @@
"//src/tint/lang/core:test",
"//src/tint/lang/spirv/ir:test",
"//src/tint/lang/wgsl/ast:test",
+ "//src/tint/lang/wgsl/features:test",
"//src/tint/lang/wgsl/helpers:test",
"//src/tint/lang/wgsl/program:test",
"//src/tint/lang/wgsl/reader/lower:test",
@@ -60,6 +61,7 @@
"//src/tint/lang/wgsl/writer/ir_to_program:test",
"//src/tint/lang/wgsl/writer/raise:test",
"//src/tint/lang/wgsl:test",
+ "//src/tint/utils/bytes:test",
"//src/tint/utils/cli:test",
"//src/tint/utils/command:test",
"//src/tint/utils/containers:test",
@@ -123,6 +125,11 @@
],
"//conditions:default": [],
}) + select({
+ ":tint_build_spv_reader_or_tint_build_spv_writer": [
+ "//src/tint/lang/spirv/validate:test",
+ ],
+ "//conditions:default": [],
+ }) + select({
":tint_build_spv_writer": [
"//src/tint/lang/spirv/writer/ast_printer:test",
"//src/tint/lang/spirv/writer/common:test",
@@ -193,6 +200,14 @@
)
selects.config_setting_group(
+ name = "tint_build_spv_reader_or_tint_build_spv_writer",
+ match_any = [
+ "tint_build_spv_reader",
+ "tint_build_spv_writer",
+ ],
+)
+
+selects.config_setting_group(
name = "tint_build_glsl_writer_and_tint_build_wgsl_reader_and_tint_build_wgsl_writer",
match_all = [
":tint_build_glsl_writer",
diff --git a/src/tint/cmd/test/BUILD.cmake b/src/tint/cmd/test/BUILD.cmake
index f994d98..670c21f 100644
--- a/src/tint/cmd/test/BUILD.cmake
+++ b/src/tint/cmd/test/BUILD.cmake
@@ -53,6 +53,7 @@
tint_lang_core_test
tint_lang_spirv_ir_test
tint_lang_wgsl_ast_test
+ tint_lang_wgsl_features_test
tint_lang_wgsl_helpers_test
tint_lang_wgsl_program_test
tint_lang_wgsl_reader_lower_test
@@ -61,6 +62,7 @@
tint_lang_wgsl_writer_ir_to_program_test
tint_lang_wgsl_writer_raise_test
tint_lang_wgsl_test
+ tint_utils_bytes_test
tint_utils_cli_test
tint_utils_command_test
tint_utils_containers_test
@@ -136,6 +138,12 @@
)
endif(TINT_BUILD_SPV_READER AND TINT_BUILD_WGSL_WRITER)
+if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+ tint_target_add_dependencies(tint_cmd_test_test_cmd test_cmd
+ tint_lang_spirv_validate_test
+ )
+endif(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+
if(TINT_BUILD_SPV_WRITER)
tint_target_add_dependencies(tint_cmd_test_test_cmd test_cmd
tint_lang_spirv_writer_ast_printer_test
diff --git a/src/tint/cmd/test/BUILD.gn b/src/tint/cmd/test/BUILD.gn
index 774b68a..17410ae 100644
--- a/src/tint/cmd/test/BUILD.gn
+++ b/src/tint/cmd/test/BUILD.gn
@@ -59,6 +59,7 @@
"${tint_src_dir}/lang/spirv/ir:unittests",
"${tint_src_dir}/lang/wgsl:unittests",
"${tint_src_dir}/lang/wgsl/ast:unittests",
+ "${tint_src_dir}/lang/wgsl/features:unittests",
"${tint_src_dir}/lang/wgsl/helpers:unittests",
"${tint_src_dir}/lang/wgsl/program:unittests",
"${tint_src_dir}/lang/wgsl/reader/lower:unittests",
@@ -66,6 +67,7 @@
"${tint_src_dir}/lang/wgsl/sem:unittests",
"${tint_src_dir}/lang/wgsl/writer/ir_to_program:unittests",
"${tint_src_dir}/lang/wgsl/writer/raise:unittests",
+ "${tint_src_dir}/utils/bytes:unittests",
"${tint_src_dir}/utils/cli:unittests",
"${tint_src_dir}/utils/command:unittests",
"${tint_src_dir}/utils/containers:unittests",
@@ -129,6 +131,10 @@
deps += [ "${tint_src_dir}/lang/spirv/reader/ast_parser:unittests" ]
}
+ if (tint_build_spv_reader || tint_build_spv_writer) {
+ deps += [ "${tint_src_dir}/lang/spirv/validate:unittests" ]
+ }
+
if (tint_build_spv_writer) {
deps += [
"${tint_src_dir}/lang/spirv/writer:unittests",
diff --git a/src/tint/cmd/tint/BUILD.bazel b/src/tint/cmd/tint/BUILD.bazel
index 1abb879..b6fb729 100644
--- a/src/tint/cmd/tint/BUILD.bazel
+++ b/src/tint/cmd/tint/BUILD.bazel
@@ -56,6 +56,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/helpers",
"//src/tint/lang/wgsl/inspector",
"//src/tint/lang/wgsl/program",
@@ -102,11 +103,6 @@
],
"//conditions:default": [],
}) + select({
- ":tint_build_spv_reader": [
- "//src/tint/lang/spirv/reader",
- ],
- "//conditions:default": [],
- }) + select({
":tint_build_spv_reader_or_tint_build_spv_writer": [
"@spirv_tools",
],
diff --git a/src/tint/cmd/tint/BUILD.cmake b/src/tint/cmd/tint/BUILD.cmake
index bd4e4ed..9f35d05 100644
--- a/src/tint/cmd/tint/BUILD.cmake
+++ b/src/tint/cmd/tint/BUILD.cmake
@@ -57,6 +57,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_helpers
tint_lang_wgsl_inspector
tint_lang_wgsl_program
@@ -108,12 +109,6 @@
)
endif(TINT_BUILD_MSL_WRITER)
-if(TINT_BUILD_SPV_READER)
- tint_target_add_dependencies(tint_cmd_tint_cmd cmd
- tint_lang_spirv_reader
- )
-endif(TINT_BUILD_SPV_READER)
-
if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
tint_target_add_external_dependencies(tint_cmd_tint_cmd cmd
"spirv-tools"
diff --git a/src/tint/cmd/tint/BUILD.gn b/src/tint/cmd/tint/BUILD.gn
index 4bb12ce..c5b628c 100644
--- a/src/tint/cmd/tint/BUILD.gn
+++ b/src/tint/cmd/tint/BUILD.gn
@@ -56,6 +56,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/helpers",
"${tint_src_dir}/lang/wgsl/inspector",
"${tint_src_dir}/lang/wgsl/program",
@@ -105,10 +106,6 @@
]
}
- if (tint_build_spv_reader) {
- deps += [ "${tint_src_dir}/lang/spirv/reader" ]
- }
-
if (tint_build_spv_reader || tint_build_spv_writer) {
deps += [
"${tint_spirv_tools_dir}:spvtools_headers",
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index 7ae374d..5ba2c6e 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -27,12 +27,9 @@
#include <charconv>
#include <cstdio>
-#include <fstream>
#include <iostream>
-#include <limits>
#include <memory>
#include <optional>
-#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
@@ -63,17 +60,13 @@
#include "src/tint/utils/text/string.h"
#include "src/tint/utils/text/string_stream.h"
-#if TINT_BUILD_SPV_READER
-#include "src/tint/lang/spirv/reader/reader.h"
-#endif // TINT_BUILD_SPV_READER
-
#if TINT_BUILD_WGSL_READER
#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
#include "src/tint/lang/wgsl/reader/reader.h"
#endif // TINT_BUILD_WGSL_READER
#if TINT_BUILD_SPV_WRITER
-#include "src/tint/lang/spirv/writer/helpers/generate_bindings.h"
+#include "src/tint/lang/spirv/writer/helpers/ast_generate_bindings.h"
#include "src/tint/lang/spirv/writer/writer.h"
#endif // TINT_BUILD_SPV_WRITER
@@ -134,10 +127,10 @@
/// Prints the given hash value in a format string that the end-to-end test runner can parse.
[[maybe_unused]] void PrintHash(uint32_t hash) {
- std::cout << "<<HASH: 0x" << std::hex << hash << ">>" << std::endl;
+ std::cout << "<<HASH: 0x" << std::hex << hash << ">>\n";
}
-enum class Format {
+enum class Format : uint8_t {
kUnknown,
kNone,
kSpirv,
@@ -375,6 +368,22 @@
attachment.
)");
+ auto& pixel_local_attachment_formats =
+ options.Add<StringOption>("pixel_local_attachment_formats",
+ R"(Pixel local storage attachment formats, comma-separated
+Each binding is of the form MEMBER_INDEX=ATTACHMENT_FORMAT,
+where MEMBER_INDEX is the pixel-local structure member
+index and ATTACHMENT_FORMAT is the format of the emitted
+attachment, which can only be one of the below value:
+R32Sint, R32Uint, R32Float.
+)");
+
+ auto& pixel_local_group_index = options.Add<ValueOption<uint32_t>>(
+ "pixel_local_group_index",
+ R"(The bind group index of the pixel local attachments (default 0).
+)",
+ Default{0});
+
auto& skip_hash = options.Add<StringOption>(
"skip-hash", R"(Skips validation if the hash of the output is equal to any
of the hash codes in the comma separated list of hashes)");
@@ -408,7 +417,7 @@
auto result = options.Parse(arguments);
if (!result) {
- std::cerr << result.Failure() << std::endl;
+ std::cerr << result.Failure() << "\n";
show_usage();
return false;
}
@@ -424,7 +433,7 @@
std::cerr << "override values must be of the form IDENTIFIER=VALUE";
return false;
}
- auto value = tint::ParseNumber<double>(parts[1]);
+ auto value = tint::strconv::ParseNumber<double>(parts[1]);
if (!value) {
std::cerr << "invalid override value: " << parts[1];
return false;
@@ -437,19 +446,19 @@
auto binding_points = tint::Split(*hlsl_rc_bp.value, ",");
if (binding_points.Length() != 2) {
std::cerr << "Invalid binding point for " << hlsl_rc_bp.name << ": "
- << *hlsl_rc_bp.value << std::endl;
+ << *hlsl_rc_bp.value << "\n";
return false;
}
- auto group = tint::ParseUint32(binding_points[0]);
+ auto group = tint::strconv::ParseUint32(binding_points[0]);
if (!group) {
std::cerr << "Invalid group for " << hlsl_rc_bp.name << ": " << binding_points[0]
- << std::endl;
+ << "\n";
return false;
}
- auto binding = tint::ParseUint32(binding_points[1]);
+ auto binding = tint::strconv::ParseUint32(binding_points[1]);
if (!binding) {
std::cerr << "Invalid binding for " << hlsl_rc_bp.name << ": " << binding_points[1]
- << std::endl;
+ << "\n";
return false;
}
opts->hlsl_root_constant_binding_point = tint::BindingPoint{group.Get(), binding.Get()};
@@ -461,19 +470,19 @@
auto values = tint::Split(binding, "=");
if (values.Length() != 2) {
std::cerr << "Invalid binding " << pixel_local_attachments.name << ": " << binding
- << std::endl;
+ << "\n";
return false;
}
- auto member_index = tint::ParseUint32(values[0]);
+ auto member_index = tint::strconv::ParseUint32(values[0]);
if (!member_index) {
std::cerr << "Invalid member index for " << pixel_local_attachments.name << ": "
- << values[0] << std::endl;
+ << values[0] << "\n";
return false;
}
- auto attachment_index = tint::ParseUint32(values[1]);
+ auto attachment_index = tint::strconv::ParseUint32(values[1]);
if (!attachment_index) {
std::cerr << "Invalid attachment index for " << pixel_local_attachments.name << ": "
- << values[1] << std::endl;
+ << values[1] << "\n";
return false;
}
opts->pixel_local_options.attachments.emplace(member_index.Get(),
@@ -481,10 +490,47 @@
}
}
+ if (pixel_local_group_index.value.has_value()) {
+ opts->pixel_local_options.pixel_local_group_index = *pixel_local_group_index.value;
+ }
+
+ if (pixel_local_attachment_formats.value.has_value()) {
+ auto binding_formats = tint::Split(*pixel_local_attachment_formats.value, ",");
+ for (auto& binding_format : binding_formats) {
+ auto values = tint::Split(binding_format, "=");
+ if (values.Length() != 2) {
+ std::cerr << "Invalid binding format " << pixel_local_attachment_formats.name
+ << ": " << binding_format << std::endl;
+ return false;
+ }
+ auto member_index = tint::strconv::ParseUint32(values[0]);
+ if (!member_index) {
+ std::cerr << "Invalid member index for " << pixel_local_attachment_formats.name
+ << ": " << values[0] << std::endl;
+ return false;
+ }
+ auto format = values[1];
+ tint::PixelLocalOptions::TexelFormat texel_format =
+ tint::PixelLocalOptions::TexelFormat::kUndefined;
+ if (format == "R32Sint") {
+ texel_format = tint::PixelLocalOptions::TexelFormat::kR32Sint;
+ } else if (format == "R32Uint") {
+ texel_format = tint::PixelLocalOptions::TexelFormat::kR32Uint;
+ } else if (format == "R32Float") {
+ texel_format = tint::PixelLocalOptions::TexelFormat::kR32Float;
+ } else {
+ std::cerr << "Invalid texel format for " << pixel_local_attachments.name << ": "
+ << format << std::endl;
+ return false;
+ }
+ opts->pixel_local_options.attachment_formats.emplace(member_index.Get(), texel_format);
+ }
+ }
+
auto files = result.Get();
if (files.Length() > 1) {
std::cerr << "More than one input file specified: "
- << tint::Join(Transform(files, tint::Quote), ", ") << std::endl;
+ << tint::Join(Transform(files, tint::Quote), ", ") << "\n";
return false;
}
if (files.Length() == 1) {
@@ -514,7 +560,7 @@
file = fopen(output_file.c_str(), mode.c_str());
#endif
if (!file) {
- std::cerr << "Could not open file " << output_file << " for writing" << std::endl;
+ std::cerr << "Could not open file " << output_file << " for writing\n";
return false;
}
}
@@ -523,9 +569,9 @@
fwrite(buffer.data(), sizeof(typename ContainerT::value_type), buffer.size(), file);
if (buffer.size() != written) {
if (use_stdout) {
- std::cerr << "Could not write all output to standard output" << std::endl;
+ std::cerr << "Could not write all output to standard output\n";
} else {
- std::cerr << "Could not write to file " << output_file << std::endl;
+ std::cerr << "Could not write to file " << output_file << "\n";
fclose(file);
}
return false;
@@ -571,7 +617,7 @@
if (!tools.Disassemble(
data, &result,
SPV_BINARY_TO_TEXT_OPTION_INDENT | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES)) {
- std::cerr << spv_errors << std::endl;
+ std::cerr << spv_errors << "\n";
}
return result;
}
@@ -588,12 +634,23 @@
gen_options.disable_robustness = !options.enable_robustness;
gen_options.disable_workgroup_init = options.disable_workgroup_init;
gen_options.bindings = tint::spirv::writer::GenerateBindings(program);
- gen_options.use_tint_ir = options.use_ir;
- auto result = tint::spirv::writer::Generate(program, gen_options);
+ tint::Result<tint::spirv::writer::Output> result;
+ if (options.use_ir) {
+ // Convert the AST program to an IR module.
+ auto ir = tint::wgsl::reader::ProgramToLoweredIR(program);
+ if (!ir) {
+ std::cerr << "Failed to generate IR: " << ir << "\n";
+ return false;
+ }
+ result = tint::spirv::writer::Generate(ir.Get(), gen_options);
+ } else {
+ result = tint::spirv::writer::Generate(program, gen_options);
+ }
+
if (!result) {
tint::cmd::PrintWGSL(std::cerr, program);
- std::cerr << "Failed to generate: " << result.Failure() << std::endl;
+ std::cerr << "Failed to generate: " << result.Failure() << "\n";
return false;
}
@@ -617,7 +674,7 @@
spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_1);
tools.SetMessageConsumer(
[](spv_message_level_t, const char*, const spv_position_t& pos, const char* msg) {
- std::cerr << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg << std::endl;
+ std::cerr << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg << "\n";
});
if (!tools.Validate(result.Get().spirv.data(), result.Get().spirv.size(),
spvtools::ValidatorOptions())) {
@@ -645,7 +702,7 @@
tint::wgsl::writer::Options gen_options;
auto result = tint::wgsl::writer::Generate(program, gen_options);
if (!result) {
- std::cerr << "Failed to generate: " << result.Failure() << std::endl;
+ std::cerr << "Failed to generate: " << result.Failure() << "\n";
return false;
}
@@ -701,7 +758,6 @@
// TODO(jrprice): Provide a way for the user to set non-default options.
tint::msl::writer::Options gen_options;
- gen_options.use_tint_ir = options.use_ir;
gen_options.disable_robustness = !options.enable_robustness;
gen_options.disable_workgroup_init = options.disable_workgroup_init;
gen_options.pixel_local_options = options.pixel_local_options;
@@ -711,10 +767,23 @@
0);
gen_options.array_length_from_uniform.bindpoint_to_size_index.emplace(tint::BindingPoint{0, 1},
1);
- auto result = tint::msl::writer::Generate(*input_program, gen_options);
+
+ tint::Result<tint::msl::writer::Output> result;
+ if (options.use_ir) {
+ // Convert the AST program to an IR module.
+ auto ir = tint::wgsl::reader::ProgramToLoweredIR(program);
+ if (!ir) {
+ std::cerr << "Failed to generate IR: " << ir << "\n";
+ return false;
+ }
+ result = tint::msl::writer::Generate(ir.Get(), gen_options);
+ } else {
+ result = tint::msl::writer::Generate(*input_program, gen_options);
+ }
+
if (!result) {
tint::cmd::PrintWGSL(std::cerr, program);
- std::cerr << "Failed to generate: " << result.Failure() << std::endl;
+ std::cerr << "Failed to generate: " << result.Failure() << "\n";
return false;
}
@@ -760,7 +829,7 @@
}
#endif // __APPLE__
if (res.failed) {
- std::cerr << res.output << std::endl;
+ std::cerr << res.output << "\n";
return false;
}
}
@@ -782,6 +851,7 @@
gen_options.external_texture_options.bindings_map =
tint::cmd::GenerateExternalTextureBindings(program);
gen_options.root_constant_binding_point = options.hlsl_root_constant_binding_point;
+ gen_options.pixel_local_options = options.pixel_local_options;
auto result = tint::hlsl::writer::Generate(program, gen_options);
if (!result) {
tint::cmd::PrintWGSL(std::cerr, program);
@@ -887,7 +957,7 @@
#else
(void)program;
(void)options;
- std::cerr << "HLSL writer not enabled in tint build" << std::endl;
+ std::cerr << "HLSL writer not enabled in tint build\n";
return false;
#endif // TINT_BUILD_HLSL_WRITER
}
@@ -914,7 +984,7 @@
auto result = tint::glsl::writer::Generate(prg, gen_options, entry_point_name);
if (!result) {
tint::cmd::PrintWGSL(std::cerr, prg);
- std::cerr << "Failed to generate: " << result.Failure() << std::endl;
+ std::cerr << "Failed to generate: " << result.Failure() << "\n";
return false;
}
@@ -1019,17 +1089,18 @@
const auto& name = override.key;
const auto& value = override.value;
if (name.empty()) {
- std::cerr << "empty override name" << std::endl;
+ std::cerr << "empty override name\n";
return false;
}
- if (auto num = tint::ParseNumber<decltype(tint::OverrideId::value)>(name)) {
+ if (auto num =
+ tint::strconv::ParseNumber<decltype(tint::OverrideId::value)>(name)) {
tint::OverrideId id{num.Get()};
values.emplace(id, value);
} else {
auto override_names = inspector.GetNamedOverrideIds();
auto it = override_names.find(name);
if (it == override_names.end()) {
- std::cerr << "unknown override '" << name << "'" << std::endl;
+ std::cerr << "unknown override '" << name << "'\n";
return false;
}
values.emplace(it->second, value);
@@ -1046,7 +1117,7 @@
auto transform_names = [&] {
tint::StringStream names;
for (auto& t : transforms) {
- names << " " << t.name << std::endl;
+ names << " " << t.name << "\n";
}
return names.str();
};
@@ -1083,22 +1154,22 @@
gen_options.use_syntax_tree_writer = true;
auto result = tint::wgsl::writer::Generate(info.program, gen_options);
if (!result) {
- std::cerr << "Failed to dump AST: " << result.Failure() << std::endl;
+ std::cerr << "Failed to dump AST: " << result.Failure() << "\n";
} else {
- std::cout << result->wgsl << std::endl;
+ std::cout << result->wgsl << "\n";
}
}
#endif // TINT_BUILD_SYNTAX_TREE_WRITER
#if TINT_BUILD_WGSL_READER
if (options.dump_ir) {
- auto result = tint::wgsl::reader::ProgramToIR(info.program);
+ auto result = tint::wgsl::reader::ProgramToLoweredIR(info.program);
if (!result) {
- std::cerr << "Failed to build IR from program: " << result.Failure() << std::endl;
+ std::cerr << "Failed to build IR from program: " << result.Failure() << "\n";
} else {
auto mod = result.Move();
if (options.dump_ir) {
- std::cout << tint::core::ir::Disassemble(mod) << std::endl;
+ std::cout << tint::core::ir::Disassemble(mod) << "\n";
}
}
}
@@ -1159,8 +1230,8 @@
}
}
- std::cerr << "Unknown transform: " << name << std::endl;
- std::cerr << "Available transforms: " << std::endl << transform_names() << std::endl;
+ std::cerr << "Unknown transform: " << name << "\n";
+ std::cerr << "Available transforms: \n" << transform_names() << "\n";
return false;
};
@@ -1189,7 +1260,7 @@
auto program = transform_manager.Run(info.program, std::move(transform_inputs), outputs);
if (!program.IsValid()) {
tint::cmd::PrintWGSL(std::cerr, program);
- std::cerr << program.Diagnostics() << std::endl;
+ std::cerr << program.Diagnostics() << "\n";
return 1;
}
@@ -1214,7 +1285,7 @@
case Format::kNone:
break;
default:
- std::cerr << "Unknown output format specified" << std::endl;
+ std::cerr << "Unknown output format specified\n";
return 1;
}
if (!success) {
diff --git a/src/tint/externals.json b/src/tint/externals.json
index a7631a5..dd5d1df 100644
--- a/src/tint/externals.json
+++ b/src/tint/externals.json
@@ -17,7 +17,7 @@
"IncludePatterns": [
"Metal/Metal.h"
],
- "Condition": "is_mac",
+ "Condition": "tint_build_is_mac",
},
"thread": {
"IncludePatterns": [
@@ -64,6 +64,6 @@
"IncludePatterns": [
"winsock2.h"
],
- "Condition": "is_win",
+ "Condition": "tint_build_is_win",
},
-}
\ No newline at end of file
+}
diff --git a/src/tint/flags.bzl b/src/tint/flags.bzl
index 08b5d60..b607cf8 100644
--- a/src/tint/flags.bzl
+++ b/src/tint/flags.bzl
@@ -35,7 +35,7 @@
def declare_os_flag():
"""Creates the 'os' string flag that specifies the OS to target, and a pair of
- 'is_<os>_true' and 'is_<os>_false' targets.
+ 'tint_build_is_<os>_true' and 'tint_build_is_<os>_false' targets.
The OS flag can be specified on the command line with '--//src/tint:os=<os>'
"""
@@ -55,13 +55,13 @@
for os in OSes:
native.config_setting(
- name = "is_{}_true".format(os),
+ name = "tint_build_is_{}_true".format(os),
flag_values = { ":os": os },
visibility = ["//visibility:public"],
)
selects.config_setting_group(
- name = "is_{}_false".format(os),
- match_any = [ "is_{}_true".format(other) for other in OSes if other != os],
+ name = "tint_build_is_{}_false".format(os),
+ match_any = [ "tint_build_is_{}_true".format(other) for other in OSes if other != os],
visibility = ["//visibility:public"],
)
diff --git a/src/tint/fuzzers/tint_common_fuzzer.cc b/src/tint/fuzzers/tint_common_fuzzer.cc
index de7e8f6..be08086 100644
--- a/src/tint/fuzzers/tint_common_fuzzer.cc
+++ b/src/tint/fuzzers/tint_common_fuzzer.cc
@@ -55,7 +55,7 @@
#include "src/tint/utils/math/hash.h"
#if TINT_BUILD_SPV_WRITER
-#include "src/tint/lang/spirv/writer/helpers/generate_bindings.h"
+#include "src/tint/lang/spirv/writer/helpers/ast_generate_bindings.h"
#endif // TINT_BUILD_SPV_WRITER
#if TINT_BUILD_MSL_WRITER
@@ -364,12 +364,6 @@
}
case OutputFormat::kMSL: {
#if TINT_BUILD_MSL_WRITER
- // TODO(crbug.com/tint/1967): Skip fuzzing of the IR version of the MSL writer, which is
- // still under construction.
- if (options_msl_.use_tint_ir) {
- return 0;
- }
-
// Remap resource numbers to a flat namespace.
// TODO(crbug.com/tint/1501): Do this via Options::BindingMap.
if (auto flattened = tint::wgsl::FlattenBindings(program)) {
diff --git a/src/tint/lang/core/BUILD.bazel b/src/tint/lang/core/BUILD.bazel
index ee003f9..a26c37f 100644
--- a/src/tint/lang/core/BUILD.bazel
+++ b/src/tint/lang/core/BUILD.bazel
@@ -107,6 +107,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/core/BUILD.cmake b/src/tint/lang/core/BUILD.cmake
index 6ce30bf..a5c1610 100644
--- a/src/tint/lang/core/BUILD.cmake
+++ b/src/tint/lang/core/BUILD.cmake
@@ -111,6 +111,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/core/BUILD.gn b/src/tint/lang/core/BUILD.gn
index 011fb58..88de4fd 100644
--- a/src/tint/lang/core/BUILD.gn
+++ b/src/tint/lang/core/BUILD.gn
@@ -108,6 +108,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/core/access_test.cc b/src/tint/lang/core/access_test.cc
index 5b7116b..69c05b2 100644
--- a/src/tint/lang/core/access_test.cc
+++ b/src/tint/lang/core/access_test.cc
@@ -86,7 +86,7 @@
TEST_P(AccessPrintTest, Print) {
Access value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, AccessPrintTest, testing::ValuesIn(kValidCases));
diff --git a/src/tint/lang/core/address_space_test.cc b/src/tint/lang/core/address_space_test.cc
index 38ab91c..0f63446 100644
--- a/src/tint/lang/core/address_space_test.cc
+++ b/src/tint/lang/core/address_space_test.cc
@@ -101,7 +101,7 @@
TEST_P(AddressSpacePrintTest, Print) {
AddressSpace value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, AddressSpacePrintTest, testing::ValuesIn(kValidCases));
diff --git a/src/tint/lang/core/attribute_test.cc b/src/tint/lang/core/attribute_test.cc
index ac6b338..10d8e72 100644
--- a/src/tint/lang/core/attribute_test.cc
+++ b/src/tint/lang/core/attribute_test.cc
@@ -146,7 +146,7 @@
TEST_P(AttributePrintTest, Print) {
Attribute value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, AttributePrintTest, testing::ValuesIn(kValidCases));
diff --git a/src/tint/lang/core/builtin_type_test.cc b/src/tint/lang/core/builtin_type_test.cc
index 32284c7..8fd8d6a 100644
--- a/src/tint/lang/core/builtin_type_test.cc
+++ b/src/tint/lang/core/builtin_type_test.cc
@@ -462,7 +462,7 @@
TEST_P(BuiltinTypePrintTest, Print) {
BuiltinType value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, BuiltinTypePrintTest, testing::ValuesIn(kValidCases));
diff --git a/src/tint/lang/core/builtin_value_test.cc b/src/tint/lang/core/builtin_value_test.cc
index 721aacf..220aab8 100644
--- a/src/tint/lang/core/builtin_value_test.cc
+++ b/src/tint/lang/core/builtin_value_test.cc
@@ -138,7 +138,7 @@
TEST_P(BuiltinValuePrintTest, Print) {
BuiltinValue value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, BuiltinValuePrintTest, testing::ValuesIn(kValidCases));
diff --git a/src/tint/lang/core/constant/BUILD.bazel b/src/tint/lang/core/constant/BUILD.bazel
index dfdb0d1..b7967f5 100644
--- a/src/tint/lang/core/constant/BUILD.bazel
+++ b/src/tint/lang/core/constant/BUILD.bazel
@@ -108,6 +108,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/intrinsic",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
diff --git a/src/tint/lang/core/constant/BUILD.cmake b/src/tint/lang/core/constant/BUILD.cmake
index 0a8076d..3e86cd2 100644
--- a/src/tint/lang/core/constant/BUILD.cmake
+++ b/src/tint/lang/core/constant/BUILD.cmake
@@ -107,6 +107,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_intrinsic
tint_lang_wgsl_program
tint_lang_wgsl_resolver
diff --git a/src/tint/lang/core/constant/BUILD.gn b/src/tint/lang/core/constant/BUILD.gn
index 64d4cce..39c11d9 100644
--- a/src/tint/lang/core/constant/BUILD.gn
+++ b/src/tint/lang/core/constant/BUILD.gn
@@ -109,6 +109,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/intrinsic",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
diff --git a/src/tint/lang/core/interpolation_sampling_test.cc b/src/tint/lang/core/interpolation_sampling_test.cc
index be7a47e..6d658b2 100644
--- a/src/tint/lang/core/interpolation_sampling_test.cc
+++ b/src/tint/lang/core/interpolation_sampling_test.cc
@@ -95,7 +95,7 @@
TEST_P(InterpolationSamplingPrintTest, Print) {
InterpolationSampling value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases,
diff --git a/src/tint/lang/core/interpolation_type_test.cc b/src/tint/lang/core/interpolation_type_test.cc
index 8d3ac8b..5d93e72 100644
--- a/src/tint/lang/core/interpolation_type_test.cc
+++ b/src/tint/lang/core/interpolation_type_test.cc
@@ -89,7 +89,7 @@
TEST_P(InterpolationTypePrintTest, Print) {
InterpolationType value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, InterpolationTypePrintTest, testing::ValuesIn(kValidCases));
diff --git a/src/tint/lang/core/intrinsic/BUILD.bazel b/src/tint/lang/core/intrinsic/BUILD.bazel
index b1ba629..ea936ea 100644
--- a/src/tint/lang/core/intrinsic/BUILD.bazel
+++ b/src/tint/lang/core/intrinsic/BUILD.bazel
@@ -86,6 +86,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/intrinsic",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
diff --git a/src/tint/lang/core/intrinsic/BUILD.cmake b/src/tint/lang/core/intrinsic/BUILD.cmake
index d10b9fe..4a6f199 100644
--- a/src/tint/lang/core/intrinsic/BUILD.cmake
+++ b/src/tint/lang/core/intrinsic/BUILD.cmake
@@ -85,6 +85,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_intrinsic
tint_lang_wgsl_program
tint_lang_wgsl_resolver
diff --git a/src/tint/lang/core/intrinsic/BUILD.gn b/src/tint/lang/core/intrinsic/BUILD.gn
index 8294126..011a65a 100644
--- a/src/tint/lang/core/intrinsic/BUILD.gn
+++ b/src/tint/lang/core/intrinsic/BUILD.gn
@@ -85,6 +85,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/intrinsic",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
diff --git a/src/tint/lang/core/ir/BUILD.bazel b/src/tint/lang/core/ir/BUILD.bazel
index a07a52e..3c62fe9 100644
--- a/src/tint/lang/core/ir/BUILD.bazel
+++ b/src/tint/lang/core/ir/BUILD.bazel
@@ -113,6 +113,7 @@
"exit_switch.h",
"function.h",
"function_param.h",
+ "ice.h",
"if.h",
"instruction.h",
"instruction_result.h",
diff --git a/src/tint/lang/core/ir/BUILD.cmake b/src/tint/lang/core/ir/BUILD.cmake
index 028790d..19c6a8a 100644
--- a/src/tint/lang/core/ir/BUILD.cmake
+++ b/src/tint/lang/core/ir/BUILD.cmake
@@ -89,6 +89,7 @@
lang/core/ir/function.h
lang/core/ir/function_param.cc
lang/core/ir/function_param.h
+ lang/core/ir/ice.h
lang/core/ir/if.cc
lang/core/ir/if.h
lang/core/ir/instruction.cc
diff --git a/src/tint/lang/core/ir/BUILD.gn b/src/tint/lang/core/ir/BUILD.gn
index 0e76537..9bcb139 100644
--- a/src/tint/lang/core/ir/BUILD.gn
+++ b/src/tint/lang/core/ir/BUILD.gn
@@ -92,6 +92,7 @@
"function.h",
"function_param.cc",
"function_param.h",
+ "ice.h",
"if.cc",
"if.h",
"instruction.cc",
diff --git a/src/tint/lang/core/ir/access.cc b/src/tint/lang/core/ir/access.cc
index adb651c..c469a5d 100644
--- a/src/tint/lang/core/ir/access.cc
+++ b/src/tint/lang/core/ir/access.cc
@@ -46,7 +46,7 @@
Access::~Access() = default;
Access* Access::Clone(CloneContext& ctx) {
- auto new_result = ctx.Clone(Result());
+ auto new_result = ctx.Clone(Result(0));
auto obj = ctx.Remap(Object());
auto indices = ctx.Remap<Access::kDefaultNumOperands>(Indices());
return ctx.ir.instructions.Create<Access>(new_result, obj, indices);
diff --git a/src/tint/lang/core/ir/access.h b/src/tint/lang/core/ir/access.h
index 274fa6b..0bf2caa 100644
--- a/src/tint/lang/core/ir/access.h
+++ b/src/tint/lang/core/ir/access.h
@@ -57,15 +57,23 @@
/// @returns the object used for the access
Value* Object() { return operands_[kObjectOperandOffset]; }
+ /// @returns the object used for the access
+ const Value* Object() const { return operands_[kObjectOperandOffset]; }
+
/// Adds the given index to the end of the access chain
/// @param idx the index to add
void AddIndex(Value* idx) { AddOperand(operands_.Length(), idx); }
/// @returns the accessor indices
- tint::Slice<Value*> Indices() { return operands_.Slice().Offset(kIndicesOperandOffset); }
+ tint::Slice<Value* const> Indices() { return operands_.Slice().Offset(kIndicesOperandOffset); }
+
+ /// @returns the accessor indices
+ tint::Slice<const Value* const> Indices() const {
+ return operands_.Slice().Offset(kIndicesOperandOffset);
+ }
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "access"; }
+ std::string FriendlyName() const override { return "access"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/access_test.cc b/src/tint/lang/core/ir/access_test.cc
index be295e8..f3be39c 100644
--- a/src/tint/lang/core/ir/access_test.cc
+++ b/src/tint/lang/core/ir/access_test.cc
@@ -45,7 +45,7 @@
auto* idx = b.Constant(u32(1));
auto* a = b.Access(ty.i32(), var, idx);
- EXPECT_THAT(var->Result()->Usages(), testing::UnorderedElementsAre(Usage{a, 0u}));
+ EXPECT_THAT(var->Result(0)->Usages(), testing::UnorderedElementsAre(Usage{a, 0u}));
EXPECT_THAT(idx->Usages(), testing::UnorderedElementsAre(Usage{a, 1u}));
}
@@ -55,11 +55,10 @@
auto* idx = b.Constant(u32(1));
auto* a = b.Access(ty.i32(), var, idx);
- EXPECT_TRUE(a->HasResults());
- EXPECT_FALSE(a->HasMultiResults());
+ EXPECT_EQ(a->Results().Length(), 1u);
- EXPECT_TRUE(a->Result()->Is<InstructionResult>());
- EXPECT_EQ(a, a->Result()->Source());
+ EXPECT_TRUE(a->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(a, a->Result(0)->Instruction());
}
TEST_F(IR_AccessTest, Fail_NullType) {
@@ -85,8 +84,8 @@
EXPECT_NE(a, new_a);
- EXPECT_NE(a->Result(), new_a->Result());
- EXPECT_EQ(type, new_a->Result()->Type());
+ EXPECT_NE(a->Result(0), new_a->Result(0));
+ EXPECT_EQ(type, new_a->Result(0)->Type());
EXPECT_NE(nullptr, new_a->Object());
EXPECT_EQ(a->Object(), new_a->Object());
diff --git a/src/tint/lang/core/ir/binary.cc b/src/tint/lang/core/ir/binary.cc
index c5a8e7c..41c9972 100644
--- a/src/tint/lang/core/ir/binary.cc
+++ b/src/tint/lang/core/ir/binary.cc
@@ -43,7 +43,7 @@
Binary::~Binary() = default;
Binary* Binary::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto* lhs = ctx.Remap(LHS());
auto* rhs = ctx.Remap(RHS());
return ctx.ir.instructions.Create<Binary>(new_result, op_, lhs, rhs);
diff --git a/src/tint/lang/core/ir/binary.h b/src/tint/lang/core/ir/binary.h
index 117dfbf..6490be9 100644
--- a/src/tint/lang/core/ir/binary.h
+++ b/src/tint/lang/core/ir/binary.h
@@ -79,16 +79,22 @@
Binary* Clone(CloneContext& ctx) override;
/// @returns the binary operator
- BinaryOp Op() { return op_; }
+ BinaryOp Op() const { return op_; }
/// @returns the left-hand-side value for the instruction
Value* LHS() { return operands_[kLhsOperandOffset]; }
+ /// @returns the left-hand-side value for the instruction
+ const Value* LHS() const { return operands_[kLhsOperandOffset]; }
+
/// @returns the right-hand-side value for the instruction
Value* RHS() { return operands_[kRhsOperandOffset]; }
+ /// @returns the right-hand-side value for the instruction
+ const Value* RHS() const { return operands_[kRhsOperandOffset]; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "binary"; }
+ std::string FriendlyName() const override { return "binary"; }
private:
BinaryOp op_;
diff --git a/src/tint/lang/core/ir/binary_test.cc b/src/tint/lang/core/ir/binary_test.cc
index 0eae85d..d468a61 100644
--- a/src/tint/lang/core/ir/binary_test.cc
+++ b/src/tint/lang/core/ir/binary_test.cc
@@ -53,10 +53,9 @@
TEST_F(IR_BinaryTest, Result) {
auto* a = b.Add(mod.Types().i32(), 4_i, 2_i);
- EXPECT_TRUE(a->HasResults());
- EXPECT_FALSE(a->HasMultiResults());
- EXPECT_TRUE(a->Result()->Is<InstructionResult>());
- EXPECT_EQ(a, a->Result()->Source());
+ EXPECT_EQ(a->Results().Length(), 1u);
+ EXPECT_TRUE(a->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(a, a->Result(0)->Instruction());
}
TEST_F(IR_BinaryTest, CreateAnd) {
@@ -396,7 +395,7 @@
EXPECT_NE(inst, c);
- EXPECT_EQ(mod.Types().i32(), c->Result()->Type());
+ EXPECT_EQ(mod.Types().i32(), c->Result(0)->Type());
EXPECT_EQ(BinaryOp::kAnd, c->Op());
auto new_lhs = c->LHS()->As<Constant>()->Value();
diff --git a/src/tint/lang/core/ir/bitcast.cc b/src/tint/lang/core/ir/bitcast.cc
index 62a40d7..26031a47 100644
--- a/src/tint/lang/core/ir/bitcast.cc
+++ b/src/tint/lang/core/ir/bitcast.cc
@@ -42,7 +42,7 @@
Bitcast::~Bitcast() = default;
Bitcast* Bitcast::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto* val = ctx.Remap(Val());
return ctx.ir.instructions.Create<Bitcast>(new_result, val);
}
diff --git a/src/tint/lang/core/ir/bitcast.h b/src/tint/lang/core/ir/bitcast.h
index 11998fe..3526681 100644
--- a/src/tint/lang/core/ir/bitcast.h
+++ b/src/tint/lang/core/ir/bitcast.h
@@ -53,8 +53,11 @@
/// @returns the operand value
Value* Val() { return operands_[kValueOperandOffset]; }
+ /// @returns the operand value
+ const Value* Val() const { return operands_[kValueOperandOffset]; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "bitcast"; }
+ std::string FriendlyName() const override { return "bitcast"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/bitcast_test.cc b/src/tint/lang/core/ir/bitcast_test.cc
index 3075df1..833f460 100644
--- a/src/tint/lang/core/ir/bitcast_test.cc
+++ b/src/tint/lang/core/ir/bitcast_test.cc
@@ -45,7 +45,7 @@
auto* inst = b.Bitcast(mod.Types().i32(), 4_i);
ASSERT_TRUE(inst->Is<ir::Bitcast>());
- ASSERT_NE(inst->Result()->Type(), nullptr);
+ ASSERT_NE(inst->Result(0)->Type(), nullptr);
auto args = inst->Args();
ASSERT_EQ(args.Length(), 1u);
@@ -58,10 +58,9 @@
TEST_F(IR_BitcastTest, Result) {
auto* a = b.Bitcast(mod.Types().i32(), 4_i);
- EXPECT_TRUE(a->HasResults());
- EXPECT_FALSE(a->HasMultiResults());
- EXPECT_TRUE(a->Result()->Is<InstructionResult>());
- EXPECT_EQ(a, a->Result()->Source());
+ EXPECT_EQ(a->Results().Length(), 1u);
+ EXPECT_TRUE(a->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(a, a->Result(0)->Instruction());
}
TEST_F(IR_BitcastTest, Bitcast_Usage) {
@@ -90,7 +89,7 @@
EXPECT_NE(inst, n);
- EXPECT_EQ(mod.Types().i32(), n->Result()->Type());
+ EXPECT_EQ(mod.Types().i32(), n->Result(0)->Type());
auto new_val = n->Val()->As<Constant>()->Value();
ASSERT_TRUE(new_val->Is<core::constant::Scalar<i32>>());
diff --git a/src/tint/lang/core/ir/block.h b/src/tint/lang/core/ir/block.h
index 6273b29..02cb037 100644
--- a/src/tint/lang/core/ir/block.h
+++ b/src/tint/lang/core/ir/block.h
@@ -32,6 +32,7 @@
#include "src/tint/lang/core/ir/instruction.h"
#include "src/tint/lang/core/ir/terminator.h"
+#include "src/tint/utils/containers/const_propagating_ptr.h"
#include "src/tint/utils/containers/vector.h"
// Forward declarations
@@ -58,33 +59,34 @@
/// @param out the block to clone into
virtual void CloneInto(CloneContext& ctx, Block* out);
- /// @returns true if this is block has a terminator instruction
- bool HasTerminator() {
- return instructions_.last != nullptr && instructions_.last->Is<ir::Terminator>();
- }
+ /// @return the terminator instruction for this block, or nullptr if this block does not end in
+ /// a terminator.
+ ir::Terminator* Terminator() { return tint::As<ir::Terminator>(instructions_.last.Get()); }
- /// @return the terminator instruction for this block
- ir::Terminator* Terminator() {
- if (!HasTerminator()) {
- return nullptr;
- }
- return instructions_.last->As<ir::Terminator>();
+ /// @return the terminator instruction for this block, or nullptr if this block does not end in
+ /// a terminator.
+ const ir::Terminator* Terminator() const {
+ return tint::As<ir::Terminator>(instructions_.last.Get());
}
/// @returns the instructions in the block
- Instruction* Instructions() { return instructions_.first; }
+ Instruction* Instructions() { return instructions_.first.Get(); }
+
+ /// @returns the instructions in the block
+ const Instruction* Instructions() const { return instructions_.first.Get(); }
/// Iterator for the instructions inside a block
+ template <typename T>
class Iterator {
public:
/// Constructor
/// @param inst the instruction to start iterating from
- explicit Iterator(Instruction* inst) : inst_(inst) {}
+ explicit Iterator(T* inst) : inst_(inst) {}
~Iterator() = default;
/// Dereference operator
/// @returns the instruction for this iterator
- Instruction* operator*() const { return inst_; }
+ T* operator*() const { return inst_; }
/// Comparison operator
/// @param itr to compare against
@@ -104,21 +106,35 @@
}
private:
- Instruction* inst_ = nullptr;
+ T* inst_ = nullptr;
};
/// @returns the iterator pointing to the start of the instruction list
- Iterator begin() { return Iterator{instructions_.first}; }
+ Iterator<Instruction> begin() { return Iterator<Instruction>{instructions_.first}; }
/// @returns the ending iterator
- Iterator end() { return Iterator{nullptr}; }
+ Iterator<Instruction> end() { return Iterator<Instruction>{nullptr}; }
+
+ /// @returns the iterator pointing to the start of the instruction list
+ Iterator<const Instruction> begin() const {
+ return Iterator<const Instruction>{instructions_.first};
+ }
+
+ /// @returns the ending iterator
+ Iterator<const Instruction> end() const { return Iterator<const Instruction>{nullptr}; }
/// @returns the first instruction in the instruction list
Instruction* Front() { return instructions_.first; }
+ /// @returns the first instruction in the instruction list
+ const Instruction* Front() const { return instructions_.first; }
+
/// @returns the last instruction in the instruction list
Instruction* Back() { return instructions_.last; }
+ /// @returns the last instruction in the instruction list
+ const Instruction* Back() const { return instructions_.last; }
+
/// Adds the instruction to the beginning of the block
/// @param inst the instruction to add
/// @returns the instruction to allow calls to be chained
@@ -144,14 +160,17 @@
void Remove(Instruction* inst);
/// @returns true if the block contains no instructions
- bool IsEmpty() { return Length() == 0; }
+ bool IsEmpty() const { return Length() == 0; }
/// @returns the number of instructions in the block
- size_t Length() { return instructions_.count; }
+ size_t Length() const { return instructions_.count; }
/// @return the parent instruction that owns this block
ControlInstruction* Parent() { return parent_; }
+ /// @return the parent instruction that owns this block
+ const ControlInstruction* Parent() const { return parent_; }
+
/// @param parent the parent instruction that owns this block
void SetParent(ControlInstruction* parent) { parent_ = parent; }
@@ -160,12 +179,12 @@
private:
struct {
- Instruction* first = nullptr;
- Instruction* last = nullptr;
+ ConstPropagatingPtr<Instruction> first;
+ ConstPropagatingPtr<Instruction> last;
size_t count = 0;
} instructions_;
- ControlInstruction* parent_ = nullptr;
+ ConstPropagatingPtr<ControlInstruction> parent_;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/block_param.h b/src/tint/lang/core/ir/block_param.h
index 3ab0c26..009e022 100644
--- a/src/tint/lang/core/ir/block_param.h
+++ b/src/tint/lang/core/ir/block_param.h
@@ -42,7 +42,7 @@
~BlockParam() override;
/// @returns the type of the var
- const core::type::Type* Type() override { return type_; }
+ const core::type::Type* Type() const override { return type_; }
/// @copydoc Instruction::Clone()
BlockParam* Clone(CloneContext& ctx) override;
diff --git a/src/tint/lang/core/ir/block_test.cc b/src/tint/lang/core/ir/block_test.cc
index d48b7c7..8e2f3b6 100644
--- a/src/tint/lang/core/ir/block_test.cc
+++ b/src/tint/lang/core/ir/block_test.cc
@@ -35,65 +35,65 @@
using namespace tint::core::number_suffixes; // NOLINT
using IR_BlockTest = IRTestHelper;
-TEST_F(IR_BlockTest, HasTerminator_Empty) {
+TEST_F(IR_BlockTest, Terminator_Empty) {
auto* blk = b.Block();
- EXPECT_FALSE(blk->HasTerminator());
+ EXPECT_EQ(blk->Terminator(), nullptr);
}
-TEST_F(IR_BlockTest, HasTerminator_None) {
+TEST_F(IR_BlockTest, Terminator_None) {
auto* blk = b.Block();
blk->Append(b.Add(mod.Types().i32(), 1_u, 2_u));
- EXPECT_FALSE(blk->HasTerminator());
+ EXPECT_EQ(blk->Terminator(), nullptr);
}
-TEST_F(IR_BlockTest, HasTerminator_BreakIf) {
+TEST_F(IR_BlockTest, Terminator_BreakIf) {
auto* blk = b.Block();
auto* loop = b.Loop();
blk->Append(b.BreakIf(loop, true));
- EXPECT_TRUE(blk->HasTerminator());
+ EXPECT_NE(blk->Terminator(), nullptr);
}
-TEST_F(IR_BlockTest, HasTerminator_Continue) {
+TEST_F(IR_BlockTest, Terminator_Continue) {
auto* blk = b.Block();
auto* loop = b.Loop();
blk->Append(b.Continue(loop));
- EXPECT_TRUE(blk->HasTerminator());
+ EXPECT_NE(blk->Terminator(), nullptr);
}
-TEST_F(IR_BlockTest, HasTerminator_ExitIf) {
+TEST_F(IR_BlockTest, Terminator_ExitIf) {
auto* blk = b.Block();
auto* if_ = b.If(true);
blk->Append(b.ExitIf(if_));
- EXPECT_TRUE(blk->HasTerminator());
+ EXPECT_NE(blk->Terminator(), nullptr);
}
-TEST_F(IR_BlockTest, HasTerminator_ExitLoop) {
+TEST_F(IR_BlockTest, Terminator_ExitLoop) {
auto* blk = b.Block();
auto* loop = b.Loop();
blk->Append(b.ExitLoop(loop));
- EXPECT_TRUE(blk->HasTerminator());
+ EXPECT_NE(blk->Terminator(), nullptr);
}
-TEST_F(IR_BlockTest, HasTerminator_ExitSwitch) {
+TEST_F(IR_BlockTest, Terminator_ExitSwitch) {
auto* blk = b.Block();
auto* s = b.Switch(1_u);
blk->Append(b.ExitSwitch(s));
- EXPECT_TRUE(blk->HasTerminator());
+ EXPECT_NE(blk->Terminator(), nullptr);
}
-TEST_F(IR_BlockTest, HasTerminator_NextIteration) {
+TEST_F(IR_BlockTest, Terminator_NextIteration) {
auto* blk = b.Block();
auto* loop = b.Loop();
blk->Append(b.NextIteration(loop));
- EXPECT_TRUE(blk->HasTerminator());
+ EXPECT_NE(blk->Terminator(), nullptr);
}
-TEST_F(IR_BlockTest, HasTerminator_Return) {
+TEST_F(IR_BlockTest, Terminator_Return) {
auto* f = b.Function("myFunc", mod.Types().void_());
auto* blk = b.Block();
blk->Append(b.Return(f));
- EXPECT_TRUE(blk->HasTerminator());
+ EXPECT_NE(blk->Terminator(), nullptr);
}
TEST_F(IR_BlockTest, Append) {
diff --git a/src/tint/lang/core/ir/break_if.h b/src/tint/lang/core/ir/break_if.h
index b2b1b5e..bc8dbdf 100644
--- a/src/tint/lang/core/ir/break_if.h
+++ b/src/tint/lang/core/ir/break_if.h
@@ -32,6 +32,7 @@
#include "src/tint/lang/core/ir/terminator.h"
#include "src/tint/lang/core/ir/value.h"
+#include "src/tint/utils/containers/const_propagating_ptr.h"
#include "src/tint/utils/rtti/castable.h"
// Forward declarations
@@ -60,22 +61,26 @@
/// @copydoc Instruction::Clone()
BreakIf* Clone(CloneContext& ctx) override;
- /// @returns the MultiInBlock arguments
- tint::Slice<Value* const> Args() override {
- return operands_.Slice().Offset(kArgsOperandOffset);
- }
+ /// @returns the offset of the arguments in Operands()
+ size_t ArgsOperandOffset() const override { return kArgsOperandOffset; }
/// @returns the break condition
Value* Condition() { return operands_[kConditionOperandOffset]; }
+ /// @returns the break condition
+ const Value* Condition() const { return operands_[kConditionOperandOffset]; }
+
/// @returns the loop containing the break-if
ir::Loop* Loop() { return loop_; }
+ /// @returns the loop containing the break-if
+ const ir::Loop* Loop() const { return loop_; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "break_if"; }
+ std::string FriendlyName() const override { return "break_if"; }
private:
- ir::Loop* loop_ = nullptr;
+ ConstPropagatingPtr<ir::Loop> loop_;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/break_if_test.cc b/src/tint/lang/core/ir/break_if_test.cc
index df13922..9b36ad1 100644
--- a/src/tint/lang/core/ir/break_if_test.cc
+++ b/src/tint/lang/core/ir/break_if_test.cc
@@ -57,8 +57,7 @@
auto* arg2 = b.Constant(2_u);
auto* brk = b.BreakIf(loop, cond, arg1, arg2);
- EXPECT_FALSE(brk->HasResults());
- EXPECT_FALSE(brk->HasMultiResults());
+ EXPECT_TRUE(brk->Results().IsEmpty());
}
TEST_F(IR_BreakIfTest, Fail_NullLoop) {
diff --git a/src/tint/lang/core/ir/builder.cc b/src/tint/lang/core/ir/builder.cc
index f6f94ef..9315f8a 100644
--- a/src/tint/lang/core/ir/builder.cc
+++ b/src/tint/lang/core/ir/builder.cc
@@ -66,15 +66,25 @@
return Append(ir.instructions.Create<ir::Loop>(Block(), MultiInBlock(), MultiInBlock()));
}
-Block* Builder::Case(ir::Switch* s, VectorRef<Switch::CaseSelector> selectors) {
+Block* Builder::Case(ir::Switch* s, VectorRef<ir::Constant*> values) {
auto* block = Block();
- s->Cases().Push(Switch::Case{std::move(selectors), block});
+
+ Switch::Case c;
+ c.block = block;
+ for (auto* value : values) {
+ c.selectors.Push(Switch::CaseSelector{value});
+ }
+ s->Cases().Push(std::move(c));
block->SetParent(s);
return block;
}
-Block* Builder::Case(ir::Switch* s, std::initializer_list<Switch::CaseSelector> selectors) {
- return Case(s, Vector<Switch::CaseSelector, 4>(selectors));
+Block* Builder::DefaultCase(ir::Switch* s) {
+ return Case(s, Vector<ir::Constant*, 1>{nullptr});
+}
+
+Block* Builder::Case(ir::Switch* s, std::initializer_list<ir::Constant*> selectors) {
+ return Case(s, Vector<ir::Constant*, 4>(selectors));
}
ir::Discard* Builder::Discard() {
diff --git a/src/tint/lang/core/ir/builder.h b/src/tint/lang/core/ir/builder.h
index 6020902..2a89fa9 100644
--- a/src/tint/lang/core/ir/builder.h
+++ b/src/tint/lang/core/ir/builder.h
@@ -268,17 +268,22 @@
return Append(ir.instructions.Create<ir::Switch>(cond_val));
}
- /// Creates a case for the switch @p s with the given selectors
+ /// Creates a default case for the switch @p s
/// @param s the switch to create the case into
- /// @param selectors the case selectors for the case statement
/// @returns the start block for the case instruction
- ir::Block* Case(ir::Switch* s, VectorRef<Switch::CaseSelector> selectors);
+ ir::Block* DefaultCase(ir::Switch* s);
/// Creates a case for the switch @p s with the given selectors
/// @param s the switch to create the case into
- /// @param selectors the case selectors for the case statement
+ /// @param values the case selector values for the case statement
/// @returns the start block for the case instruction
- ir::Block* Case(ir::Switch* s, std::initializer_list<Switch::CaseSelector> selectors);
+ ir::Block* Case(ir::Switch* s, VectorRef<ir::Constant*> values);
+
+ /// Creates a case for the switch @p s with the given selectors
+ /// @param s the switch to create the case into
+ /// @param values the case selector values for the case statement
+ /// @returns the start block for the case instruction
+ ir::Block* Case(ir::Switch* s, std::initializer_list<ir::Constant*> values);
/// Creates a new ir::Constant
/// @param val the constant value
@@ -396,8 +401,9 @@
return in; /// Pass-through
} else if constexpr (is_instruction) {
/// Extract the first result from the instruction
- TINT_ASSERT(in->HasResults() && !in->HasMultiResults());
- return in->Result();
+ auto results = in->Results();
+ TINT_ASSERT(results.Length() == 1);
+ return results[0];
}
} else if constexpr (is_numeric) {
/// Creates a value from the given number
@@ -454,6 +460,17 @@
return Binary(BinaryOp::kAnd, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an And operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* And(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return And(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an Or operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -464,6 +481,17 @@
return Binary(BinaryOp::kOr, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an Or operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* Or(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Or(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an Xor operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -474,6 +502,17 @@
return Binary(BinaryOp::kXor, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an Xor operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* Xor(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Xor(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an Equal operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -484,6 +523,17 @@
return Binary(BinaryOp::kEqual, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an Equal operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* Equal(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Equal(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an NotEqual operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -494,6 +544,17 @@
return Binary(BinaryOp::kNotEqual, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an NotEqual operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* NotEqual(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return NotEqual(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an LessThan operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -504,6 +565,17 @@
return Binary(BinaryOp::kLessThan, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an LessThan operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* LessThan(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return LessThan(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an GreaterThan operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -514,6 +586,17 @@
return Binary(BinaryOp::kGreaterThan, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an GreaterThan operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* GreaterThan(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return GreaterThan(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an LessThanEqual operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -525,6 +608,17 @@
std::forward<RHS>(rhs));
}
+ /// Creates an LessThanEqual operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* LessThanEqual(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return LessThanEqual(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an GreaterThanEqual operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -536,6 +630,17 @@
std::forward<RHS>(rhs));
}
+ /// Creates an GreaterThanEqual operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* GreaterThanEqual(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return GreaterThanEqual(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an ShiftLeft operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -546,6 +651,17 @@
return Binary(BinaryOp::kShiftLeft, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an ShiftLeft operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* ShiftLeft(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return ShiftLeft(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an ShiftRight operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -556,6 +672,17 @@
return Binary(BinaryOp::kShiftRight, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an ShiftRight operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* ShiftRight(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return ShiftRight(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an Add operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -566,6 +693,17 @@
return Binary(BinaryOp::kAdd, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an Add operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* Add(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Add(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an Subtract operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -576,6 +714,17 @@
return Binary(BinaryOp::kSubtract, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an Subtract operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* Subtract(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Subtract(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an Multiply operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -586,6 +735,17 @@
return Binary(BinaryOp::kMultiply, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an Multiply operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* Multiply(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Multiply(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an Divide operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -596,6 +756,17 @@
return Binary(BinaryOp::kDivide, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an Divide operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* Divide(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Divide(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an Modulo operation
/// @param type the result type of the expression
/// @param lhs the lhs of the add
@@ -606,6 +777,17 @@
return Binary(BinaryOp::kModulo, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
+ /// Creates an Modulo operation
+ /// @tparam TYPE the result type of the expression
+ /// @param lhs the lhs of the add
+ /// @param rhs the rhs of the add
+ /// @returns the operation
+ template <typename TYPE, typename LHS, typename RHS>
+ ir::Binary* Modulo(LHS&& lhs, RHS&& rhs) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Modulo(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
+ }
+
/// Creates an op for `op val`
/// @param op the unary operator
/// @param type the result type of the binary expression
@@ -617,6 +799,17 @@
return Append(ir.instructions.Create<ir::Unary>(InstructionResult(type), op, value));
}
+ /// Creates an op for `op val`
+ /// @param op the unary operator
+ /// @tparam TYPE the result type of the binary expression
+ /// @param val the value of the operation
+ /// @returns the operation
+ template <typename TYPE, typename VAL>
+ ir::Unary* Unary(UnaryOp op, VAL&& val) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Unary(op, type, std::forward<VAL>(val));
+ }
+
/// Creates a Complement operation
/// @param type the result type of the expression
/// @param val the value
@@ -626,6 +819,16 @@
return Unary(ir::UnaryOp::kComplement, type, std::forward<VAL>(val));
}
+ /// Creates a Complement operation
+ /// @tparam TYPE the result type of the expression
+ /// @param val the value
+ /// @returns the operation
+ template <typename TYPE, typename VAL>
+ ir::Unary* Complement(VAL&& val) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Complement(type, std::forward<VAL>(val));
+ }
+
/// Creates a Negation operation
/// @param type the result type of the expression
/// @param val the value
@@ -635,6 +838,16 @@
return Unary(ir::UnaryOp::kNegation, type, std::forward<VAL>(val));
}
+ /// Creates a Negation operation
+ /// @tparam TYPE the result type of the expression
+ /// @param val the value
+ /// @returns the operation
+ template <typename TYPE, typename VAL>
+ ir::Unary* Negation(VAL&& val) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Negation(type, std::forward<VAL>(val));
+ }
+
/// Creates a Not operation
/// @param type the result type of the expression
/// @param val the value
@@ -648,6 +861,16 @@
}
}
+ /// Creates a Not operation
+ /// @tparam TYPE the result type of the expression
+ /// @param val the value
+ /// @returns the operation
+ template <typename TYPE, typename VAL>
+ ir::Binary* Not(VAL&& val) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Not(type, std::forward<VAL>(val));
+ }
+
/// Creates a bitcast instruction
/// @param type the result type of the bitcast
/// @param val the value being bitcast
@@ -658,6 +881,17 @@
return Append(ir.instructions.Create<ir::Bitcast>(InstructionResult(type), value));
}
+ /// Creates a bitcast instruction
+ /// @tparam TYPE the result type of the bitcast
+ /// @param val the value being bitcast
+ /// @returns the instruction
+ template <typename TYPE, typename VAL>
+ ir::Bitcast* Bitcast(VAL&& val) {
+ auto* type = ir.Types().Get<TYPE>();
+ auto* value = Value(std::forward<VAL>(val));
+ return Bitcast(type, value);
+ }
+
/// Creates a discard instruction
/// @returns the instruction
ir::Discard* Discard();
@@ -682,6 +916,18 @@
Values(std::forward<ARGS>(args)...)));
}
+ /// Creates a user function call instruction
+ /// @tparam TYPE the return type of the call
+ /// @param func the function to call
+ /// @param args the call arguments
+ /// @returns the instruction
+ template <typename TYPE, typename... ARGS>
+ ir::UserCall* Call(ir::Function* func, ARGS&&... args) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Append(ir.instructions.Create<ir::UserCall>(InstructionResult(type), func,
+ Values(std::forward<ARGS>(args)...)));
+ }
+
/// Creates a core builtin call instruction
/// @param type the return type of the call
/// @param func the builtin function to call
@@ -694,6 +940,18 @@
}
/// Creates a core builtin call instruction
+ /// @tparam TYPE the return type of the call
+ /// @param func the builtin function to call
+ /// @param args the call arguments
+ /// @returns the instruction
+ template <typename TYPE, typename... ARGS>
+ ir::CoreBuiltinCall* Call(core::BuiltinFn func, ARGS&&... args) {
+ auto* type = ir.Types().Get<TYPE>();
+ return Append(ir.instructions.Create<ir::CoreBuiltinCall>(
+ InstructionResult(type), func, Values(std::forward<ARGS>(args)...)));
+ }
+
+ /// Creates a core builtin call instruction
/// @param type the return type of the call
/// @param func the builtin function to call
/// @param args the call arguments
@@ -820,7 +1078,7 @@
}
auto* var = Var(name, ir.Types().ptr(SPACE, val->Type(), ACCESS));
var->SetInitializer(val);
- ir.SetName(var->Result(), name);
+ ir.SetName(var->Result(0), name);
return var;
}
@@ -857,7 +1115,16 @@
return nullptr;
}
auto* let = Append(ir.instructions.Create<ir::Let>(InstructionResult(val->Type()), val));
- ir.SetName(let->Result(), name);
+ ir.SetName(let->Result(0), name);
+ return let;
+ }
+
+ /// Creates a new `let` declaration, with an unassigned value
+ /// @param type the let type
+ /// @returns the instruction
+ ir::Let* Let(const type::Type* type) {
+ auto* let = ir.instructions.Create<ir::Let>(InstructionResult(type), nullptr);
+ Append(let);
return let;
}
@@ -980,6 +1247,16 @@
/// @returns the value
ir::FunctionParam* FunctionParam(std::string_view name, const core::type::Type* type);
+ /// Creates a new `FunctionParam` with a name.
+ /// @tparam TYPE the parameter type
+ /// @param name the parameter name
+ /// @returns the value
+ template <typename TYPE>
+ ir::FunctionParam* FunctionParam(std::string_view name) {
+ auto* type = ir.Types().Get<TYPE>();
+ return FunctionParam(name, type);
+ }
+
/// Creates a new `Access`
/// @param type the return type
/// @param object the object being accessed
@@ -1019,6 +1296,16 @@
Vector<uint32_t, 4>(indices)));
}
+ /// Name names the value or instruction with @p name
+ /// @param name the new name for the value or instruction
+ /// @param object the value or instruction
+ /// @return @p object
+ template <typename OBJECT>
+ OBJECT* Name(std::string_view name, OBJECT* object) {
+ ir.SetName(object, name);
+ return object;
+ }
+
/// Creates a terminate invocation instruction
/// @returns the instruction
ir::TerminateInvocation* TerminateInvocation();
diff --git a/src/tint/lang/core/ir/builtin_call.h b/src/tint/lang/core/ir/builtin_call.h
index 73ed85a..0351ff4 100644
--- a/src/tint/lang/core/ir/builtin_call.h
+++ b/src/tint/lang/core/ir/builtin_call.h
@@ -47,10 +47,10 @@
~BuiltinCall() override;
/// @returns the identifier for the function
- virtual size_t FuncId() = 0;
+ virtual size_t FuncId() const = 0;
/// @returns the table data to validate this builtin
- virtual const core::intrinsic::TableData& TableData() = 0;
+ virtual const core::intrinsic::TableData& TableData() const = 0;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/call.h b/src/tint/lang/core/ir/call.h
index 6df2c85..b56a092 100644
--- a/src/tint/lang/core/ir/call.h
+++ b/src/tint/lang/core/ir/call.h
@@ -38,8 +38,16 @@
public:
~Call() override;
+ /// @returns the offset of the arguments in Operands()
+ virtual size_t ArgsOperandOffset() const { return 0; }
+
/// @returns the call arguments
- virtual tint::Slice<Value*> Args() { return operands_.Slice(); }
+ tint::Slice<Value* const> Args() { return operands_.Slice().Offset(ArgsOperandOffset()); }
+
+ /// @returns the call arguments
+ tint::Slice<const Value* const> Args() const {
+ return operands_.Slice().Offset(ArgsOperandOffset());
+ }
/// Append a new argument to the argument list for this call instruction.
/// @param arg the argument value to append
diff --git a/src/tint/lang/core/ir/clone_context.h b/src/tint/lang/core/ir/clone_context.h
index 9c09f98..221fb83 100644
--- a/src/tint/lang/core/ir/clone_context.h
+++ b/src/tint/lang/core/ir/clone_context.h
@@ -28,6 +28,7 @@
#ifndef SRC_TINT_LANG_CORE_IR_CLONE_CONTEXT_H_
#define SRC_TINT_LANG_CORE_IR_CLONE_CONTEXT_H_
+#include "src/tint/utils/containers/const_propagating_ptr.h"
#include "src/tint/utils/containers/hashmap.h"
#include "src/tint/utils/containers/transform.h"
#include "src/tint/utils/traits/traits.h"
@@ -63,6 +64,14 @@
return result;
}
+ /// Performs a clone of @p what.
+ /// @param what the item to clone
+ /// @return the cloned item
+ template <typename T>
+ T* Clone(ConstPropagatingPtr<T>& what) {
+ return Clone(what.Get());
+ }
+
/// Performs a clone of all the elements in @p what.
/// @param what the elements to clone
/// @return the cloned elements
@@ -98,6 +107,14 @@
return what;
}
+ /// Obtains the (potentially) remapped pointer to @p what
+ /// @param what the item
+ /// @return the cloned item for @p what, or the original pointer if @p what has not been cloned.
+ template <typename T>
+ T* Remap(ConstPropagatingPtr<T>& what) {
+ return Remap(what.Get());
+ }
+
/// Obtains the (potentially) remapped pointer of all the elements in @p what.
/// @param what the item
/// @return the remapped elements
diff --git a/src/tint/lang/core/ir/constant.h b/src/tint/lang/core/ir/constant.h
index 3b29da9..c5fb574 100644
--- a/src/tint/lang/core/ir/constant.h
+++ b/src/tint/lang/core/ir/constant.h
@@ -42,10 +42,10 @@
~Constant() override;
/// @returns the constants value
- const core::constant::Value* Value() { return value_; }
+ const core::constant::Value* Value() const { return value_; }
/// @returns the type of the constant
- const core::type::Type* Type() override { return value_->Type(); }
+ const core::type::Type* Type() const override { return value_->Type(); }
/// @copydoc Value::Clone()
Constant* Clone(CloneContext& ctx) override;
diff --git a/src/tint/lang/core/ir/construct.cc b/src/tint/lang/core/ir/construct.cc
index d3a81b9..fd67aee 100644
--- a/src/tint/lang/core/ir/construct.cc
+++ b/src/tint/lang/core/ir/construct.cc
@@ -44,7 +44,7 @@
Construct::~Construct() = default;
Construct* Construct::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto args = ctx.Remap<Construct::kDefaultNumOperands>(Args());
return ctx.ir.instructions.Create<Construct>(new_result, args);
}
diff --git a/src/tint/lang/core/ir/construct.h b/src/tint/lang/core/ir/construct.h
index 0bbcbe3..ff9ca22 100644
--- a/src/tint/lang/core/ir/construct.h
+++ b/src/tint/lang/core/ir/construct.h
@@ -51,7 +51,7 @@
Construct* Clone(CloneContext& ctx) override;
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "construct"; }
+ std::string FriendlyName() const override { return "construct"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/construct_test.cc b/src/tint/lang/core/ir/construct_test.cc
index 51cf309..04c68dc 100644
--- a/src/tint/lang/core/ir/construct_test.cc
+++ b/src/tint/lang/core/ir/construct_test.cc
@@ -51,10 +51,9 @@
auto* arg2 = b.Constant(false);
auto* c = b.Construct(mod.Types().f32(), arg1, arg2);
- EXPECT_TRUE(c->HasResults());
- EXPECT_FALSE(c->HasMultiResults());
- EXPECT_TRUE(c->Result()->Is<InstructionResult>());
- EXPECT_EQ(c, c->Result()->Source());
+ EXPECT_EQ(c->Results().Length(), 1u);
+ EXPECT_TRUE(c->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(c, c->Result(0)->Instruction());
}
TEST_F(IR_ConstructTest, Fail_NullType) {
@@ -75,8 +74,8 @@
auto* new_c = clone_ctx.Clone(c);
EXPECT_NE(c, new_c);
- EXPECT_NE(c->Result(), new_c->Result());
- EXPECT_EQ(mod.Types().f32(), new_c->Result()->Type());
+ EXPECT_NE(c->Result(0), new_c->Result(0));
+ EXPECT_EQ(mod.Types().f32(), new_c->Result(0)->Type());
auto args = new_c->Args();
EXPECT_EQ(2u, args.Length());
@@ -92,8 +91,8 @@
auto* c = b.Construct(mod.Types().f32());
auto* new_c = clone_ctx.Clone(c);
- EXPECT_NE(c->Result(), new_c->Result());
- EXPECT_EQ(mod.Types().f32(), new_c->Result()->Type());
+ EXPECT_NE(c->Result(0), new_c->Result(0));
+ EXPECT_EQ(mod.Types().f32(), new_c->Result(0)->Type());
EXPECT_TRUE(new_c->Args().IsEmpty());
}
diff --git a/src/tint/lang/core/ir/continue.h b/src/tint/lang/core/ir/continue.h
index ff6e999..6233282 100644
--- a/src/tint/lang/core/ir/continue.h
+++ b/src/tint/lang/core/ir/continue.h
@@ -31,6 +31,7 @@
#include <string>
#include "src/tint/lang/core/ir/terminator.h"
+#include "src/tint/utils/containers/const_propagating_ptr.h"
#include "src/tint/utils/rtti/castable.h"
// Forward declarations
@@ -58,11 +59,14 @@
/// @returns the loop owning the continue block
ir::Loop* Loop() { return loop_; }
+ /// @returns the loop owning the continue block
+ const ir::Loop* Loop() const { return loop_; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "continue"; }
+ std::string FriendlyName() const override { return "continue"; }
private:
- ir::Loop* loop_ = nullptr;
+ ConstPropagatingPtr<ir::Loop> loop_;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/continue_test.cc b/src/tint/lang/core/ir/continue_test.cc
index a25d232..5346bde 100644
--- a/src/tint/lang/core/ir/continue_test.cc
+++ b/src/tint/lang/core/ir/continue_test.cc
@@ -55,8 +55,7 @@
auto* brk = b.Continue(loop, arg1, arg2);
- EXPECT_FALSE(brk->HasResults());
- EXPECT_FALSE(brk->HasMultiResults());
+ EXPECT_TRUE(brk->Results().IsEmpty());
}
TEST_F(IR_ContinueTest, Fail_NullLoop) {
diff --git a/src/tint/lang/core/ir/control_instruction.h b/src/tint/lang/core/ir/control_instruction.h
index 0bd994b..cb172db 100644
--- a/src/tint/lang/core/ir/control_instruction.h
+++ b/src/tint/lang/core/ir/control_instruction.h
@@ -59,13 +59,13 @@
void SetResults(VectorRef<InstructionResult*> values) {
for (auto* value : results_) {
if (value) {
- value->SetSource(nullptr);
+ value->SetInstruction(nullptr);
}
}
results_ = std::move(values);
for (auto* value : results_) {
if (value) {
- value->SetSource(this);
+ value->SetInstruction(this);
}
}
}
diff --git a/src/tint/lang/core/ir/convert.cc b/src/tint/lang/core/ir/convert.cc
index 92639f6..4a479de 100644
--- a/src/tint/lang/core/ir/convert.cc
+++ b/src/tint/lang/core/ir/convert.cc
@@ -44,7 +44,7 @@
Convert::~Convert() = default;
Convert* Convert::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto* val = ctx.Remap(Args()[0]);
return ctx.ir.instructions.Create<Convert>(new_result, val);
}
diff --git a/src/tint/lang/core/ir/convert.h b/src/tint/lang/core/ir/convert.h
index 7e8d47c..20350aa 100644
--- a/src/tint/lang/core/ir/convert.h
+++ b/src/tint/lang/core/ir/convert.h
@@ -52,7 +52,7 @@
Convert* Clone(CloneContext& ctx) override;
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "convert"; }
+ std::string FriendlyName() const override { return "convert"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/convert_test.cc b/src/tint/lang/core/ir/convert_test.cc
index fad55b5..ad5f53d 100644
--- a/src/tint/lang/core/ir/convert_test.cc
+++ b/src/tint/lang/core/ir/convert_test.cc
@@ -48,10 +48,9 @@
TEST_F(IR_ConvertTest, Results) {
auto* c = b.Convert(mod.Types().i32(), 1_u);
- EXPECT_TRUE(c->HasResults());
- EXPECT_FALSE(c->HasMultiResults());
- EXPECT_TRUE(c->Result()->Is<InstructionResult>());
- EXPECT_EQ(c->Result()->Source(), c);
+ EXPECT_EQ(c->Results().Length(), 1u);
+ EXPECT_TRUE(c->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(c->Result(0)->Instruction(), c);
}
TEST_F(IR_ConvertTest, Clone) {
@@ -60,8 +59,8 @@
auto* new_c = clone_ctx.Clone(c);
EXPECT_NE(c, new_c);
- EXPECT_NE(c->Result(), new_c->Result());
- EXPECT_EQ(mod.Types().f32(), new_c->Result()->Type());
+ EXPECT_NE(c->Result(0), new_c->Result(0));
+ EXPECT_EQ(mod.Types().f32(), new_c->Result(0)->Type());
auto args = new_c->Args();
EXPECT_EQ(1u, args.Length());
diff --git a/src/tint/lang/core/ir/core_builtin_call.cc b/src/tint/lang/core/ir/core_builtin_call.cc
index 3dd8483..33e38b5 100644
--- a/src/tint/lang/core/ir/core_builtin_call.cc
+++ b/src/tint/lang/core/ir/core_builtin_call.cc
@@ -48,7 +48,7 @@
CoreBuiltinCall::~CoreBuiltinCall() = default;
CoreBuiltinCall* CoreBuiltinCall::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto args = ctx.Remap<CoreBuiltinCall::kDefaultNumOperands>(Args());
return ctx.ir.instructions.Create<CoreBuiltinCall>(new_result, func_, args);
}
diff --git a/src/tint/lang/core/ir/core_builtin_call.h b/src/tint/lang/core/ir/core_builtin_call.h
index b102071..9e7e9f0 100644
--- a/src/tint/lang/core/ir/core_builtin_call.h
+++ b/src/tint/lang/core/ir/core_builtin_call.h
@@ -54,16 +54,16 @@
CoreBuiltinCall* Clone(CloneContext& ctx) override;
/// @returns the builtin function
- core::BuiltinFn Func() { return func_; }
+ core::BuiltinFn Func() const { return func_; }
/// @returns the identifier for the function
- size_t FuncId() override { return static_cast<size_t>(func_); }
+ size_t FuncId() const override { return static_cast<size_t>(func_); }
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return core::str(func_); }
+ std::string FriendlyName() const override { return core::str(func_); }
/// @returns the table data to validate this builtin
- const core::intrinsic::TableData& TableData() override {
+ const core::intrinsic::TableData& TableData() const override {
return core::intrinsic::Dialect::kData;
}
diff --git a/src/tint/lang/core/ir/core_builtin_call_test.cc b/src/tint/lang/core/ir/core_builtin_call_test.cc
index 447788a..05965f8 100644
--- a/src/tint/lang/core/ir/core_builtin_call_test.cc
+++ b/src/tint/lang/core/ir/core_builtin_call_test.cc
@@ -50,10 +50,9 @@
auto* arg2 = b.Constant(2_u);
auto* builtin = b.Call(mod.Types().f32(), core::BuiltinFn::kAbs, arg1, arg2);
- EXPECT_TRUE(builtin->HasResults());
- EXPECT_FALSE(builtin->HasMultiResults());
- EXPECT_TRUE(builtin->Result()->Is<InstructionResult>());
- EXPECT_EQ(builtin->Result()->Source(), builtin);
+ EXPECT_EQ(builtin->Results().Length(), 1u);
+ EXPECT_TRUE(builtin->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(builtin->Result(0)->Instruction(), builtin);
}
TEST_F(IR_CoreBuiltinCallTest, Fail_NullType) {
@@ -92,8 +91,8 @@
auto* new_b = clone_ctx.Clone(builtin);
EXPECT_NE(builtin, new_b);
- EXPECT_NE(builtin->Result(), new_b->Result());
- EXPECT_EQ(mod.Types().f32(), new_b->Result()->Type());
+ EXPECT_NE(builtin->Result(0), new_b->Result(0));
+ EXPECT_EQ(mod.Types().f32(), new_b->Result(0)->Type());
EXPECT_EQ(core::BuiltinFn::kAbs, new_b->Func());
@@ -111,8 +110,8 @@
auto* builtin = b.Call(mod.Types().f32(), core::BuiltinFn::kAbs);
auto* new_b = clone_ctx.Clone(builtin);
- EXPECT_NE(builtin->Result(), new_b->Result());
- EXPECT_EQ(mod.Types().f32(), new_b->Result()->Type());
+ EXPECT_NE(builtin->Result(0), new_b->Result(0));
+ EXPECT_EQ(mod.Types().f32(), new_b->Result(0)->Type());
EXPECT_EQ(core::BuiltinFn::kAbs, new_b->Func());
diff --git a/src/tint/lang/core/ir/disassembler.cc b/src/tint/lang/core/ir/disassembler.cc
index 09d5c75..728004c 100644
--- a/src/tint/lang/core/ir/disassembler.cc
+++ b/src/tint/lang/core/ir/disassembler.cc
@@ -87,11 +87,11 @@
} // namespace
-std::string Disassemble(Module& mod) {
+std::string Disassemble(const Module& mod) {
return Disassembler{mod}.Disassemble();
}
-Disassembler::Disassembler(Module& mod) : mod_(mod) {}
+Disassembler::Disassembler(const Module& mod) : mod_(mod) {}
Disassembler::~Disassembler() = default;
@@ -108,12 +108,12 @@
current_output_start_pos_ = out_.tellp();
}
-size_t Disassembler::IdOf(Block* node) {
+size_t Disassembler::IdOf(const Block* node) {
TINT_ASSERT(node);
return block_ids_.GetOrCreate(node, [&] { return block_ids_.Count(); });
}
-std::string Disassembler::IdOf(Value* value) {
+std::string Disassembler::IdOf(const Value* value) {
TINT_ASSERT(value);
return value_ids_.GetOrCreate(value, [&] {
if (auto sym = mod_.NameOf(value)) {
@@ -132,7 +132,7 @@
});
}
-std::string Disassembler::NameOf(If* inst) {
+std::string Disassembler::NameOf(const If* inst) {
if (!inst) {
return "undef";
}
@@ -140,7 +140,7 @@
return if_names_.GetOrCreate(inst, [&] { return "if_" + std::to_string(if_names_.Count()); });
}
-std::string Disassembler::NameOf(Loop* inst) {
+std::string Disassembler::NameOf(const Loop* inst) {
if (!inst) {
return "undef";
}
@@ -149,7 +149,7 @@
[&] { return "loop_" + std::to_string(loop_names_.Count()); });
}
-std::string Disassembler::NameOf(Switch* inst) {
+std::string Disassembler::NameOf(const Switch* inst) {
if (!inst) {
return "undef";
}
@@ -174,13 +174,13 @@
EmitLine();
}
- for (auto* func : mod_.functions) {
+ for (auto& func : mod_.functions) {
EmitFunction(func);
}
return out_.str();
}
-void Disassembler::EmitBlock(Block* blk, std::string_view comment /* = "" */) {
+void Disassembler::EmitBlock(const Block* blk, std::string_view comment /* = "" */) {
Indent();
SourceMarker sm(this);
@@ -229,7 +229,7 @@
}
}
-void Disassembler::EmitParamAttributes(FunctionParam* p) {
+void Disassembler::EmitParamAttributes(const FunctionParam* p) {
if (!p->Invariant() && !p->Location().has_value() && !p->BindingPoint().has_value() &&
!p->Builtin().has_value()) {
return;
@@ -266,7 +266,7 @@
out_ << "]";
}
-void Disassembler::EmitReturnAttributes(Function* func) {
+void Disassembler::EmitReturnAttributes(const Function* func) {
if (!func->ReturnInvariant() && !func->ReturnLocation().has_value() &&
!func->ReturnBuiltin().has_value()) {
return;
@@ -298,7 +298,7 @@
out_ << "]";
}
-void Disassembler::EmitFunction(Function* func) {
+void Disassembler::EmitFunction(const Function* func) {
in_function_ = true;
std::string fn_id = IdOf(func);
@@ -358,17 +358,17 @@
EmitLine();
}
-void Disassembler::EmitValueWithType(Instruction* val) {
+void Disassembler::EmitValueWithType(const Instruction* val) {
SourceMarker sm(this);
- if (val->Result()) {
- EmitValueWithType(val->Result());
+ if (val->Result(0)) {
+ EmitValueWithType(val->Result(0));
} else {
out_ << "undef";
}
- sm.StoreResult(Usage{val, 0});
+ sm.StoreResult(IndexedValue{val, 0});
}
-void Disassembler::EmitValueWithType(Value* val) {
+void Disassembler::EmitValueWithType(const Value* val) {
if (!val) {
out_ << "undef";
return;
@@ -378,10 +378,10 @@
out_ << ":" << val->Type()->FriendlyName();
}
-void Disassembler::EmitValue(Value* val) {
+void Disassembler::EmitValue(const Value* val) {
tint::Switch(
val,
- [&](ir::Constant* constant) {
+ [&](const ir::Constant* constant) {
std::function<void(const core::constant::Value*)> emit =
[&](const core::constant::Value* c) {
tint::Switch(
@@ -427,10 +427,12 @@
};
emit(constant->Value());
},
- [&](ir::InstructionResult* rv) { out_ << "%" << IdOf(rv); },
- [&](ir::BlockParam* p) { out_ << "%" << IdOf(p) << ":" << p->Type()->FriendlyName(); },
- [&](ir::FunctionParam* p) { out_ << "%" << IdOf(p); },
- [&](ir::Function* f) { out_ << "%" << IdOf(f); },
+ [&](const ir::InstructionResult* rv) { out_ << "%" << IdOf(rv); },
+ [&](const ir::BlockParam* p) {
+ out_ << "%" << IdOf(p) << ":" << p->Type()->FriendlyName();
+ },
+ [&](const ir::FunctionParam* p) { out_ << "%" << IdOf(p); },
+ [&](const ir::Function* f) { out_ << "%" << IdOf(f); },
[&](Default) {
if (val == nullptr) {
out_ << "undef";
@@ -440,13 +442,13 @@
});
}
-void Disassembler::EmitInstructionName(Instruction* inst) {
+void Disassembler::EmitInstructionName(const Instruction* inst) {
SourceMarker sm(this);
out_ << inst->FriendlyName();
sm.Store(inst);
}
-void Disassembler::EmitInstruction(Instruction* inst) {
+void Disassembler::EmitInstruction(const Instruction* inst) {
TINT_DEFER(EmitLine());
if (!inst->Alive()) {
@@ -456,26 +458,26 @@
return;
}
tint::Switch(
- inst, //
- [&](Switch* s) { EmitSwitch(s); }, //
- [&](If* i) { EmitIf(i); }, //
- [&](Loop* l) { EmitLoop(l); }, //
- [&](Binary* b) { EmitBinary(b); }, //
- [&](Unary* u) { EmitUnary(u); }, //
- [&](Discard* d) { EmitInstructionName(d); },
- [&](Store* s) {
+ inst, //
+ [&](const Switch* s) { EmitSwitch(s); }, //
+ [&](const If* i) { EmitIf(i); }, //
+ [&](const Loop* l) { EmitLoop(l); }, //
+ [&](const Binary* b) { EmitBinary(b); }, //
+ [&](const Unary* u) { EmitUnary(u); }, //
+ [&](const Discard* d) { EmitInstructionName(d); },
+ [&](const Store* s) {
EmitInstructionName(s);
out_ << " ";
EmitOperand(s, Store::kToOperandOffset);
out_ << ", ";
EmitOperand(s, Store::kFromOperandOffset);
},
- [&](StoreVectorElement* s) {
+ [&](const StoreVectorElement* s) {
EmitInstructionName(s);
out_ << " ";
EmitOperandList(s);
},
- [&](UserCall* uc) {
+ [&](const UserCall* uc) {
EmitValueWithType(uc);
out_ << " = ";
EmitInstructionName(uc);
@@ -486,7 +488,7 @@
}
EmitOperandList(uc, UserCall::kArgsOperandOffset);
},
- [&](Var* v) {
+ [&](const Var* v) {
EmitValueWithType(v);
out_ << " = ";
EmitInstructionName(v);
@@ -519,7 +521,7 @@
out_ << " @builtin(" << v->Attributes().builtin.value() << ")";
}
},
- [&](Swizzle* s) {
+ [&](const Swizzle* s) {
EmitValueWithType(s);
out_ << " = ";
EmitInstructionName(s);
@@ -543,7 +545,7 @@
}
}
},
- [&](Terminator* b) { EmitTerminator(b); },
+ [&](const Terminator* b) { EmitTerminator(b); },
[&](Default) {
EmitValueWithType(inst);
out_ << " = ";
@@ -572,13 +574,13 @@
}
}
-void Disassembler::EmitOperand(Instruction* inst, size_t index) {
- SourceMarker condMarker(this);
+void Disassembler::EmitOperand(const Instruction* inst, size_t index) {
+ SourceMarker marker(this);
EmitValue(inst->Operands()[index]);
- condMarker.Store(Usage{inst, static_cast<uint32_t>(index)});
+ marker.Store(IndexedValue{inst, static_cast<uint32_t>(index)});
}
-void Disassembler::EmitOperandList(Instruction* inst, size_t start_index /* = 0 */) {
+void Disassembler::EmitOperandList(const Instruction* inst, size_t start_index /* = 0 */) {
for (size_t i = start_index, n = inst->Operands().Length(); i < n; i++) {
if (i != start_index) {
out_ << ", ";
@@ -587,17 +589,16 @@
}
}
-void Disassembler::EmitIf(If* if_) {
+void Disassembler::EmitIf(const If* if_) {
SourceMarker sm(this);
- if (if_->HasResults()) {
- auto res = if_->Results();
- for (size_t i = 0; i < res.Length(); ++i) {
+ if (auto results = if_->Results(); !results.IsEmpty()) {
+ for (size_t i = 0; i < results.Length(); ++i) {
if (i > 0) {
out_ << ", ";
}
SourceMarker rs(this);
- EmitValueWithType(res[i]);
- rs.StoreResult(Usage{if_, i});
+ EmitValueWithType(results[i]);
+ rs.StoreResult(IndexedValue{if_, i});
}
out_ << " = ";
}
@@ -625,7 +626,7 @@
if (has_false) {
ScopedIndent si(indent_size_);
EmitBlock(if_->False(), "false");
- } else if (if_->HasResults()) {
+ } else if (auto results = if_->Results(); !results.IsEmpty()) {
ScopedIndent si(indent_size_);
Indent();
out_ << "# implicit false block: exit_if undef";
@@ -639,7 +640,7 @@
out_ << "}";
}
-void Disassembler::EmitLoop(Loop* l) {
+void Disassembler::EmitLoop(const Loop* l) {
Vector<std::string, 3> parts;
if (!l->Initializer()->IsEmpty()) {
parts.Push("i: %b" + std::to_string(IdOf(l->Initializer())));
@@ -650,15 +651,14 @@
parts.Push("c: %b" + std::to_string(IdOf(l->Continuing())));
}
SourceMarker sm(this);
- if (l->HasResults()) {
- auto res = l->Results();
- for (size_t i = 0; i < res.Length(); ++i) {
+ if (auto results = l->Results(); !results.IsEmpty()) {
+ for (size_t i = 0; i < results.Length(); ++i) {
if (i > 0) {
out_ << ", ";
}
SourceMarker rs(this);
- EmitValueWithType(res[i]);
- rs.StoreResult(Usage{l, i});
+ EmitValueWithType(results[i]);
+ rs.StoreResult(IndexedValue{l, i});
}
out_ << " = ";
}
@@ -688,17 +688,16 @@
out_ << "}";
}
-void Disassembler::EmitSwitch(Switch* s) {
+void Disassembler::EmitSwitch(const Switch* s) {
SourceMarker sm(this);
- if (s->HasResults()) {
- auto res = s->Results();
- for (size_t i = 0; i < res.Length(); ++i) {
+ if (auto results = s->Results(); !results.IsEmpty()) {
+ for (size_t i = 0; i < results.Length(); ++i) {
if (i > 0) {
out_ << ", ";
}
SourceMarker rs(this);
- EmitValueWithType(res[i]);
- rs.StoreResult(Usage{s, i});
+ EmitValueWithType(results[i]);
+ rs.StoreResult(IndexedValue{s, i});
}
out_ << " = ";
}
@@ -721,7 +720,7 @@
EmitValue(selector.val);
}
}
- out_ << ", %b" << IdOf(c.Block()) << ")";
+ out_ << ", %b" << IdOf(c.block) << ")";
}
out_ << "]";
sm.Store(s);
@@ -731,50 +730,50 @@
for (auto& c : s->Cases()) {
ScopedIndent si(indent_size_);
- EmitBlock(c.Block(), "case");
+ EmitBlock(c.block, "case");
}
Indent();
out_ << "}";
}
-void Disassembler::EmitTerminator(Terminator* b) {
+void Disassembler::EmitTerminator(const Terminator* b) {
SourceMarker sm(this);
size_t args_offset = 0;
tint::Switch(
b,
- [&](ir::Return*) {
+ [&](const ir::Return*) {
out_ << "ret";
- args_offset = ir::Return::kArgOperandOffset;
+ args_offset = ir::Return::kArgsOperandOffset;
},
- [&](ir::Continue* cont) {
+ [&](const ir::Continue* cont) {
out_ << "continue %b" << IdOf(cont->Loop()->Continuing());
args_offset = ir::Continue::kArgsOperandOffset;
},
- [&](ir::ExitIf*) {
+ [&](const ir::ExitIf*) {
out_ << "exit_if";
args_offset = ir::ExitIf::kArgsOperandOffset;
},
- [&](ir::ExitSwitch*) {
+ [&](const ir::ExitSwitch*) {
out_ << "exit_switch";
args_offset = ir::ExitSwitch::kArgsOperandOffset;
},
- [&](ir::ExitLoop*) {
+ [&](const ir::ExitLoop*) {
out_ << "exit_loop";
args_offset = ir::ExitLoop::kArgsOperandOffset;
},
- [&](ir::NextIteration* ni) {
+ [&](const ir::NextIteration* ni) {
out_ << "next_iteration %b" << IdOf(ni->Loop()->Body());
args_offset = ir::NextIteration::kArgsOperandOffset;
},
- [&](ir::Unreachable*) { out_ << "unreachable"; },
- [&](ir::BreakIf* bi) {
+ [&](const ir::Unreachable*) { out_ << "unreachable"; },
+ [&](const ir::BreakIf* bi) {
out_ << "break_if ";
EmitValue(bi->Condition());
out_ << " %b" << IdOf(bi->Loop()->Body());
args_offset = ir::BreakIf::kArgsOperandOffset;
},
- [&](ir::TerminateInvocation*) { out_ << "terminate_invocation"; },
+ [&](const ir::TerminateInvocation*) { out_ << "terminate_invocation"; },
[&](Default) { out_ << "unknown terminator " << b->TypeInfo().name; });
if (!b->Args().IsEmpty()) {
@@ -784,14 +783,14 @@
sm.Store(b);
tint::Switch(
- b, //
- [&](ir::ExitIf* e) { out_ << " # " << NameOf(e->If()); }, //
- [&](ir::ExitSwitch* e) { out_ << " # " << NameOf(e->Switch()); }, //
- [&](ir::ExitLoop* e) { out_ << " # " << NameOf(e->Loop()); } //
+ b, //
+ [&](const ir::ExitIf* e) { out_ << " # " << NameOf(e->If()); }, //
+ [&](const ir::ExitSwitch* e) { out_ << " # " << NameOf(e->Switch()); }, //
+ [&](const ir::ExitLoop* e) { out_ << " # " << NameOf(e->Loop()); } //
);
}
-void Disassembler::EmitValueList(tint::Slice<Value* const> values) {
+void Disassembler::EmitValueList(tint::Slice<const Value* const> values) {
for (size_t i = 0, n = values.Length(); i < n; i++) {
if (i > 0) {
out_ << ", ";
@@ -800,7 +799,7 @@
}
}
-void Disassembler::EmitBinary(Binary* b) {
+void Disassembler::EmitBinary(const Binary* b) {
SourceMarker sm(this);
EmitValueWithType(b);
out_ << " = ";
@@ -860,7 +859,7 @@
sm.Store(b);
}
-void Disassembler::EmitUnary(Unary* u) {
+void Disassembler::EmitUnary(const Unary* u) {
SourceMarker sm(this);
EmitValueWithType(u);
out_ << " = ";
diff --git a/src/tint/lang/core/ir/disassembler.h b/src/tint/lang/core/ir/disassembler.h
index d26d98c..8f15e95 100644
--- a/src/tint/lang/core/ir/disassembler.h
+++ b/src/tint/lang/core/ir/disassembler.h
@@ -51,14 +51,32 @@
/// @returns the disassembly for the module @p mod
/// @param mod the module to disassemble
-std::string Disassemble(Module& mod);
+std::string Disassemble(const Module& mod);
/// Helper class to disassemble the IR
class Disassembler {
public:
+ /// A reference to an instruction's operand or result.
+ struct IndexedValue {
+ /// The instruction that is using the value;
+ const Instruction* instruction = nullptr;
+ /// The index of the operand that is the value being used.
+ size_t index = 0u;
+
+ /// @returns the hash code of the IndexedValue
+ size_t HashCode() const { return Hash(instruction, index); }
+
+ /// An equality helper for IndexedValue.
+ /// @param other the IndexedValue to compare against
+ /// @returns true if the two IndexedValues are equal
+ bool operator==(const IndexedValue& other) const {
+ return instruction == other.instruction && index == other.index;
+ }
+ };
+
/// Constructor
/// @param mod the module
- explicit Disassembler(Module& mod);
+ explicit Disassembler(const Module& mod);
~Disassembler();
/// Returns the module as a string
@@ -70,41 +88,45 @@
/// @param inst the instruction to retrieve
/// @returns the source for the instruction
- Source InstructionSource(Instruction* inst) {
+ Source InstructionSource(const Instruction* inst) {
return instruction_to_src_.Get(inst).value_or(Source{});
}
/// @param operand the operand to retrieve
/// @returns the source for the operand
- Source OperandSource(Usage operand) { return operand_to_src_.Get(operand).value_or(Source{}); }
+ Source OperandSource(IndexedValue operand) {
+ return operand_to_src_.Get(operand).value_or(Source{});
+ }
/// @param result the result to retrieve
/// @returns the source for the result
- Source ResultSource(Usage result) { return result_to_src_.Get(result).value_or(Source{}); }
+ Source ResultSource(IndexedValue result) {
+ return result_to_src_.Get(result).value_or(Source{});
+ }
/// @param blk teh block to retrieve
/// @returns the source for the block
- Source BlockSource(Block* blk) { return block_to_src_.Get(blk).value_or(Source{}); }
+ Source BlockSource(const Block* blk) { return block_to_src_.Get(blk).value_or(Source{}); }
/// Stores the given @p src location for @p inst instruction
/// @param inst the instruction to store
/// @param src the source location
- void SetSource(Instruction* inst, Source src) { instruction_to_src_.Add(inst, src); }
+ void SetSource(const Instruction* inst, Source src) { instruction_to_src_.Add(inst, src); }
/// Stores the given @p src location for @p blk block
/// @param blk the block to store
/// @param src the source location
- void SetSource(Block* blk, Source src) { block_to_src_.Add(blk, src); }
+ void SetSource(const Block* blk, Source src) { block_to_src_.Add(blk, src); }
/// Stores the given @p src location for @p op operand
/// @param op the operand to store
/// @param src the source location
- void SetSource(Usage op, Source src) { operand_to_src_.Add(op, src); }
+ void SetSource(IndexedValue op, Source src) { operand_to_src_.Add(op, src); }
/// Stores the given @p src location for @p result
/// @param result the result to store
/// @param src the source location
- void SetResultSource(Usage result, Source src) { result_to_src_.Add(result, src); }
+ void SetResultSource(IndexedValue result, Source src) { result_to_src_.Add(result, src); }
/// @returns the source location for the current emission location
Source::Location MakeCurrentLocation();
@@ -115,13 +137,13 @@
explicit SourceMarker(Disassembler* d) : dis_(d), begin_(dis_->MakeCurrentLocation()) {}
~SourceMarker() = default;
- void Store(Instruction* inst) { dis_->SetSource(inst, MakeSource()); }
+ void Store(const Instruction* inst) { dis_->SetSource(inst, MakeSource()); }
- void Store(Block* blk) { dis_->SetSource(blk, MakeSource()); }
+ void Store(const Block* blk) { dis_->SetSource(blk, MakeSource()); }
- void Store(Usage operand) { dis_->SetSource(operand, MakeSource()); }
+ void Store(IndexedValue operand) { dis_->SetSource(operand, MakeSource()); }
- void StoreResult(Usage result) { dis_->SetResultSource(result, MakeSource()); }
+ void StoreResult(IndexedValue result) { dis_->SetResultSource(result, MakeSource()); }
Source MakeSource() const {
return Source(Source::Range(begin_, dis_->MakeCurrentLocation()));
@@ -134,39 +156,39 @@
StringStream& Indent();
- size_t IdOf(Block* blk);
- std::string IdOf(Value* node);
- std::string NameOf(If* inst);
- std::string NameOf(Loop* inst);
- std::string NameOf(Switch* inst);
+ size_t IdOf(const Block* blk);
+ std::string IdOf(const Value* node);
+ std::string NameOf(const If* inst);
+ std::string NameOf(const Loop* inst);
+ std::string NameOf(const Switch* inst);
- void EmitBlock(Block* blk, std::string_view comment = "");
- void EmitFunction(Function* func);
- void EmitParamAttributes(FunctionParam* p);
- void EmitReturnAttributes(Function* func);
+ void EmitBlock(const Block* blk, std::string_view comment = "");
+ void EmitFunction(const Function* func);
+ void EmitParamAttributes(const FunctionParam* p);
+ void EmitReturnAttributes(const Function* func);
void EmitBindingPoint(BindingPoint p);
void EmitLocation(Location loc);
- void EmitInstruction(Instruction* inst);
- void EmitValueWithType(Instruction* val);
- void EmitValueWithType(Value* val);
- void EmitValue(Value* val);
- void EmitValueList(tint::Slice<ir::Value* const> values);
- void EmitBinary(Binary* b);
- void EmitUnary(Unary* b);
- void EmitTerminator(Terminator* b);
- void EmitSwitch(Switch* s);
- void EmitLoop(Loop* l);
- void EmitIf(If* i);
+ void EmitInstruction(const Instruction* inst);
+ void EmitValueWithType(const Instruction* val);
+ void EmitValueWithType(const Value* val);
+ void EmitValue(const Value* val);
+ void EmitValueList(tint::Slice<const ir::Value* const> values);
+ void EmitBinary(const Binary* b);
+ void EmitUnary(const Unary* b);
+ void EmitTerminator(const Terminator* b);
+ void EmitSwitch(const Switch* s);
+ void EmitLoop(const Loop* l);
+ void EmitIf(const If* i);
void EmitStructDecl(const core::type::Struct* str);
void EmitLine();
- void EmitOperand(Instruction* inst, size_t index);
- void EmitOperandList(Instruction* inst, size_t start_index = 0);
- void EmitInstructionName(Instruction* inst);
+ void EmitOperand(const Instruction* inst, size_t index);
+ void EmitOperandList(const Instruction* inst, size_t start_index = 0);
+ void EmitInstructionName(const Instruction* inst);
- Module& mod_;
+ const Module& mod_;
StringStream out_;
- Hashmap<Block*, size_t, 32> block_ids_;
- Hashmap<Value*, std::string, 32> value_ids_;
+ Hashmap<const Block*, size_t, 32> block_ids_;
+ Hashmap<const Value*, std::string, 32> value_ids_;
Hashset<std::string, 32> ids_;
uint32_t indent_size_ = 0;
bool in_function_ = false;
@@ -174,13 +196,13 @@
uint32_t current_output_line_ = 1;
uint32_t current_output_start_pos_ = 0;
- Hashmap<Block*, Source, 8> block_to_src_;
- Hashmap<Instruction*, Source, 8> instruction_to_src_;
- Hashmap<Usage, Source, 8, Usage::Hasher> operand_to_src_;
- Hashmap<Usage, Source, 8, Usage::Hasher> result_to_src_;
- Hashmap<If*, std::string, 8> if_names_;
- Hashmap<Loop*, std::string, 8> loop_names_;
- Hashmap<Switch*, std::string, 8> switch_names_;
+ Hashmap<const Block*, Source, 8> block_to_src_;
+ Hashmap<const Instruction*, Source, 8> instruction_to_src_;
+ Hashmap<IndexedValue, Source, 8> operand_to_src_;
+ Hashmap<IndexedValue, Source, 8> result_to_src_;
+ Hashmap<const If*, std::string, 8> if_names_;
+ Hashmap<const Loop*, std::string, 8> loop_names_;
+ Hashmap<const Switch*, std::string, 8> switch_names_;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/discard.h b/src/tint/lang/core/ir/discard.h
index 31a805d..62e20f7 100644
--- a/src/tint/lang/core/ir/discard.h
+++ b/src/tint/lang/core/ir/discard.h
@@ -46,7 +46,7 @@
Discard* Clone(CloneContext& ctx) override;
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "discard"; }
+ std::string FriendlyName() const override { return "discard"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/discard_test.cc b/src/tint/lang/core/ir/discard_test.cc
index bc9bc09..098b99f 100644
--- a/src/tint/lang/core/ir/discard_test.cc
+++ b/src/tint/lang/core/ir/discard_test.cc
@@ -43,8 +43,7 @@
TEST_F(IR_DiscardTest, Result) {
auto* inst = b.Discard();
- EXPECT_FALSE(inst->HasResults());
- EXPECT_FALSE(inst->HasMultiResults());
+ EXPECT_TRUE(inst->Results().IsEmpty());
}
TEST_F(IR_DiscardTest, Clone) {
diff --git a/src/tint/lang/core/ir/exit.h b/src/tint/lang/core/ir/exit.h
index 8a3d448..f75da6f 100644
--- a/src/tint/lang/core/ir/exit.h
+++ b/src/tint/lang/core/ir/exit.h
@@ -29,6 +29,7 @@
#define SRC_TINT_LANG_CORE_IR_EXIT_H_
#include "src/tint/lang/core/ir/terminator.h"
+#include "src/tint/utils/containers/const_propagating_ptr.h"
// Forward declarations
namespace tint::core::ir {
@@ -48,13 +49,16 @@
/// @return the control instruction that this exit is associated with
ir::ControlInstruction* ControlInstruction() { return ctrl_inst_; }
+ /// @return the control instruction that this exit is associated with
+ const ir::ControlInstruction* ControlInstruction() const { return ctrl_inst_; }
+
protected:
/// Sets control instruction that this exit is associated with
/// @param ctrl_inst the new ControlInstruction that this exit is associated with
void SetControlInstruction(ir::ControlInstruction* ctrl_inst);
private:
- ir::ControlInstruction* ctrl_inst_ = nullptr;
+ ConstPropagatingPtr<ir::ControlInstruction> ctrl_inst_;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/exit_if.cc b/src/tint/lang/core/ir/exit_if.cc
index 373a682..74cd394 100644
--- a/src/tint/lang/core/ir/exit_if.cc
+++ b/src/tint/lang/core/ir/exit_if.cc
@@ -59,4 +59,8 @@
return static_cast<ir::If*>(ControlInstruction());
}
+const ir::If* ExitIf::If() const {
+ return static_cast<const ir::If*>(ControlInstruction());
+}
+
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/exit_if.h b/src/tint/lang/core/ir/exit_if.h
index be83148..3b6f568 100644
--- a/src/tint/lang/core/ir/exit_if.h
+++ b/src/tint/lang/core/ir/exit_if.h
@@ -62,8 +62,11 @@
/// @returns the if being exited
ir::If* If();
+ /// @returns the if being exited
+ const ir::If* If() const;
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "exit_if"; }
+ std::string FriendlyName() const override { return "exit_if"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/exit_if_test.cc b/src/tint/lang/core/ir/exit_if_test.cc
index ad838f9..7eb07ce 100644
--- a/src/tint/lang/core/ir/exit_if_test.cc
+++ b/src/tint/lang/core/ir/exit_if_test.cc
@@ -44,7 +44,7 @@
EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{e, 0u}));
EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{e, 1u}));
- EXPECT_EQ(if_->Result(), nullptr);
+ EXPECT_EQ(if_->Result(0), nullptr);
}
TEST_F(IR_ExitIfTest, Result) {
@@ -53,8 +53,7 @@
auto* if_ = b.If(true);
auto* e = b.ExitIf(if_, arg1, arg2);
- EXPECT_FALSE(e->HasResults());
- EXPECT_FALSE(e->HasMultiResults());
+ EXPECT_TRUE(e->Results().IsEmpty());
}
TEST_F(IR_ExitIfTest, Destroy) {
diff --git a/src/tint/lang/core/ir/exit_loop.cc b/src/tint/lang/core/ir/exit_loop.cc
index 1d06680..fe8da1b 100644
--- a/src/tint/lang/core/ir/exit_loop.cc
+++ b/src/tint/lang/core/ir/exit_loop.cc
@@ -60,4 +60,8 @@
return static_cast<ir::Loop*>(ControlInstruction());
}
+const ir::Loop* ExitLoop::Loop() const {
+ return static_cast<const ir::Loop*>(ControlInstruction());
+}
+
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/exit_loop.h b/src/tint/lang/core/ir/exit_loop.h
index 83bb20e..0686fc2 100644
--- a/src/tint/lang/core/ir/exit_loop.h
+++ b/src/tint/lang/core/ir/exit_loop.h
@@ -62,8 +62,11 @@
/// @returns the loop being exited
ir::Loop* Loop();
+ /// @returns the loop being exited
+ const ir::Loop* Loop() const;
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "exit_loop"; }
+ std::string FriendlyName() const override { return "exit_loop"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/exit_loop_test.cc b/src/tint/lang/core/ir/exit_loop_test.cc
index 2f25903..18c59a3 100644
--- a/src/tint/lang/core/ir/exit_loop_test.cc
+++ b/src/tint/lang/core/ir/exit_loop_test.cc
@@ -44,7 +44,7 @@
EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{e, 0u}));
EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{e, 1u}));
- EXPECT_EQ(loop->Result(), nullptr);
+ EXPECT_EQ(loop->Result(0), nullptr);
}
TEST_F(IR_ExitLoopTest, Destroy) {
diff --git a/src/tint/lang/core/ir/exit_switch.cc b/src/tint/lang/core/ir/exit_switch.cc
index fe7ef6c..5d90811 100644
--- a/src/tint/lang/core/ir/exit_switch.cc
+++ b/src/tint/lang/core/ir/exit_switch.cc
@@ -59,4 +59,8 @@
return static_cast<ir::Switch*>(ControlInstruction());
}
+const ir::Switch* ExitSwitch::Switch() const {
+ return static_cast<const ir::Switch*>(ControlInstruction());
+}
+
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/exit_switch.h b/src/tint/lang/core/ir/exit_switch.h
index 3b614f1..878f73b 100644
--- a/src/tint/lang/core/ir/exit_switch.h
+++ b/src/tint/lang/core/ir/exit_switch.h
@@ -62,8 +62,11 @@
/// @returns the switch being exited
ir::Switch* Switch();
+ /// @returns the switch being exited
+ const ir::Switch* Switch() const;
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "exit_switch"; }
+ std::string FriendlyName() const override { return "exit_switch"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/exit_switch_test.cc b/src/tint/lang/core/ir/exit_switch_test.cc
index 222cc3c..2fc1f77 100644
--- a/src/tint/lang/core/ir/exit_switch_test.cc
+++ b/src/tint/lang/core/ir/exit_switch_test.cc
@@ -44,7 +44,7 @@
EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{e, 0u}));
EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{e, 1u}));
- EXPECT_EQ(switch_->Result(), nullptr);
+ EXPECT_EQ(switch_->Result(0), nullptr);
}
TEST_F(IR_ExitSwitchTest, Result) {
@@ -53,8 +53,7 @@
auto* switch_ = b.Switch(true);
auto* e = b.ExitSwitch(switch_, arg1, arg2);
- EXPECT_FALSE(e->HasResults());
- EXPECT_FALSE(e->HasMultiResults());
+ EXPECT_TRUE(e->Results().IsEmpty());
}
TEST_F(IR_ExitSwitchTest, Destroy) {
diff --git a/src/tint/lang/core/ir/function.h b/src/tint/lang/core/ir/function.h
index 33639bb..1937673 100644
--- a/src/tint/lang/core/ir/function.h
+++ b/src/tint/lang/core/ir/function.h
@@ -36,6 +36,7 @@
#include "src/tint/lang/core/ir/location.h"
#include "src/tint/lang/core/ir/value.h"
#include "src/tint/lang/core/type/type.h"
+#include "src/tint/utils/containers/const_propagating_ptr.h"
#include "src/tint/utils/ice/ice.h"
// Forward declarations
@@ -88,7 +89,7 @@
void SetStage(PipelineStage stage) { pipeline_stage_ = stage; }
/// @returns the function pipeline stage
- PipelineStage Stage() { return pipeline_stage_; }
+ PipelineStage Stage() const { return pipeline_stage_; }
/// Sets the workgroup size
/// @param x the x size
@@ -100,10 +101,10 @@
void ClearWorkgroupSize() { workgroup_size_ = {}; }
/// @returns the workgroup size information
- std::optional<std::array<uint32_t, 3>> WorkgroupSize() { return workgroup_size_; }
+ std::optional<std::array<uint32_t, 3>> WorkgroupSize() const { return workgroup_size_; }
/// @returns the return type for the function
- const core::type::Type* ReturnType() { return return_.type; }
+ const core::type::Type* ReturnType() const { return return_.type; }
/// Sets the return attributes
/// @param builtin the builtin to set
@@ -112,7 +113,7 @@
return_.builtin = builtin;
}
/// @returns the return builtin attribute
- std::optional<enum ReturnBuiltin> ReturnBuiltin() { return return_.builtin; }
+ std::optional<enum ReturnBuiltin> ReturnBuiltin() const { return return_.builtin; }
/// Clears the return builtin attribute.
void ClearReturnBuiltin() { return_.builtin = {}; }
@@ -123,7 +124,7 @@
return_.location = {loc, interp};
}
/// @returns the return location
- std::optional<Location> ReturnLocation() { return return_.location; }
+ std::optional<Location> ReturnLocation() const { return return_.location; }
/// Clears the return location attribute.
void ClearReturnLocation() { return_.location = {}; }
@@ -131,7 +132,7 @@
/// @param val the invariant value to set
void SetReturnInvariant(bool val) { return_.invariant = val; }
/// @returns the return invariant value
- bool ReturnInvariant() { return return_.invariant; }
+ bool ReturnInvariant() const { return return_.invariant; }
/// Sets the function parameters
/// @param params the function parameters
@@ -144,15 +145,22 @@
/// @returns the function parameters
const VectorRef<FunctionParam*> Params() { return params_; }
+ /// @returns the function parameters
+ VectorRef<const FunctionParam*> Params() const { return params_; }
+
/// Sets the root block for the function
/// @param target the root block
void SetBlock(Block* target) {
TINT_ASSERT(target != nullptr);
block_ = target;
}
+
/// @returns the function root block
ir::Block* Block() { return block_; }
+ /// @returns the function root block
+ const ir::Block* Block() const { return block_; }
+
/// Destroys the function and all of its instructions.
void Destroy() override;
@@ -168,7 +176,7 @@
} return_;
Vector<FunctionParam*, 1> params_;
- ir::Block* block_ = nullptr;
+ ConstPropagatingPtr<ir::Block> block_;
};
/// @param value the enum value
diff --git a/src/tint/lang/core/ir/function_param.h b/src/tint/lang/core/ir/function_param.h
index 0955ef3..4f8e22c 100644
--- a/src/tint/lang/core/ir/function_param.h
+++ b/src/tint/lang/core/ir/function_param.h
@@ -78,7 +78,7 @@
~FunctionParam() override;
/// @returns the type of the var
- const core::type::Type* Type() override { return type_; }
+ const core::type::Type* Type() const override { return type_; }
/// @copydoc Value::Clone()
FunctionParam* Clone(CloneContext& ctx) override;
@@ -90,7 +90,7 @@
builtin_ = val;
}
/// @returns the builtin set for the parameter
- std::optional<FunctionParam::Builtin> Builtin() { return builtin_; }
+ std::optional<FunctionParam::Builtin> Builtin() const { return builtin_; }
/// Clears the builtin attribute.
void ClearBuiltin() { builtin_ = {}; }
@@ -98,7 +98,7 @@
/// @param val the value to set for invariant
void SetInvariant(bool val) { invariant_ = val; }
/// @returns true if parameter is invariant
- bool Invariant() { return invariant_; }
+ bool Invariant() const { return invariant_; }
/// Sets the location
/// @param loc the location value
@@ -107,7 +107,7 @@
location_ = {loc, interpolation};
}
/// @returns the location if `Attributes` contains `kLocation`
- std::optional<struct Location> Location() { return location_; }
+ std::optional<struct Location> Location() const { return location_; }
/// Clears the location attribute.
void ClearLocation() { location_ = {}; }
@@ -116,7 +116,7 @@
/// @param binding the binding
void SetBindingPoint(uint32_t group, uint32_t binding) { binding_point_ = {group, binding}; }
/// @returns the binding points if `Attributes` contains `kBindingPoint`
- std::optional<struct BindingPoint>& BindingPoint() { return binding_point_; }
+ std::optional<struct BindingPoint> BindingPoint() const { return binding_point_; }
private:
const core::type::Type* type_ = nullptr;
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/lang/core/ir/ice.h
similarity index 65%
copy from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
copy to src/tint/lang/core/ir/ice.h
index 6f0f657..40ef1dd 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/lang/core/ir/ice.h
@@ -25,28 +25,12 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
-#define SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#ifndef SRC_TINT_LANG_CORE_IR_ICE_H_
+#define SRC_TINT_LANG_CORE_IR_ICE_H_
-#include <string>
+#include "src/tint/lang/core/ir/disassembler.h"
-#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/result/result.h"
+/// Emit an ICE message with the disassembly of `mod` attached.
+#define TINT_IR_ICE(mod) TINT_ICE() << tint::core::ir::Disassembler{mod}.Disassemble() << "\n"
-// Forward declarations.
-namespace tint::core::ir {
-class Module;
-}
-
-namespace tint::wgsl::writer {
-
-/// RenameConflicts is a transform that renames declarations which prevent identifiers from
-/// resolving to the correct declaration, and those with identical identifiers declared in the same
-/// scope.
-/// @param module the module to transform
-/// @returns success or failure
-Result<SuccessType> RenameConflicts(core::ir::Module* module);
-
-} // namespace tint::wgsl::writer
-
-#endif // SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#endif // SRC_TINT_LANG_CORE_IR_ICE_H_
diff --git a/src/tint/lang/core/ir/if.h b/src/tint/lang/core/ir/if.h
index ccf8c1d..cc03e63 100644
--- a/src/tint/lang/core/ir/if.h
+++ b/src/tint/lang/core/ir/if.h
@@ -31,6 +31,7 @@
#include <string>
#include "src/tint/lang/core/ir/control_instruction.h"
+#include "src/tint/utils/containers/const_propagating_ptr.h"
// Forward declarations
namespace tint::core::ir {
@@ -76,18 +77,27 @@
/// @returns the if condition
Value* Condition() { return operands_[kConditionOperandOffset]; }
+ /// @returns the if condition
+ const Value* Condition() const { return operands_[kConditionOperandOffset]; }
+
/// @returns the true block
ir::Block* True() { return true_; }
+ /// @returns the true block
+ const ir::Block* True() const { return true_; }
+
/// @returns the false block
ir::Block* False() { return false_; }
+ /// @returns the false block
+ const ir::Block* False() const { return false_; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "if"; }
+ std::string FriendlyName() const override { return "if"; }
private:
- ir::Block* true_ = nullptr;
- ir::Block* false_ = nullptr;
+ ConstPropagatingPtr<ir::Block> true_;
+ ConstPropagatingPtr<ir::Block> false_;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/if_test.cc b/src/tint/lang/core/ir/if_test.cc
index 3d3ea8b..6d609fd 100644
--- a/src/tint/lang/core/ir/if_test.cc
+++ b/src/tint/lang/core/ir/if_test.cc
@@ -45,8 +45,7 @@
TEST_F(IR_IfTest, Result) {
auto* if_ = b.If(b.Constant(true));
- EXPECT_FALSE(if_->HasResults());
- EXPECT_FALSE(if_->HasMultiResults());
+ EXPECT_TRUE(if_->Results().IsEmpty());
}
TEST_F(IR_IfTest, Parent) {
diff --git a/src/tint/lang/core/ir/instruction.cc b/src/tint/lang/core/ir/instruction.cc
index 3778221..69d3f77 100644
--- a/src/tint/lang/core/ir/instruction.cc
+++ b/src/tint/lang/core/ir/instruction.cc
@@ -44,7 +44,7 @@
Remove();
}
for (auto* result : Results()) {
- result->SetSource(nullptr);
+ result->SetInstruction(nullptr);
result->Destroy();
}
flags_.Add(Flag::kDead);
diff --git a/src/tint/lang/core/ir/instruction.h b/src/tint/lang/core/ir/instruction.h
index c15e6c6..886df26 100644
--- a/src/tint/lang/core/ir/instruction.h
+++ b/src/tint/lang/core/ir/instruction.h
@@ -32,6 +32,7 @@
#include "src/tint/lang/core/ir/instruction_result.h"
#include "src/tint/lang/core/ir/value.h"
+#include "src/tint/utils/containers/const_propagating_ptr.h"
#include "src/tint/utils/containers/enum_set.h"
#include "src/tint/utils/rtti/castable.h"
@@ -57,24 +58,21 @@
/// @returns the operands of the instruction
virtual VectorRef<ir::Value*> Operands() = 0;
- /// @returns true if the instruction has result values
- virtual bool HasResults() { return false; }
- /// @returns true if the instruction has multiple values
- virtual bool HasMultiResults() { return false; }
-
- /// @returns the first result. Returns `nullptr` if there are no results, or if ther are
- /// multi-results
- virtual InstructionResult* Result() { return nullptr; }
+ /// @returns the operands of the instruction
+ virtual VectorRef<const ir::Value*> Operands() const = 0;
/// @returns the result values for this instruction
- virtual VectorRef<InstructionResult*> Results() { return tint::Empty; }
+ virtual VectorRef<InstructionResult*> Results() = 0;
+
+ /// @returns the result values for this instruction
+ virtual VectorRef<const InstructionResult*> Results() const = 0;
/// Removes the instruction from the block, and destroys all the result values.
/// The result values must not be in use.
virtual void Destroy();
/// @returns the friendly name for the instruction
- virtual std::string FriendlyName() = 0;
+ virtual std::string FriendlyName() const = 0;
/// @param ctx the CloneContext used to clone this instruction
/// @returns a clone of this instruction
@@ -94,6 +92,9 @@
/// @returns the block that owns this instruction
ir::Block* Block() { return block_; }
+ /// @returns the block that owns this instruction
+ const ir::Block* Block() const { return block_; }
+
/// Adds the new instruction before the given instruction in the owning block
/// @param before the instruction to insert before
void InsertBefore(Instruction* before);
@@ -106,18 +107,42 @@
/// Removes this instruction from the owning block
void Remove();
+ /// @param idx the index of the operand
+ /// @returns the operand with index @p idx, or `nullptr` if there are no operands or the index
+ /// is out of bounds.
+ Value* Operand(size_t idx) {
+ auto res = Operands();
+ return idx < res.Length() ? res[idx] : nullptr;
+ }
+
+ /// @param idx the index of the operand
+ /// @returns the operand with index @p idx, or `nullptr` if there are no operands or the index
+ /// is out of bounds.
+ const Value* Operand(size_t idx) const {
+ auto res = Operands();
+ return idx < res.Length() ? res[idx] : nullptr;
+ }
+
/// @param idx the index of the result
/// @returns the result with index @p idx, or `nullptr` if there are no results or the index is
/// out of bounds.
- Value* Result(size_t idx) {
+ InstructionResult* Result(size_t idx) {
+ auto res = Results();
+ return idx < res.Length() ? res[idx] : nullptr;
+ }
+
+ /// @param idx the index of the result
+ /// @returns the result with index @p idx, or `nullptr` if there are no results or the index is
+ /// out of bounds.
+ const InstructionResult* Result(size_t idx) const {
auto res = Results();
return idx < res.Length() ? res[idx] : nullptr;
}
/// Pointer to the next instruction in the list
- Instruction* next = nullptr;
+ ConstPropagatingPtr<Instruction> next;
/// Pointer to the previous instruction in the list
- Instruction* prev = nullptr;
+ ConstPropagatingPtr<Instruction> prev;
protected:
/// Flags applied to an Instruction
@@ -132,7 +157,7 @@
Instruction();
/// The block that owns this instruction
- ir::Block* block_ = nullptr;
+ ConstPropagatingPtr<ir::Block> block_;
/// Bitset of instruction flags
tint::EnumSet<Flag> flags_;
diff --git a/src/tint/lang/core/ir/instruction_result.cc b/src/tint/lang/core/ir/instruction_result.cc
index 496c82b..2aa0fc7 100644
--- a/src/tint/lang/core/ir/instruction_result.cc
+++ b/src/tint/lang/core/ir/instruction_result.cc
@@ -44,12 +44,12 @@
InstructionResult::~InstructionResult() = default;
void InstructionResult::Destroy() {
- TINT_ASSERT(source_ == nullptr);
+ TINT_ASSERT(instruction_ == nullptr);
Base::Destroy();
}
InstructionResult* InstructionResult::Clone(CloneContext& ctx) {
- // Do not clone the `Source`. It will be set when this result is placed in the new parent
+ // Do not clone the `Instruction`. It will be set when this result is placed in the new parent
// instruction.
return ctx.ir.values.Create<InstructionResult>(type_);
}
diff --git a/src/tint/lang/core/ir/instruction_result.h b/src/tint/lang/core/ir/instruction_result.h
index 8ba3878..2b6b442 100644
--- a/src/tint/lang/core/ir/instruction_result.h
+++ b/src/tint/lang/core/ir/instruction_result.h
@@ -47,7 +47,7 @@
void Destroy() override;
/// @returns the type of the value
- const core::type::Type* Type() override { return type_; }
+ const core::type::Type* Type() const override { return type_; }
/// @copydoc Value::Clone()
InstructionResult* Clone(CloneContext& ctx) override;
@@ -56,15 +56,18 @@
/// @param type the new type of the value
void SetType(const core::type::Type* type) { type_ = type; }
- /// Sets the source instruction for this value
+ /// Sets the instruction for this value
/// @param inst the instruction to set
- void SetSource(Instruction* inst) { source_ = inst; }
+ void SetInstruction(Instruction* inst) { instruction_ = inst; }
- /// @returns the source instruction, if any
- Instruction* Source() { return source_; }
+ /// @returns the instruction, if any
+ ir::Instruction* Instruction() { return instruction_; }
+
+ /// @returns the instruction, if any
+ const ir::Instruction* Instruction() const { return instruction_; }
private:
- Instruction* source_ = nullptr;
+ ir::Instruction* instruction_ = nullptr;
const core::type::Type* type_ = nullptr;
};
diff --git a/src/tint/lang/core/ir/instruction_result_test.cc b/src/tint/lang/core/ir/instruction_result_test.cc
index 71212db..534f347 100644
--- a/src/tint/lang/core/ir/instruction_result_test.cc
+++ b/src/tint/lang/core/ir/instruction_result_test.cc
@@ -37,23 +37,23 @@
using IR_InstructionResultTest = IRTestHelper;
-TEST_F(IR_InstructionResultTest, Destroy_HasSource) {
+TEST_F(IR_InstructionResultTest, Destroy_HasInstruction) {
EXPECT_FATAL_FAILURE(
{
Module mod;
Builder b{mod};
- auto* val = b.Add(mod.Types().i32(), 1_i, 2_i)->Result();
+ auto* val = b.Add(mod.Types().i32(), 1_i, 2_i)->Result(0);
val->Destroy();
},
"");
}
TEST_F(IR_InstructionResultTest, Clone) {
- auto* val = b.Add(mod.Types().i32(), 1_i, 2_i)->Result();
+ auto* val = b.Add(mod.Types().i32(), 1_i, 2_i)->Result(0);
auto* new_res = clone_ctx.Clone(val);
EXPECT_NE(val, new_res);
- EXPECT_EQ(nullptr, new_res->Source());
+ EXPECT_EQ(nullptr, new_res->Instruction());
EXPECT_EQ(mod.Types().i32(), new_res->Type());
}
diff --git a/src/tint/lang/core/ir/let.cc b/src/tint/lang/core/ir/let.cc
index e6b2ea3..ddbf9a3 100644
--- a/src/tint/lang/core/ir/let.cc
+++ b/src/tint/lang/core/ir/let.cc
@@ -43,7 +43,7 @@
Let::~Let() = default;
Let* Let::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto* val = ctx.Remap(Value());
auto* new_let = ctx.ir.instructions.Create<Let>(new_result, val);
diff --git a/src/tint/lang/core/ir/let.h b/src/tint/lang/core/ir/let.h
index f983a2c..a2fe222 100644
--- a/src/tint/lang/core/ir/let.h
+++ b/src/tint/lang/core/ir/let.h
@@ -49,11 +49,17 @@
/// @copydoc Instruction::Clone()
Let* Clone(CloneContext& ctx) override;
+ /// @param value the new let value
+ void SetValue(ir::Value* value) { SetOperand(kValueOperandOffset, value); }
+
/// @returns the value
ir::Value* Value() { return operands_[kValueOperandOffset]; }
+ /// @returns the value
+ const ir::Value* Value() const { return operands_[kValueOperandOffset]; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "let"; }
+ std::string FriendlyName() const override { return "let"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/let_test.cc b/src/tint/lang/core/ir/let_test.cc
index 59c5947..78b9d5e 100644
--- a/src/tint/lang/core/ir/let_test.cc
+++ b/src/tint/lang/core/ir/let_test.cc
@@ -55,11 +55,10 @@
TEST_F(IR_LetTest, Results) {
auto* value = b.Constant(1_f);
auto* let = b.Let("l", value);
- EXPECT_TRUE(let->HasResults());
- EXPECT_FALSE(let->HasMultiResults());
- EXPECT_TRUE(let->Result()->Is<InstructionResult>());
- EXPECT_EQ(let->Result()->Source(), let);
- EXPECT_EQ(let->Result()->Type(), value->Type());
+ EXPECT_EQ(let->Results().Length(), 1u);
+ EXPECT_TRUE(let->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(let->Result(0)->Instruction(), let);
+ EXPECT_EQ(let->Result(0)->Type(), value->Type());
}
TEST_F(IR_LetTest, Clone) {
@@ -69,15 +68,15 @@
auto* new_let = clone_ctx.Clone(let);
EXPECT_NE(let, new_let);
- EXPECT_NE(nullptr, new_let->Result());
- EXPECT_NE(let->Result(), new_let->Result());
+ EXPECT_NE(nullptr, new_let->Result(0));
+ EXPECT_NE(let->Result(0), new_let->Result(0));
auto new_val = new_let->Value()->As<Constant>()->Value();
ASSERT_TRUE(new_val->Is<core::constant::Scalar<f32>>());
EXPECT_FLOAT_EQ(4_f, new_val->As<core::constant::Scalar<f32>>()->ValueAs<f32>());
EXPECT_EQ(std::string("l"), mod.NameOf(new_let).Name());
- EXPECT_EQ(std::string("l"), mod.NameOf(new_let->Result()).Name());
+ EXPECT_EQ(std::string("l"), mod.NameOf(new_let->Result(0)).Name());
}
} // namespace
diff --git a/src/tint/lang/core/ir/load.cc b/src/tint/lang/core/ir/load.cc
index 2d63594..ba9f6d3 100644
--- a/src/tint/lang/core/ir/load.cc
+++ b/src/tint/lang/core/ir/load.cc
@@ -49,7 +49,7 @@
Load::~Load() = default;
Load* Load::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto* from = ctx.Remap(From());
return ctx.ir.instructions.Create<Load>(new_result, from);
}
diff --git a/src/tint/lang/core/ir/load.h b/src/tint/lang/core/ir/load.h
index daab943..167fa87 100644
--- a/src/tint/lang/core/ir/load.h
+++ b/src/tint/lang/core/ir/load.h
@@ -54,8 +54,11 @@
/// @returns the value being loaded from
Value* From() { return operands_[kFromOperandOffset]; }
+ /// @returns the value being loaded from
+ const Value* From() const { return operands_[kFromOperandOffset]; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "load"; }
+ std::string FriendlyName() const override { return "load"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/load_test.cc b/src/tint/lang/core/ir/load_test.cc
index ccb77dc..1550b14 100644
--- a/src/tint/lang/core/ir/load_test.cc
+++ b/src/tint/lang/core/ir/load_test.cc
@@ -45,13 +45,13 @@
auto* inst = b.Load(var);
ASSERT_TRUE(inst->Is<Load>());
- ASSERT_EQ(inst->From(), var->Result());
- EXPECT_EQ(inst->Result()->Type(), store_type);
+ ASSERT_EQ(inst->From(), var->Result(0));
+ EXPECT_EQ(inst->Result(0)->Type(), store_type);
auto* result = inst->From()->As<InstructionResult>();
ASSERT_NE(result, nullptr);
- ASSERT_TRUE(result->Source()->Is<ir::Var>());
- EXPECT_EQ(result->Source(), var);
+ ASSERT_TRUE(result->Instruction()->Is<ir::Var>());
+ EXPECT_EQ(result->Instruction(), var);
}
TEST_F(IR_LoadTest, Usage) {
@@ -66,10 +66,9 @@
auto* var = b.Var(ty.ptr<function, i32>());
auto* inst = b.Load(var);
- EXPECT_TRUE(inst->HasResults());
- EXPECT_FALSE(inst->HasMultiResults());
- EXPECT_TRUE(inst->Result()->Is<InstructionResult>());
- EXPECT_EQ(inst->Result()->Source(), inst);
+ EXPECT_EQ(inst->Results().Length(), 1u);
+ EXPECT_TRUE(inst->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(inst->Result(0)->Instruction(), inst);
}
TEST_F(IR_LoadTest, Fail_NonPtr_Builder) {
@@ -90,10 +89,10 @@
auto* new_inst = clone_ctx.Clone(inst);
EXPECT_NE(inst, new_inst);
- EXPECT_NE(nullptr, new_inst->Result());
- EXPECT_NE(inst->Result(), new_inst->Result());
+ EXPECT_NE(nullptr, new_inst->Result(0));
+ EXPECT_NE(inst->Result(0), new_inst->Result(0));
- EXPECT_EQ(new_var->Result(), new_inst->From());
+ EXPECT_EQ(new_var->Result(0), new_inst->From());
}
} // namespace
diff --git a/src/tint/lang/core/ir/load_vector_element.cc b/src/tint/lang/core/ir/load_vector_element.cc
index 525043b..4db0a53 100644
--- a/src/tint/lang/core/ir/load_vector_element.cc
+++ b/src/tint/lang/core/ir/load_vector_element.cc
@@ -45,7 +45,7 @@
LoadVectorElement::~LoadVectorElement() = default;
LoadVectorElement* LoadVectorElement::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto* from = ctx.Remap(From());
auto* index = ctx.Remap(Index());
return ctx.ir.instructions.Create<LoadVectorElement>(new_result, from, index);
diff --git a/src/tint/lang/core/ir/load_vector_element.h b/src/tint/lang/core/ir/load_vector_element.h
index e883c79..f8cbb37 100644
--- a/src/tint/lang/core/ir/load_vector_element.h
+++ b/src/tint/lang/core/ir/load_vector_element.h
@@ -57,11 +57,17 @@
/// @returns the vector pointer value
ir::Value* From() { return operands_[kFromOperandOffset]; }
+ /// @returns the vector pointer value
+ const ir::Value* From() const { return operands_[kFromOperandOffset]; }
+
/// @returns the new vector element index
ir::Value* Index() { return operands_[kIndexOperandOffset]; }
+ /// @returns the new vector element index
+ const ir::Value* Index() const { return operands_[kIndexOperandOffset]; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "load_vector_element"; }
+ std::string FriendlyName() const override { return "load_vector_element"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/load_vector_element_test.cc b/src/tint/lang/core/ir/load_vector_element_test.cc
index 78bcd44..0f69ec1 100644
--- a/src/tint/lang/core/ir/load_vector_element_test.cc
+++ b/src/tint/lang/core/ir/load_vector_element_test.cc
@@ -44,7 +44,7 @@
auto* inst = b.LoadVectorElement(from, 2_i);
ASSERT_TRUE(inst->Is<LoadVectorElement>());
- ASSERT_EQ(inst->From(), from->Result());
+ ASSERT_EQ(inst->From(), from->Result(0));
ASSERT_TRUE(inst->Index()->Is<Constant>());
auto index = inst->Index()->As<Constant>()->Value();
@@ -67,8 +67,7 @@
auto* from = b.Var(ty.ptr<private_, vec3<i32>>());
auto* inst = b.LoadVectorElement(from, 2_i);
- EXPECT_TRUE(inst->HasResults());
- EXPECT_FALSE(inst->HasMultiResults());
+ EXPECT_EQ(inst->Results().Length(), 1u);
}
TEST_F(IR_LoadVectorElementTest, Clone) {
@@ -79,10 +78,10 @@
auto* new_inst = clone_ctx.Clone(inst);
EXPECT_NE(inst, new_inst);
- EXPECT_NE(nullptr, new_inst->Result());
- EXPECT_NE(inst->Result(), new_inst->Result());
+ EXPECT_NE(nullptr, new_inst->Result(0));
+ EXPECT_NE(inst->Result(0), new_inst->Result(0));
- EXPECT_EQ(new_from->Result(), new_inst->From());
+ EXPECT_EQ(new_from->Result(0), new_inst->From());
auto new_idx = new_inst->Index()->As<Constant>()->Value();
ASSERT_TRUE(new_idx->Is<core::constant::Scalar<i32>>());
diff --git a/src/tint/lang/core/ir/loop.cc b/src/tint/lang/core/ir/loop.cc
index efb0cd7..a5e3519 100644
--- a/src/tint/lang/core/ir/loop.cc
+++ b/src/tint/lang/core/ir/loop.cc
@@ -85,7 +85,7 @@
}
bool Loop::HasInitializer() {
- return initializer_->HasTerminator();
+ return initializer_->Terminator() != nullptr;
}
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/loop.h b/src/tint/lang/core/ir/loop.h
index 906032f..c22b8b9 100644
--- a/src/tint/lang/core/ir/loop.h
+++ b/src/tint/lang/core/ir/loop.h
@@ -31,6 +31,7 @@
#include <string>
#include "src/tint/lang/core/ir/control_instruction.h"
+#include "src/tint/utils/containers/const_propagating_ptr.h"
// Forward declarations
namespace tint::core::ir {
@@ -87,6 +88,9 @@
/// @returns the switch initializer block
ir::Block* Initializer() { return initializer_; }
+ /// @returns the switch initializer block
+ const ir::Block* Initializer() const { return initializer_; }
+
/// @returns true if the loop uses an initializer block. If true, then the Loop first branches
/// to the initializer block, otherwise it first branches to the body block.
bool HasInitializer();
@@ -94,16 +98,22 @@
/// @returns the switch start block
ir::MultiInBlock* Body() { return body_; }
+ /// @returns the switch start block
+ const ir::MultiInBlock* Body() const { return body_; }
+
/// @returns the switch continuing block
ir::MultiInBlock* Continuing() { return continuing_; }
+ /// @returns the switch continuing block
+ const ir::MultiInBlock* Continuing() const { return continuing_; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "loop"; }
+ std::string FriendlyName() const override { return "loop"; }
private:
- ir::Block* initializer_ = nullptr;
- ir::MultiInBlock* body_ = nullptr;
- ir::MultiInBlock* continuing_ = nullptr;
+ ConstPropagatingPtr<ir::Block> initializer_;
+ ConstPropagatingPtr<ir::MultiInBlock> body_;
+ ConstPropagatingPtr<ir::MultiInBlock> continuing_;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/loop_test.cc b/src/tint/lang/core/ir/loop_test.cc
index df6abcc..b8721e2 100644
--- a/src/tint/lang/core/ir/loop_test.cc
+++ b/src/tint/lang/core/ir/loop_test.cc
@@ -44,8 +44,7 @@
TEST_F(IR_LoopTest, Result) {
auto* loop = b.Loop();
- EXPECT_FALSE(loop->HasResults());
- EXPECT_FALSE(loop->HasMultiResults());
+ EXPECT_TRUE(loop->Results().IsEmpty());
}
TEST_F(IR_LoopTest, Fail_NullInitializerBlock) {
@@ -83,7 +82,7 @@
auto* new_loop = clone_ctx.Clone(loop);
EXPECT_NE(loop, new_loop);
- EXPECT_FALSE(new_loop->HasResults());
+ EXPECT_TRUE(new_loop->Results().IsEmpty());
EXPECT_EQ(0u, new_loop->Exits().Count());
EXPECT_NE(nullptr, new_loop->Initializer());
EXPECT_NE(loop->Initializer(), new_loop->Initializer());
diff --git a/src/tint/lang/core/ir/module.cc b/src/tint/lang/core/ir/module.cc
index a6f2c5b..4738c14 100644
--- a/src/tint/lang/core/ir/module.cc
+++ b/src/tint/lang/core/ir/module.cc
@@ -41,18 +41,20 @@
Module& Module::operator=(Module&&) = default;
-Symbol Module::NameOf(Instruction* inst) {
- TINT_ASSERT(inst->HasResults() && !inst->HasMultiResults());
- return NameOf(inst->Result());
+Symbol Module::NameOf(const Instruction* inst) const {
+ if (inst->Results().Length() != 1) {
+ return Symbol{};
+ }
+ return NameOf(inst->Result(0));
}
-Symbol Module::NameOf(Value* value) {
+Symbol Module::NameOf(const Value* value) const {
return value_to_name_.Get(value).value_or(Symbol{});
}
void Module::SetName(Instruction* inst, std::string_view name) {
- TINT_ASSERT(inst->HasResults() && !inst->HasMultiResults());
- return SetName(inst->Result(), name);
+ TINT_ASSERT(inst->Results().Length() == 1);
+ return SetName(inst->Result(0), name);
}
void Module::SetName(Value* value, std::string_view name) {
@@ -65,4 +67,8 @@
value_to_name_.Replace(value, name);
}
+void Module::ClearName(Value* value) {
+ value_to_name_.Remove(value);
+}
+
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/module.h b/src/tint/lang/core/ir/module.h
index ac7b99b..fba89fb 100644
--- a/src/tint/lang/core/ir/module.h
+++ b/src/tint/lang/core/ir/module.h
@@ -38,6 +38,7 @@
#include "src/tint/lang/core/ir/instruction.h"
#include "src/tint/lang/core/ir/value.h"
#include "src/tint/lang/core/type/manager.h"
+#include "src/tint/utils/containers/const_propagating_ptr.h"
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/diagnostic/source.h"
#include "src/tint/utils/id/generation_id.h"
@@ -53,7 +54,7 @@
GenerationID prog_id_;
/// Map of value to name
- Hashmap<Value*, Symbol, 32> value_to_name_;
+ Hashmap<const Value*, Symbol, 32> value_to_name_;
public:
/// Constructor
@@ -71,12 +72,12 @@
/// @param inst the instruction
/// @return the name of the given instruction, or an invalid symbol if the instruction is not
- /// named. Requires that the instruction only has a single return value.
- Symbol NameOf(Instruction* inst);
+ /// named or does not have a single return value.
+ Symbol NameOf(const Instruction* inst) const;
/// @param value the value
/// @return the name of the given value, or an invalid symbol if the value is not named.
- Symbol NameOf(Value* value);
+ Symbol NameOf(const Value* value) const;
/// @param inst the instruction to set the name of
/// @param name the desired name of the value. May be suffixed on collision.
@@ -91,9 +92,16 @@
/// @param name the desired name of the value
void SetName(Value* value, Symbol name);
+ /// Removes the name from @p value
+ /// @param value the value to remove the name from
+ void ClearName(Value* value);
+
/// @return the type manager for the module
core::type::Manager& Types() { return constant_values.types; }
+ /// @return the type manager for the module
+ const core::type::Manager& Types() const { return constant_values.types; }
+
/// The block allocator
BlockAllocator<Block> blocks;
@@ -107,19 +115,16 @@
BlockAllocator<Value> values;
/// List of functions in the program
- Vector<Function*, 8> functions;
+ Vector<ConstPropagatingPtr<Function>, 8> functions;
/// The block containing module level declarations, if any exist.
- Block* root_block = nullptr;
+ ConstPropagatingPtr<Block> root_block;
/// The symbol table for the module
SymbolTable symbols{prog_id_};
/// The map of core::constant::Value to their ir::Constant.
Hashmap<const core::constant::Value*, ir::Constant*, 16> constants;
-
- /// If the module generated a validation error, will store the file for the disassembly text.
- std::unique_ptr<Source::File> disassembly_file;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/multi_in_block.h b/src/tint/lang/core/ir/multi_in_block.h
index ed2b117..76915f1 100644
--- a/src/tint/lang/core/ir/multi_in_block.h
+++ b/src/tint/lang/core/ir/multi_in_block.h
@@ -31,11 +31,7 @@
#include <utility>
#include "src/tint/lang/core/ir/block.h"
-
-// Forward declarations
-namespace tint::core::ir {
-class BlockParam;
-}
+#include "src/tint/lang/core/ir/block_param.h"
namespace tint::core::ir {
@@ -63,7 +59,10 @@
void SetParams(std::initializer_list<BlockParam*> params);
/// @returns the params to the block
- const Vector<BlockParam*, 2>& Params() { return params_; }
+ VectorRef<BlockParam*> Params() { return params_; }
+
+ /// @returns the params to the block
+ VectorRef<const BlockParam*> Params() const { return params_; }
/// @returns branches made to this block by sibling blocks
const VectorRef<ir::Terminator*> InboundSiblingBranches() { return inbound_sibling_branches_; }
diff --git a/src/tint/lang/core/ir/next_iteration.h b/src/tint/lang/core/ir/next_iteration.h
index f14be17..f859ee0 100644
--- a/src/tint/lang/core/ir/next_iteration.h
+++ b/src/tint/lang/core/ir/next_iteration.h
@@ -31,6 +31,7 @@
#include <string>
#include "src/tint/lang/core/ir/terminator.h"
+#include "src/tint/utils/containers/const_propagating_ptr.h"
#include "src/tint/utils/rtti/castable.h"
// Forward declarations
@@ -58,11 +59,14 @@
/// @returns the loop being iterated
ir::Loop* Loop() { return loop_; }
+ /// @returns the loop being iterated
+ const ir::Loop* Loop() const { return loop_; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "next_iteration"; }
+ std::string FriendlyName() const override { return "next_iteration"; }
private:
- ir::Loop* loop_ = nullptr;
+ ConstPropagatingPtr<ir::Loop> loop_;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/next_iteration_test.cc b/src/tint/lang/core/ir/next_iteration_test.cc
index 75cdca1..249bd63 100644
--- a/src/tint/lang/core/ir/next_iteration_test.cc
+++ b/src/tint/lang/core/ir/next_iteration_test.cc
@@ -48,8 +48,7 @@
TEST_F(IR_NextIterationTest, Result) {
auto* inst = b.NextIteration(b.Loop());
- EXPECT_FALSE(inst->HasResults());
- EXPECT_FALSE(inst->HasMultiResults());
+ EXPECT_TRUE(inst->Results().IsEmpty());
}
TEST_F(IR_NextIterationTest, Clone) {
diff --git a/src/tint/lang/core/ir/operand_instruction.h b/src/tint/lang/core/ir/operand_instruction.h
index 624eeb8..2b3f83a 100644
--- a/src/tint/lang/core/ir/operand_instruction.h
+++ b/src/tint/lang/core/ir/operand_instruction.h
@@ -94,25 +94,29 @@
/// @returns the operands of the instruction
VectorRef<ir::Value*> Operands() override { return operands_; }
- /// @returns true if the instruction has result values
- bool HasResults() override { return !results_.IsEmpty(); }
- /// @returns true if the instruction has multiple values
- bool HasMultiResults() override { return results_.Length() > 1; }
-
- /// @returns the first result. Returns `nullptr` if there are no results, or if ther are
- /// multi-results
- InstructionResult* Result() override {
- if (!HasResults() || HasMultiResults()) {
- return nullptr;
- }
- return results_[0];
- }
-
- using Instruction::Result;
+ /// @returns the operands of the instruction
+ VectorRef<const ir::Value*> Operands() const override { return operands_; }
/// @returns the result values for this instruction
VectorRef<InstructionResult*> Results() override { return results_; }
+ /// @returns the result values for this instruction
+ VectorRef<const InstructionResult*> Results() const override { return results_; }
+
+ /// @param idx the index of the result
+ /// @returns the result with index @p idx, or `nullptr` if there are no results or the index is
+ /// out of bounds.
+ InstructionResult* Result(size_t idx) {
+ return idx < results_.Length() ? results_[idx] : nullptr;
+ }
+
+ /// @param idx the index of the result
+ /// @returns the result with index @p idx, or `nullptr` if there are no results or the index is
+ /// out of bounds.
+ const InstructionResult* Result(size_t idx) const {
+ return idx < results_.Length() ? results_[idx] : nullptr;
+ }
+
protected:
/// Append a new operand to the operand list for this instruction.
/// @param idx the index the operand should be at
@@ -141,7 +145,7 @@
/// @param value the value to append
void AddResult(InstructionResult* value) {
if (value) {
- value->SetSource(this);
+ value->SetInstruction(this);
}
results_.Push(value);
}
diff --git a/src/tint/lang/core/ir/operand_instruction_test.cc b/src/tint/lang/core/ir/operand_instruction_test.cc
index b66a600..b82c9d5 100644
--- a/src/tint/lang/core/ir/operand_instruction_test.cc
+++ b/src/tint/lang/core/ir/operand_instruction_test.cc
@@ -45,14 +45,14 @@
EXPECT_EQ(inst->Block(), block);
EXPECT_THAT(lhs->Usages(), testing::ElementsAre(Usage{inst, 0u}));
EXPECT_THAT(rhs->Usages(), testing::ElementsAre(Usage{inst, 1u}));
- EXPECT_TRUE(inst->Result()->Alive());
+ EXPECT_TRUE(inst->Result(0)->Alive());
inst->Destroy();
EXPECT_EQ(inst->Block(), nullptr);
EXPECT_TRUE(lhs->Usages().IsEmpty());
EXPECT_TRUE(rhs->Usages().IsEmpty());
- EXPECT_FALSE(inst->Result()->Alive());
+ EXPECT_FALSE(inst->Result(0)->Alive());
}
TEST_F(IR_OperandInstructionTest, ClearOperands_WithNullOperand) {
@@ -63,7 +63,7 @@
inst->Destroy();
EXPECT_EQ(inst->Block(), nullptr);
- EXPECT_FALSE(inst->Result()->Alive());
+ EXPECT_FALSE(inst->Result(0)->Alive());
}
TEST_F(IR_OperandInstructionTest, SetOperands_WithNullOperand) {
diff --git a/src/tint/lang/core/ir/return.cc b/src/tint/lang/core/ir/return.cc
index a854d62..f105afc 100644
--- a/src/tint/lang/core/ir/return.cc
+++ b/src/tint/lang/core/ir/return.cc
@@ -43,7 +43,7 @@
Return::Return(Function* func, ir::Value* arg) {
AddOperand(Return::kFunctionOperandOffset, func);
- AddOperand(Return::kArgOperandOffset, arg);
+ AddOperand(Return::kArgsOperandOffset, arg);
}
Return::~Return() = default;
@@ -56,7 +56,11 @@
return ctx.ir.instructions.Create<Return>(fn);
}
-Function* Return::Func() const {
+Function* Return::Func() {
+ return tint::As<Function>(operands_[kFunctionOperandOffset]);
+}
+
+const Function* Return::Func() const {
return tint::As<Function>(operands_[kFunctionOperandOffset]);
}
diff --git a/src/tint/lang/core/ir/return.h b/src/tint/lang/core/ir/return.h
index 412369f..4fcdc86 100644
--- a/src/tint/lang/core/ir/return.h
+++ b/src/tint/lang/core/ir/return.h
@@ -47,7 +47,7 @@
static constexpr size_t kFunctionOperandOffset = 0;
/// The offset in Operands() for the return argument
- static constexpr size_t kArgOperandOffset = 1;
+ static constexpr size_t kArgsOperandOffset = 1;
/// Constructor (no return value)
/// @param func the function being returned
@@ -64,24 +64,25 @@
Return* Clone(CloneContext& ctx) override;
/// @returns the function being returned
- Function* Func() const;
+ Function* Func();
+
+ /// @returns the function being returned
+ const Function* Func() const;
/// @returns the return value, or nullptr
ir::Value* Value() const {
- return operands_.Length() > kArgOperandOffset ? operands_[kArgOperandOffset] : nullptr;
+ return operands_.Length() > kArgsOperandOffset ? operands_[kArgsOperandOffset] : nullptr;
}
/// Sets the return value
/// @param val the new return value
- void SetValue(ir::Value* val) { SetOperand(kArgOperandOffset, val); }
+ void SetValue(ir::Value* val) { SetOperand(kArgsOperandOffset, val); }
- /// @returns the return arguments
- tint::Slice<ir::Value* const> Args() override {
- return operands_.Slice().Offset(kArgOperandOffset);
- }
+ /// @returns the offset of the arguments in Operands()
+ size_t ArgsOperandOffset() const override { return kArgsOperandOffset; }
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "return"; }
+ std::string FriendlyName() const override { return "return"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/return_test.cc b/src/tint/lang/core/ir/return_test.cc
index f019437..dfd088b 100644
--- a/src/tint/lang/core/ir/return_test.cc
+++ b/src/tint/lang/core/ir/return_test.cc
@@ -64,14 +64,12 @@
{
auto* ret1 = b.Return(vfunc);
- EXPECT_FALSE(ret1->HasResults());
- EXPECT_FALSE(ret1->HasMultiResults());
+ EXPECT_TRUE(ret1->Results().IsEmpty());
}
{
auto* ret2 = b.Return(ifunc, b.Constant(42_i));
- EXPECT_FALSE(ret2->HasResults());
- EXPECT_FALSE(ret2->HasMultiResults());
+ EXPECT_TRUE(ret2->Results().IsEmpty());
}
}
diff --git a/src/tint/lang/core/ir/store.h b/src/tint/lang/core/ir/store.h
index a5d8444..9ed7cc5 100644
--- a/src/tint/lang/core/ir/store.h
+++ b/src/tint/lang/core/ir/store.h
@@ -56,11 +56,17 @@
/// @returns the value being stored too
Value* To() { return operands_[kToOperandOffset]; }
+ /// @returns the value being stored too
+ const Value* To() const { return operands_[kToOperandOffset]; }
+
/// @returns the value being stored
Value* From() { return operands_[kFromOperandOffset]; }
+ /// @returns the value being stored
+ const Value* From() const { return operands_[kFromOperandOffset]; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "store"; }
+ std::string FriendlyName() const override { return "store"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/store_test.cc b/src/tint/lang/core/ir/store_test.cc
index aff0b12..28e4d85 100644
--- a/src/tint/lang/core/ir/store_test.cc
+++ b/src/tint/lang/core/ir/store_test.cc
@@ -44,7 +44,7 @@
auto* inst = b.Store(to, 4_i);
ASSERT_TRUE(inst->Is<Store>());
- ASSERT_EQ(inst->To(), to->Result());
+ ASSERT_EQ(inst->To(), to->Result(0));
ASSERT_TRUE(inst->From()->Is<Constant>());
auto lhs = inst->From()->As<Constant>()->Value();
@@ -67,8 +67,7 @@
auto* to = b.Var(ty.ptr<private_, i32>());
auto* inst = b.Store(to, 4_i);
- EXPECT_FALSE(inst->HasResults());
- EXPECT_FALSE(inst->HasMultiResults());
+ EXPECT_TRUE(inst->Results().IsEmpty());
}
TEST_F(IR_StoreTest, Clone) {
@@ -79,7 +78,7 @@
auto* new_s = clone_ctx.Clone(s);
EXPECT_NE(s, new_s);
- EXPECT_EQ(new_v->Result(), new_s->To());
+ EXPECT_EQ(new_v->Result(0), new_s->To());
auto new_from = new_s->From()->As<Constant>()->Value();
ASSERT_TRUE(new_from->Is<core::constant::Scalar<i32>>());
diff --git a/src/tint/lang/core/ir/store_vector_element.h b/src/tint/lang/core/ir/store_vector_element.h
index f76ec79..2ef3895 100644
--- a/src/tint/lang/core/ir/store_vector_element.h
+++ b/src/tint/lang/core/ir/store_vector_element.h
@@ -60,14 +60,23 @@
/// @returns the vector pointer value
ir::Value* To() { return operands_[kToOperandOffset]; }
+ /// @returns the vector pointer value
+ const ir::Value* To() const { return operands_[kToOperandOffset]; }
+
/// @returns the new vector element index
ir::Value* Index() { return operands_[kIndexOperandOffset]; }
+ /// @returns the new vector element index
+ const ir::Value* Index() const { return operands_[kIndexOperandOffset]; }
+
/// @returns the new vector element value
ir::Value* Value() { return operands_[kValueOperandOffset]; }
+ /// @returns the new vector element value
+ const ir::Value* Value() const { return operands_[kValueOperandOffset]; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "store_vector_element"; }
+ std::string FriendlyName() const override { return "store_vector_element"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/store_vector_element_test.cc b/src/tint/lang/core/ir/store_vector_element_test.cc
index 74664ba..971b12b 100644
--- a/src/tint/lang/core/ir/store_vector_element_test.cc
+++ b/src/tint/lang/core/ir/store_vector_element_test.cc
@@ -44,7 +44,7 @@
auto* inst = b.StoreVectorElement(to, 2_i, 4_i);
ASSERT_TRUE(inst->Is<StoreVectorElement>());
- ASSERT_EQ(inst->To(), to->Result());
+ ASSERT_EQ(inst->To(), to->Result(0));
ASSERT_TRUE(inst->Index()->Is<Constant>());
auto index = inst->Index()->As<Constant>()->Value();
@@ -75,8 +75,7 @@
auto* to = b.Var(ty.ptr<private_, vec3<i32>>());
auto* inst = b.StoreVectorElement(to, 2_i, 4_i);
- EXPECT_FALSE(inst->HasResults());
- EXPECT_FALSE(inst->HasMultiResults());
+ EXPECT_TRUE(inst->Results().IsEmpty());
}
TEST_F(IR_StoreVectorElementTest, Clone) {
@@ -87,7 +86,7 @@
auto* new_inst = clone_ctx.Clone(inst);
EXPECT_NE(inst, new_inst);
- EXPECT_EQ(new_to->Result(), new_inst->To());
+ EXPECT_EQ(new_to->Result(0), new_inst->To());
auto new_idx = new_inst->Index()->As<Constant>()->Value();
ASSERT_TRUE(new_idx->Is<core::constant::Scalar<i32>>());
diff --git a/src/tint/lang/core/ir/switch.cc b/src/tint/lang/core/ir/switch.cc
index 3880fa0..30e08bf 100644
--- a/src/tint/lang/core/ir/switch.cc
+++ b/src/tint/lang/core/ir/switch.cc
@@ -27,6 +27,8 @@
#include "src/tint/lang/core/ir/switch.h"
+#include <utility>
+
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/utils/ice/ice.h"
@@ -45,7 +47,7 @@
void Switch::ForeachBlock(const std::function<void(ir::Block*)>& cb) {
for (auto& c : cases_) {
- cb(c.Block());
+ cb(c.block);
}
}
@@ -55,17 +57,17 @@
ctx.Replace(this, new_switch);
new_switch->cases_.Reserve(cases_.Length());
- for (const auto& cse : cases_) {
+ for (auto& cse : cases_) {
Switch::Case new_case{};
new_case.block = ctx.ir.blocks.Create<ir::Block>();
cse.block->CloneInto(ctx, new_case.block);
new_case.selectors.Reserve(cse.selectors.Length());
- for (const auto& sel : cse.selectors) {
+ for (auto& sel : cse.selectors) {
auto* new_val = sel.val ? ctx.Clone(sel.val) : nullptr;
new_case.selectors.Push(Switch::CaseSelector{new_val});
}
- new_switch->cases_.Push(new_case);
+ new_switch->cases_.Push(std::move(new_case));
}
new_switch->SetResults(ctx.Clone(results_));
diff --git a/src/tint/lang/core/ir/switch.h b/src/tint/lang/core/ir/switch.h
index 4ca3965..3b44161 100644
--- a/src/tint/lang/core/ir/switch.h
+++ b/src/tint/lang/core/ir/switch.h
@@ -29,8 +29,10 @@
#define SRC_TINT_LANG_CORE_IR_SWITCH_H_
#include <string>
+#include <utility>
#include "src/tint/lang/core/ir/control_instruction.h"
+#include "src/tint/utils/containers/const_propagating_ptr.h"
// Forward declarations
namespace tint::core::ir {
@@ -64,21 +66,19 @@
/// A case selector
struct CaseSelector {
/// @returns true if this is a default selector
- bool IsDefault() { return val == nullptr; }
+ bool IsDefault() const { return val == nullptr; }
/// The selector value, or nullptr if this is the default selector
- Constant* val = nullptr;
+ ConstPropagatingPtr<Constant> val;
};
/// A case label in the struct
struct Case {
/// The case selector for this node
Vector<CaseSelector, 4> selectors;
- /// The case block.
- ir::Block* block = nullptr;
- /// @returns the case block
- ir::Block* Block() { return block; }
+ /// The case block.
+ ConstPropagatingPtr<ir::Block> block;
};
/// Constructor
@@ -95,11 +95,17 @@
/// @returns the switch cases
Vector<Case, 4>& Cases() { return cases_; }
+ /// @returns the switch cases
+ VectorRef<Case> Cases() const { return cases_; }
+
/// @returns the condition
Value* Condition() { return operands_[kConditionOperandOffset]; }
+ /// @returns the condition
+ const Value* Condition() const { return operands_[kConditionOperandOffset]; }
+
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "switch"; }
+ std::string FriendlyName() const override { return "switch"; }
private:
Vector<Case, 4> cases_;
diff --git a/src/tint/lang/core/ir/switch_test.cc b/src/tint/lang/core/ir/switch_test.cc
index f71b256..7391458 100644
--- a/src/tint/lang/core/ir/switch_test.cc
+++ b/src/tint/lang/core/ir/switch_test.cc
@@ -47,21 +47,19 @@
TEST_F(IR_SwitchTest, Results) {
auto* cond = b.Constant(true);
auto* switch_ = b.Switch(cond);
- EXPECT_FALSE(switch_->HasResults());
- EXPECT_FALSE(switch_->HasMultiResults());
+ EXPECT_TRUE(switch_->Results().IsEmpty());
}
TEST_F(IR_SwitchTest, Parent) {
auto* switch_ = b.Switch(1_i);
- b.Case(switch_, {Switch::CaseSelector{nullptr}});
- EXPECT_THAT(switch_->Cases().Front().Block()->Parent(), switch_);
+ b.DefaultCase(switch_);
+ EXPECT_THAT(switch_->Cases().Front().block->Parent(), switch_);
}
TEST_F(IR_SwitchTest, Clone) {
auto* switch_ = b.Switch(1_i);
- switch_->Cases().Push(
- Switch::Case{{Switch::CaseSelector{}, Switch::CaseSelector{b.Constant(2_i)}}, b.Block()});
- switch_->Cases().Push(Switch::Case{{Switch::CaseSelector{b.Constant(3_i)}}, b.Block()});
+ b.Case(switch_, {nullptr, b.Constant(2_i)});
+ b.Case(switch_, {b.Constant(3_i)});
auto* new_switch = clone_ctx.Clone(switch_);
@@ -103,9 +101,8 @@
{
auto* switch_ = b.Switch(1_i);
- auto* blk = b.Block();
+ auto* blk = b.Case(switch_, {b.Constant(3_i)});
b.Append(blk, [&] { b.ExitSwitch(switch_); });
- switch_->Cases().Push(Switch::Case{{Switch::CaseSelector{b.Constant(3_i)}}, blk});
new_switch = clone_ctx.Clone(switch_);
}
@@ -122,9 +119,8 @@
auto* switch_ = b.Switch(1_i);
switch_->SetResults(Vector{r0, r1});
- auto* blk = b.Block();
+ auto* blk = b.Case(switch_, Vector{b.Constant(3_i)});
b.Append(blk, [&] { b.ExitSwitch(switch_, b.Constant(42_i), b.Constant(42_f)); });
- switch_->Cases().Push(Switch::Case{{Switch::CaseSelector{b.Constant(3_i)}}, blk});
new_switch = clone_ctx.Clone(switch_);
}
diff --git a/src/tint/lang/core/ir/swizzle.cc b/src/tint/lang/core/ir/swizzle.cc
index 2c10907..1a1e6dc 100644
--- a/src/tint/lang/core/ir/swizzle.cc
+++ b/src/tint/lang/core/ir/swizzle.cc
@@ -53,7 +53,7 @@
Swizzle::~Swizzle() = default;
Swizzle* Swizzle::Clone(CloneContext& ctx) {
- auto* result = ctx.Clone(Result());
+ auto* result = ctx.Clone(Result(0));
auto* obj = ctx.Remap(Object());
return ctx.ir.instructions.Create<Swizzle>(result, obj, indices_);
}
diff --git a/src/tint/lang/core/ir/swizzle.h b/src/tint/lang/core/ir/swizzle.h
index afda992..1e5b0fc 100644
--- a/src/tint/lang/core/ir/swizzle.h
+++ b/src/tint/lang/core/ir/swizzle.h
@@ -54,11 +54,14 @@
/// @returns the object used for the access
Value* Object() { return operands_[kObjectOperandOffset]; }
+ /// @returns the object used for the access
+ const Value* Object() const { return operands_[kObjectOperandOffset]; }
+
/// @returns the swizzle indices
- VectorRef<uint32_t> Indices() { return indices_; }
+ VectorRef<uint32_t> Indices() const { return indices_; }
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "swizzle"; }
+ std::string FriendlyName() const override { return "swizzle"; }
private:
Vector<uint32_t, 4> indices_;
diff --git a/src/tint/lang/core/ir/swizzle_test.cc b/src/tint/lang/core/ir/swizzle_test.cc
index 153db7b..e66a578 100644
--- a/src/tint/lang/core/ir/swizzle_test.cc
+++ b/src/tint/lang/core/ir/swizzle_test.cc
@@ -42,17 +42,16 @@
auto* var = b.Var(ty.ptr<function, i32>());
auto* a = b.Swizzle(mod.Types().i32(), var, {1u});
- EXPECT_THAT(var->Result()->Usages(), testing::UnorderedElementsAre(Usage{a, 0u}));
+ EXPECT_THAT(var->Result(0)->Usages(), testing::UnorderedElementsAre(Usage{a, 0u}));
}
TEST_F(IR_SwizzleTest, Results) {
auto* var = b.Var(ty.ptr<function, i32>());
auto* a = b.Swizzle(mod.Types().i32(), var, {1u});
- EXPECT_TRUE(a->HasResults());
- EXPECT_FALSE(a->HasMultiResults());
- EXPECT_TRUE(a->Result()->Is<InstructionResult>());
- EXPECT_EQ(a->Result()->Source(), a);
+ EXPECT_EQ(a->Results().Length(), 1u);
+ EXPECT_TRUE(a->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(a->Result(0)->Instruction(), a);
}
TEST_F(IR_SwizzleTest, Fail_NullType) {
@@ -107,10 +106,10 @@
auto* new_s = clone_ctx.Clone(s);
EXPECT_NE(s, new_s);
- EXPECT_NE(nullptr, new_s->Result());
- EXPECT_NE(s->Result(), new_s->Result());
+ EXPECT_NE(nullptr, new_s->Result(0));
+ EXPECT_NE(s->Result(0), new_s->Result(0));
- EXPECT_EQ(new_var->Result(), new_s->Object());
+ EXPECT_EQ(new_var->Result(0), new_s->Object());
EXPECT_EQ(1u, new_s->Indices().Length());
EXPECT_EQ(2u, new_s->Indices().Front());
diff --git a/src/tint/lang/core/ir/terminate_invocation.h b/src/tint/lang/core/ir/terminate_invocation.h
index 7697c78..b0308bb 100644
--- a/src/tint/lang/core/ir/terminate_invocation.h
+++ b/src/tint/lang/core/ir/terminate_invocation.h
@@ -43,7 +43,7 @@
TerminateInvocation* Clone(CloneContext& ctx) override;
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "terminate_invocation"; }
+ std::string FriendlyName() const override { return "terminate_invocation"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/terminator.h b/src/tint/lang/core/ir/terminator.h
index 1f12541..f02c7b2 100644
--- a/src/tint/lang/core/ir/terminator.h
+++ b/src/tint/lang/core/ir/terminator.h
@@ -44,8 +44,16 @@
public:
~Terminator() override;
- /// @returns the terminator arguments
- virtual tint::Slice<Value* const> Args() { return operands_.Slice(); }
+ /// @returns the offset of the arguments in Operands()
+ virtual size_t ArgsOperandOffset() const { return 0; }
+
+ /// @returns the call arguments
+ tint::Slice<Value* const> Args() { return operands_.Slice().Offset(ArgsOperandOffset()); }
+
+ /// @returns the call arguments
+ tint::Slice<const Value* const> Args() const {
+ return operands_.Slice().Offset(ArgsOperandOffset());
+ }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/transform/BUILD.bazel b/src/tint/lang/core/ir/transform/BUILD.bazel
index 8870a6b..b75b761 100644
--- a/src/tint/lang/core/ir/transform/BUILD.bazel
+++ b/src/tint/lang/core/ir/transform/BUILD.bazel
@@ -54,6 +54,7 @@
"robustness.cc",
"shader_io.cc",
"std140.cc",
+ "value_to_let.cc",
"vectorize_scalar_matrix_constructors.cc",
"zero_init_workgroup_memory.cc",
],
@@ -73,6 +74,7 @@
"robustness.h",
"shader_io.h",
"std140.h",
+ "value_to_let.h",
"vectorize_scalar_matrix_constructors.h",
"zero_init_workgroup_memory.h",
],
@@ -120,6 +122,7 @@
"preserve_padding_test.cc",
"robustness_test.cc",
"std140_test.cc",
+ "value_to_let_test.cc",
"vectorize_scalar_matrix_constructors_test.cc",
"zero_init_workgroup_memory_test.cc",
] + select({
@@ -144,6 +147,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/lang/wgsl/writer/ir_to_program",
diff --git a/src/tint/lang/core/ir/transform/BUILD.cmake b/src/tint/lang/core/ir/transform/BUILD.cmake
index 3465e11..76a01e3 100644
--- a/src/tint/lang/core/ir/transform/BUILD.cmake
+++ b/src/tint/lang/core/ir/transform/BUILD.cmake
@@ -69,6 +69,8 @@
lang/core/ir/transform/shader_io.h
lang/core/ir/transform/std140.cc
lang/core/ir/transform/std140.h
+ lang/core/ir/transform/value_to_let.cc
+ lang/core/ir/transform/value_to_let.h
lang/core/ir/transform/vectorize_scalar_matrix_constructors.cc
lang/core/ir/transform/vectorize_scalar_matrix_constructors.h
lang/core/ir/transform/zero_init_workgroup_memory.cc
@@ -118,6 +120,7 @@
lang/core/ir/transform/preserve_padding_test.cc
lang/core/ir/transform/robustness_test.cc
lang/core/ir/transform/std140_test.cc
+ lang/core/ir/transform/value_to_let_test.cc
lang/core/ir/transform/vectorize_scalar_matrix_constructors_test.cc
lang/core/ir/transform/zero_init_workgroup_memory_test.cc
)
@@ -134,6 +137,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_lang_wgsl_writer_ir_to_program
diff --git a/src/tint/lang/core/ir/transform/BUILD.gn b/src/tint/lang/core/ir/transform/BUILD.gn
index 7343823..fbb325a 100644
--- a/src/tint/lang/core/ir/transform/BUILD.gn
+++ b/src/tint/lang/core/ir/transform/BUILD.gn
@@ -74,6 +74,8 @@
"shader_io.h",
"std140.cc",
"std140.h",
+ "value_to_let.cc",
+ "value_to_let.h",
"vectorize_scalar_matrix_constructors.cc",
"vectorize_scalar_matrix_constructors.h",
"zero_init_workgroup_memory.cc",
@@ -120,6 +122,7 @@
"preserve_padding_test.cc",
"robustness_test.cc",
"std140_test.cc",
+ "value_to_let_test.cc",
"vectorize_scalar_matrix_constructors_test.cc",
"zero_init_workgroup_memory_test.cc",
]
@@ -136,6 +139,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/lang/wgsl/writer/ir_to_program",
diff --git a/src/tint/lang/core/ir/transform/add_empty_entry_point.cc b/src/tint/lang/core/ir/transform/add_empty_entry_point.cc
index 4c86d58..d1b35b4 100644
--- a/src/tint/lang/core/ir/transform/add_empty_entry_point.cc
+++ b/src/tint/lang/core/ir/transform/add_empty_entry_point.cc
@@ -38,7 +38,7 @@
namespace {
void Run(ir::Module& ir) {
- for (auto* func : ir.functions) {
+ for (auto& func : ir.functions) {
if (func->Stage() != Function::PipelineStage::kUndefined) {
return;
}
diff --git a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
index 5d81e6b..0d9b9fa 100644
--- a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
@@ -63,7 +63,7 @@
if (!var) {
continue;
}
- auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+ auto* ptr = var->Result(0)->Type()->As<core::type::Pointer>();
if (!ptr) {
continue;
}
@@ -80,7 +80,7 @@
}
// Find function parameters that need to be replaced.
- for (auto* func : ir.functions) {
+ for (auto& func : ir.functions) {
for (uint32_t index = 0; index < func->Params().Length(); index++) {
auto* param = func->Params()[index];
auto* storage_texture = param->Type()->As<core::type::StorageTexture>();
@@ -108,7 +108,7 @@
}
// Replace all uses of the old variable with the new one.
- ReplaceUses(old_var->Result(), new_var->Result());
+ ReplaceUses(old_var->Result(0), new_var->Result(0));
}
/// Replace a function parameter with one that uses rgba8unorm instead of bgra8unorm.
@@ -147,7 +147,7 @@
// Replace load instructions with new ones that have the updated type.
auto* new_load = b.Load(new_value);
new_load->InsertBefore(load);
- ReplaceUses(load->Result(), new_load->Result());
+ ReplaceUses(load->Result(0), new_load->Result(0));
load->Destroy();
},
[&](CoreBuiltinCall* call) {
@@ -160,14 +160,14 @@
auto* value = call->Args()[index];
auto* swizzle = b.Swizzle(value->Type(), value, Vector{2u, 1u, 0u, 3u});
swizzle->InsertBefore(call);
- call->SetOperand(index, swizzle->Result());
+ call->SetOperand(index, swizzle->Result(0));
} else if (call->Func() == core::BuiltinFn::kTextureLoad) {
// Swizzle the result of a `textureLoad()` builtin.
auto* swizzle =
- b.Swizzle(call->Result()->Type(), nullptr, Vector{2u, 1u, 0u, 3u});
- call->Result()->ReplaceAllUsesWith(swizzle->Result());
+ b.Swizzle(call->Result(0)->Type(), nullptr, Vector{2u, 1u, 0u, 3u});
+ call->Result(0)->ReplaceAllUsesWith(swizzle->Result(0));
swizzle->InsertAfter(call);
- swizzle->SetOperand(Swizzle::kObjectOperandOffset, call->Result());
+ swizzle->SetOperand(Swizzle::kObjectOperandOffset, call->Result(0));
}
},
[&](UserCall* call) {
diff --git a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
index a51835b..6357040 100644
--- a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
+++ b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
@@ -72,7 +72,7 @@
auto* value = b.FunctionParam("value", ty.vec4<f32>());
func->SetParams({value, coords});
b.Append(func->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
b.Call(ty.void_(), core::BuiltinFn::kTextureStore, load, coords, value);
b.Return(func);
});
@@ -145,7 +145,7 @@
auto* value = b.FunctionParam("value", ty.vec4<f32>());
func->SetParams({value, coords});
b.Append(func->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
b.Call(ty.void_(), core::BuiltinFn::kTextureStore, load, coords, value);
b.Return(func);
});
@@ -252,7 +252,7 @@
auto* value = b.FunctionParam("value", ty.vec4<f32>());
foo->SetParams({coords, value});
b.Append(foo->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
b.Call(ty.void_(), bar, load, coords, value);
b.Return(foo);
});
@@ -342,9 +342,9 @@
auto* value = b.FunctionParam("value", ty.vec4<f32>());
foo->SetParams({coords, value});
b.Append(foo->Block(), [&] {
- auto* load_a = b.Load(var_a->Result());
- auto* load_b = b.Load(var_b->Result());
- auto* load_c = b.Load(var_c->Result());
+ auto* load_a = b.Load(var_a->Result(0));
+ auto* load_b = b.Load(var_b->Result(0));
+ auto* load_c = b.Load(var_c->Result(0));
b.Call(ty.void_(), bar, load_a, load_b, load_c, coords, value);
b.Return(foo);
});
@@ -440,11 +440,11 @@
auto* value = b.FunctionParam("value", ty.vec4<f32>());
foo->SetParams({coords, value});
b.Append(foo->Block(), [&] {
- auto* load_a = b.Load(var_a->Result());
+ auto* load_a = b.Load(var_a->Result(0));
b.Call(ty.void_(), core::BuiltinFn::kTextureStore, load_a, coords, value);
- auto* load_b = b.Load(var_a->Result());
+ auto* load_b = b.Load(var_a->Result(0));
b.Call(ty.void_(), bar, load_b, coords, value);
- auto* load_c = b.Load(var_a->Result());
+ auto* load_c = b.Load(var_a->Result(0));
b.Call(ty.void_(), bar, load_c, coords, value);
b.Return(foo);
});
@@ -527,7 +527,7 @@
auto* value = b.FunctionParam("value", ty.vec4<f32>());
func->SetParams({value, coords});
b.Append(func->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
b.Call(ty.void_(), core::BuiltinFn::kTextureStore, load, coords, index, value);
b.Return(func);
});
@@ -578,7 +578,7 @@
auto* func = b.Function("foo", ty.vec2<u32>());
b.Append(func->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
auto* dims = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, load);
b.Return(func, dims);
mod.SetName(dims, "dims");
@@ -631,7 +631,7 @@
auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
func->SetParams({coords});
b.Append(func->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load, coords);
b.Return(func, result);
mod.SetName(result, "result");
@@ -685,7 +685,7 @@
auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
func->SetParams({coords});
b.Append(func->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load, coords);
b.Call(ty.void_(), core::BuiltinFn::kTextureStore, load, coords, result);
b.Return(func);
diff --git a/src/tint/lang/core/ir/transform/binary_polyfill.cc b/src/tint/lang/core/ir/transform/binary_polyfill.cc
index 276bec4..ba175c6 100644
--- a/src/tint/lang/core/ir/transform/binary_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/binary_polyfill.cc
@@ -76,7 +76,7 @@
case BinaryOp::kDivide:
case BinaryOp::kModulo:
if (config.int_div_mod &&
- binary->Result()->Type()->is_integer_scalar_or_vector()) {
+ binary->Result(0)->Type()->is_integer_scalar_or_vector()) {
worklist.Push(binary);
}
break;
@@ -109,12 +109,12 @@
}
TINT_ASSERT_OR_RETURN(replacement);
- if (replacement != binary->Result()) {
+ if (replacement != binary->Result(0)) {
// Replace the old binary instruction result with the new value.
- if (auto name = ir.NameOf(binary->Result())) {
+ if (auto name = ir.NameOf(binary->Result(0))) {
ir.SetName(replacement, name);
}
- binary->Result()->ReplaceAllUsesWith(replacement);
+ binary->Result(0)->ReplaceAllUsesWith(replacement);
binary->Destroy();
}
}
@@ -150,7 +150,7 @@
/// @param binary the binary instruction
/// @returns the replacement value
ir::Value* IntDivMod(ir::Binary* binary) {
- auto* result_ty = binary->Result()->Type();
+ auto* result_ty = binary->Result(0)->Type();
bool is_div = binary->Op() == BinaryOp::kDivide;
bool is_signed = result_ty->is_signed_integer_scalar_or_vector();
@@ -197,7 +197,7 @@
if (binary->Op() == BinaryOp::kDivide) {
// Perform the divide with the modified RHS.
- b.Return(func, b.Divide(result_ty, lhs, rhs_or_one)->Result());
+ b.Return(func, b.Divide(result_ty, lhs, rhs_or_one)->Result(0));
} else if (binary->Op() == BinaryOp::kModulo) {
// Calculate the modulo manually, as modulo with negative operands is undefined
// behavior for many backends:
@@ -205,7 +205,7 @@
auto* whole = b.Divide(result_ty, lhs, rhs_or_one);
auto* remainder =
b.Subtract(result_ty, lhs, b.Multiply(result_ty, whole, rhs_or_one));
- b.Return(func, remainder->Result());
+ b.Return(func, remainder->Result(0));
}
});
return func;
@@ -214,7 +214,7 @@
/// Helper to splat a value to match the vector width of the result type if necessary.
auto maybe_splat = [&](ir::Value* value) -> ir::Value* {
if (value->Type()->Is<type::Scalar>() && result_ty->Is<core::type::Vector>()) {
- return b.Construct(result_ty, value)->Result();
+ return b.Construct(result_ty, value)->Result(0);
}
return value;
};
@@ -224,7 +224,7 @@
b.InsertBefore(binary, [&] {
auto* lhs = maybe_splat(binary->LHS());
auto* rhs = maybe_splat(binary->RHS());
- result = b.Call(result_ty, helper, lhs, rhs)->Result();
+ result = b.Call(result_ty, helper, lhs, rhs)->Result(0);
});
return result;
}
@@ -238,8 +238,8 @@
auto* mask = b.Constant(u32(lhs->Type()->DeepestElement()->Size() * 8 - 1));
auto* masked = b.And(rhs->Type(), rhs, MatchWidth(mask, rhs->Type()));
masked->InsertBefore(binary);
- binary->SetOperand(ir::Binary::kRhsOperandOffset, masked->Result());
- return binary->Result();
+ binary->SetOperand(ir::Binary::kRhsOperandOffset, masked->Result(0));
+ return binary->Result(0);
}
};
diff --git a/src/tint/lang/core/ir/transform/block_decorated_structs.cc b/src/tint/lang/core/ir/transform/block_decorated_structs.cc
index 32cbbd5..91d4b3d 100644
--- a/src/tint/lang/core/ir/transform/block_decorated_structs.cc
+++ b/src/tint/lang/core/ir/transform/block_decorated_structs.cc
@@ -56,7 +56,7 @@
if (!var) {
continue;
}
- auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+ auto* ptr = var->Result(0)->Type()->As<core::type::Pointer>();
if (!ptr || !core::IsHostShareable(ptr->AddressSpace())) {
continue;
}
@@ -65,7 +65,7 @@
// Now process the buffer variables.
for (auto* var : buffer_variables) {
- auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+ auto* ptr = var->Result(0)->Type()->As<core::type::Pointer>();
auto* store_ty = ptr->StoreType();
if (auto* str = store_ty->As<core::type::Struct>(); str && !str->HasFixedFootprint()) {
@@ -93,10 +93,10 @@
// Replace uses of the old variable.
// The structure has been wrapped, so replace all uses of the old variable with a member
// accessor on the new variable.
- var->Result()->ReplaceAllUsesWith([&](Usage use) -> Value* {
- auto* access = builder.Access(var->Result()->Type(), new_var, 0_u);
+ var->Result(0)->ReplaceAllUsesWith([&](Usage use) -> Value* {
+ auto* access = builder.Access(var->Result(0)->Type(), new_var, 0_u);
access->InsertBefore(use.instruction);
- return access->Result();
+ return access->Result(0);
});
var->Destroy();
diff --git a/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc b/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc
index dfe8d6a..e681183 100644
--- a/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc
+++ b/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc
@@ -256,7 +256,7 @@
auto* func = b.Function("foo", ty.u32());
b.Append(func->Block(), [&] {
- auto* let_root = b.Let("root", buffer->Result());
+ auto* let_root = b.Let("root", buffer->Result(0));
auto* let_arr = b.Let("arr", b.Access(ty.ptr(storage, ty.array<i32>()), let_root, 1_u));
auto* length = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, let_arr);
b.Return(func, length);
@@ -343,7 +343,7 @@
buffer_a->SetBindingPoint(0, 0);
buffer_b->SetBindingPoint(0, 1);
buffer_c->SetBindingPoint(0, 2);
- auto* root = mod.root_block;
+ auto* root = mod.root_block.Get();
root->Append(buffer_a);
root->Append(buffer_b);
root->Append(buffer_c);
diff --git a/src/tint/lang/core/ir/transform/builtin_polyfill.cc b/src/tint/lang/core/ir/transform/builtin_polyfill.cc
index b59f6e4..07f299c 100644
--- a/src/tint/lang/core/ir/transform/builtin_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/builtin_polyfill.cc
@@ -70,7 +70,7 @@
switch (builtin->Func()) {
case core::BuiltinFn::kClamp:
if (config.clamp_int &&
- builtin->Result()->Type()->is_integer_scalar_or_vector()) {
+ builtin->Result(0)->Type()->is_integer_scalar_or_vector()) {
worklist.Push(builtin);
}
break;
@@ -161,12 +161,12 @@
}
TINT_ASSERT_OR_RETURN(replacement);
- if (replacement != builtin->Result()) {
+ if (replacement != builtin->Result(0)) {
// Replace the old builtin call result with the new value.
- if (auto name = ir.NameOf(builtin->Result())) {
+ if (auto name = ir.NameOf(builtin->Result(0))) {
ir.SetName(replacement, name);
}
- builtin->Result()->ReplaceAllUsesWith(replacement);
+ builtin->Result(0)->ReplaceAllUsesWith(replacement);
builtin->Destroy();
}
}
@@ -201,7 +201,7 @@
/// @param call the builtin call instruction
/// @returns the replacement value
ir::Value* ClampInt(ir::CoreBuiltinCall* call) {
- auto* type = call->Result()->Type();
+ auto* type = call->Result(0)->Type();
auto* e = call->Args()[0];
auto* low = call->Args()[1];
auto* high = call->Args()[2];
@@ -210,7 +210,7 @@
b.InsertBefore(call, [&] {
auto* max = b.Call(type, core::BuiltinFn::kMax, e, low);
auto* min = b.Call(type, core::BuiltinFn::kMin, max, high);
- result = min->Result();
+ result = min->Result(0);
});
return result;
}
@@ -247,20 +247,20 @@
auto* x = input;
if (result_ty->is_signed_integer_scalar_or_vector()) {
- x = b.Bitcast(uint_ty, x)->Result();
+ x = b.Bitcast(uint_ty, x)->Result(0);
}
auto* b16 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(16),
b.LessThanEqual(bool_ty, x, V(0x0000ffff)));
- x = b.ShiftLeft(uint_ty, x, b16)->Result();
+ x = b.ShiftLeft(uint_ty, x, b16)->Result(0);
auto* b8 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(8),
b.LessThanEqual(bool_ty, x, V(0x00ffffff)));
- x = b.ShiftLeft(uint_ty, x, b8)->Result();
+ x = b.ShiftLeft(uint_ty, x, b8)->Result(0);
auto* b4 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(4),
b.LessThanEqual(bool_ty, x, V(0x0fffffff)));
- x = b.ShiftLeft(uint_ty, x, b4)->Result();
+ x = b.ShiftLeft(uint_ty, x, b4)->Result(0);
auto* b2 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(2),
b.LessThanEqual(bool_ty, x, V(0x3fffffff)));
- x = b.ShiftLeft(uint_ty, x, b2)->Result();
+ x = b.ShiftLeft(uint_ty, x, b2)->Result(0);
auto* b1 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(1),
b.LessThanEqual(bool_ty, x, V(0x7fffffff)));
auto* b0 =
@@ -270,9 +270,9 @@
b.Or(uint_ty, b8,
b.Or(uint_ty, b4, b.Or(uint_ty, b2, b.Or(uint_ty, b1, b0))))),
b0)
- ->Result();
+ ->Result(0);
if (result_ty->is_signed_integer_scalar_or_vector()) {
- result = b.Bitcast(result_ty, result)->Result();
+ result = b.Bitcast(result_ty, result)->Result(0);
}
});
return result;
@@ -310,20 +310,20 @@
auto* x = input;
if (result_ty->is_signed_integer_scalar_or_vector()) {
- x = b.Bitcast(uint_ty, x)->Result();
+ x = b.Bitcast(uint_ty, x)->Result(0);
}
auto* b16 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(16),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000ffff)), V(0)));
- x = b.ShiftRight(uint_ty, x, b16)->Result();
+ x = b.ShiftRight(uint_ty, x, b16)->Result(0);
auto* b8 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(8),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x000000ff)), V(0)));
- x = b.ShiftRight(uint_ty, x, b8)->Result();
+ x = b.ShiftRight(uint_ty, x, b8)->Result(0);
auto* b4 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(4),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000000f)), V(0)));
- x = b.ShiftRight(uint_ty, x, b4)->Result();
+ x = b.ShiftRight(uint_ty, x, b4)->Result(0);
auto* b2 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(2),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x00000003)), V(0)));
- x = b.ShiftRight(uint_ty, x, b2)->Result();
+ x = b.ShiftRight(uint_ty, x, b2)->Result(0);
auto* b1 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(1),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x00000001)), V(0)));
auto* b0 =
@@ -332,9 +332,9 @@
b.Or(uint_ty, b16,
b.Or(uint_ty, b8, b.Or(uint_ty, b4, b.Or(uint_ty, b2, b1)))),
b0)
- ->Result();
+ ->Result(0);
if (result_ty->is_signed_integer_scalar_or_vector()) {
- result = b.Bitcast(result_ty, result)->Result();
+ result = b.Bitcast(result_ty, result)->Result(0);
}
});
return result;
@@ -359,10 +359,10 @@
auto* o = b.Call(ty.u32(), core::BuiltinFn::kMin, offset, 32_u);
auto* c = b.Call(ty.u32(), core::BuiltinFn::kMin, count,
b.Subtract(ty.u32(), 32_u, o));
- call->SetOperand(ir::CoreBuiltinCall::kArgsOperandOffset + 1, o->Result());
- call->SetOperand(ir::CoreBuiltinCall::kArgsOperandOffset + 2, c->Result());
+ call->SetOperand(ir::CoreBuiltinCall::kArgsOperandOffset + 1, o->Result(0));
+ call->SetOperand(ir::CoreBuiltinCall::kArgsOperandOffset + 2, c->Result(0));
});
- return call->Result();
+ return call->Result(0);
}
default:
TINT_UNIMPLEMENTED() << "extractBits polyfill level";
@@ -402,33 +402,33 @@
auto* x = input;
if (result_ty->is_signed_integer_scalar_or_vector()) {
- x = b.Bitcast(uint_ty, x)->Result();
+ x = b.Bitcast(uint_ty, x)->Result(0);
auto* inverted = b.Complement(uint_ty, x);
x = b.Call(uint_ty, core::BuiltinFn::kSelect, inverted, x,
b.LessThan(bool_ty, x, V(0x80000000)))
- ->Result();
+ ->Result(0);
}
auto* b16 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(16), V(0),
b.Equal(bool_ty, b.And(uint_ty, x, V(0xffff0000)), V(0)));
- x = b.ShiftRight(uint_ty, x, b16)->Result();
+ x = b.ShiftRight(uint_ty, x, b16)->Result(0);
auto* b8 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(8), V(0),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000ff00)), V(0)));
- x = b.ShiftRight(uint_ty, x, b8)->Result();
+ x = b.ShiftRight(uint_ty, x, b8)->Result(0);
auto* b4 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(4), V(0),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x000000f0)), V(0)));
- x = b.ShiftRight(uint_ty, x, b4)->Result();
+ x = b.ShiftRight(uint_ty, x, b4)->Result(0);
auto* b2 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(2), V(0),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000000c)), V(0)));
- x = b.ShiftRight(uint_ty, x, b2)->Result();
+ x = b.ShiftRight(uint_ty, x, b2)->Result(0);
auto* b1 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(1), V(0),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x00000002)), V(0)));
result = b.Or(uint_ty, b16, b.Or(uint_ty, b8, b.Or(uint_ty, b4, b.Or(uint_ty, b2, b1))))
- ->Result();
+ ->Result(0);
result = b.Call(uint_ty, core::BuiltinFn::kSelect, result, V(0xffffffff),
b.Equal(bool_ty, x, V(0)))
- ->Result();
+ ->Result(0);
if (result_ty->is_signed_integer_scalar_or_vector()) {
- result = b.Bitcast(result_ty, result)->Result();
+ result = b.Bitcast(result_ty, result)->Result(0);
}
});
return result;
@@ -466,29 +466,29 @@
auto* x = input;
if (result_ty->is_signed_integer_scalar_or_vector()) {
- x = b.Bitcast(uint_ty, x)->Result();
+ x = b.Bitcast(uint_ty, x)->Result(0);
}
auto* b16 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(16),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000ffff)), V(0)));
- x = b.ShiftRight(uint_ty, x, b16)->Result();
+ x = b.ShiftRight(uint_ty, x, b16)->Result(0);
auto* b8 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(8),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x000000ff)), V(0)));
- x = b.ShiftRight(uint_ty, x, b8)->Result();
+ x = b.ShiftRight(uint_ty, x, b8)->Result(0);
auto* b4 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(4),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000000f)), V(0)));
- x = b.ShiftRight(uint_ty, x, b4)->Result();
+ x = b.ShiftRight(uint_ty, x, b4)->Result(0);
auto* b2 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(2),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x00000003)), V(0)));
- x = b.ShiftRight(uint_ty, x, b2)->Result();
+ x = b.ShiftRight(uint_ty, x, b2)->Result(0);
auto* b1 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(1),
b.Equal(bool_ty, b.And(uint_ty, x, V(0x00000001)), V(0)));
result = b.Or(uint_ty, b16, b.Or(uint_ty, b8, b.Or(uint_ty, b4, b.Or(uint_ty, b2, b1))))
- ->Result();
+ ->Result(0);
result = b.Call(uint_ty, core::BuiltinFn::kSelect, result, V(0xffffffff),
b.Equal(bool_ty, x, V(0)))
- ->Result();
+ ->Result(0);
if (result_ty->is_signed_integer_scalar_or_vector()) {
- result = b.Bitcast(result_ty, result)->Result();
+ result = b.Bitcast(result_ty, result)->Result(0);
}
});
return result;
@@ -513,10 +513,10 @@
auto* o = b.Call(ty.u32(), core::BuiltinFn::kMin, offset, 32_u);
auto* c = b.Call(ty.u32(), core::BuiltinFn::kMin, count,
b.Subtract(ty.u32(), 32_u, o));
- call->SetOperand(ir::CoreBuiltinCall::kArgsOperandOffset + 2, o->Result());
- call->SetOperand(ir::CoreBuiltinCall::kArgsOperandOffset + 3, c->Result());
+ call->SetOperand(ir::CoreBuiltinCall::kArgsOperandOffset + 2, o->Result(0));
+ call->SetOperand(ir::CoreBuiltinCall::kArgsOperandOffset + 3, c->Result(0));
});
- return call->Result();
+ return call->Result(0);
}
default:
TINT_UNIMPLEMENTED() << "insertBits polyfill level";
@@ -529,7 +529,7 @@
/// @returns the replacement value
ir::Value* Saturate(ir::CoreBuiltinCall* call) {
// Replace `saturate(x)` with `clamp(x, 0., 1.)`.
- auto* type = call->Result()->Type();
+ auto* type = call->Result(0)->Type();
ir::Constant* zero = nullptr;
ir::Constant* one = nullptr;
if (type->DeepestElement()->Is<core::type::F32>()) {
@@ -541,7 +541,7 @@
}
auto* clamp = b.Call(type, core::BuiltinFn::kClamp, Vector{call->Args()[0], zero, one});
clamp->InsertBefore(call);
- return clamp->Result();
+ return clamp->Result(0);
}
/// Polyfill a `textureSampleBaseClampToEdge()` builtin call for 2D F32 textures.
@@ -567,7 +567,7 @@
b.Call(vec2f, core::BuiltinFn::kClamp, coords, half_texel, one_minus_half_texel);
result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleLevel, texture, sampler,
clamped, 0_f)
- ->Result();
+ ->Result(0);
});
return result;
}
diff --git a/src/tint/lang/core/ir/transform/combine_access_instructions.cc b/src/tint/lang/core/ir/transform/combine_access_instructions.cc
index 856d4cb..da304ea 100644
--- a/src/tint/lang/core/ir/transform/combine_access_instructions.cc
+++ b/src/tint/lang/core/ir/transform/combine_access_instructions.cc
@@ -52,7 +52,7 @@
if (auto* access = inst->As<ir::Access>(); access && access->Alive()) {
// Look for places where the result of this access instruction is used as a base
// pointer for another access instruction.
- access->Result()->ForEachUse([&](Usage use) {
+ access->Result(0)->ForEachUse([&](Usage use) {
auto* child = use.instruction->As<ir::Access>();
if (child && use.operand_index == ir::Access::kObjectOperandOffset) {
// Push the indices of the parent access instruction into the child.
@@ -69,7 +69,7 @@
});
// If there are no other uses of the access instruction, remove it.
- if (access->Result()->Usages().IsEmpty()) {
+ if (access->Result(0)->Usages().IsEmpty()) {
access->Destroy();
}
}
diff --git a/src/tint/lang/core/ir/transform/conversion_polyfill.cc b/src/tint/lang/core/ir/transform/conversion_polyfill.cc
index 62af849..f99ea69 100644
--- a/src/tint/lang/core/ir/transform/conversion_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/conversion_polyfill.cc
@@ -74,7 +74,7 @@
}
if (auto* convert = inst->As<ir::Convert>()) {
auto* src_ty = convert->Args()[0]->Type();
- auto* res_ty = convert->Result()->Type();
+ auto* res_ty = convert->Result(0)->Type();
if (config.ftoi && //
src_ty->is_float_scalar_or_vector() && //
res_ty->is_integer_scalar_or_vector()) {
@@ -88,10 +88,10 @@
auto* replacement = ftoi(convert);
// Replace the old conversion instruction result with the new value.
- if (auto name = ir.NameOf(convert->Result())) {
+ if (auto name = ir.NameOf(convert->Result(0))) {
ir.SetName(replacement, name);
}
- convert->Result()->ReplaceAllUsesWith(replacement);
+ convert->Result(0)->ReplaceAllUsesWith(replacement);
convert->Destroy();
}
}
@@ -101,7 +101,7 @@
/// @param convert the conversion instruction
/// @returns the replacement value
ir::Value* ftoi(ir::Convert* convert) {
- auto* res_ty = convert->Result()->Type();
+ auto* res_ty = convert->Result(0)->Type();
auto* src_ty = convert->Args()[0]->Type();
auto* src_el_ty = src_ty->DeepestElement();
@@ -187,7 +187,7 @@
auto* select_high = b.Call(res_ty, core::BuiltinFn::kSelect, limits.high_limit_i,
select_low, high_cond);
- b.Return(func, select_high->Result());
+ b.Return(func, select_high->Result(0));
});
return func;
});
@@ -195,7 +195,7 @@
// Call the helper function, splatting the arguments to match the target vector width.
auto* call = b.Call(res_ty, helper, convert->Args()[0]);
call->InsertBefore(convert);
- return call->Result();
+ return call->Result(0);
}
/// Return a type with element type @p type that has the same number of vector components as
diff --git a/src/tint/lang/core/ir/transform/demote_to_helper.cc b/src/tint/lang/core/ir/transform/demote_to_helper.cc
index 6e9953c..89bb789 100644
--- a/src/tint/lang/core/ir/transform/demote_to_helper.cc
+++ b/src/tint/lang/core/ir/transform/demote_to_helper.cc
@@ -66,7 +66,7 @@
// Check each function for discard instructions, potentially inside other functions called
// (transitively) by the function.
Vector<Function*, 4> to_process;
- for (auto* func : ir.functions) {
+ for (auto& func : ir.functions) {
// If the function contains a discard (directly or indirectly), we need to process it.
if (HasDiscard(func)) {
to_process.Push(func);
@@ -145,11 +145,12 @@
// Move the original instruction into the if-true block.
auto* result = ifelse->True()->Append(inst);
- TINT_ASSERT(!inst->HasMultiResults());
- if (inst->HasResults() && !inst->Result()->Type()->Is<core::type::Void>()) {
+ auto results = inst->Results();
+ TINT_ASSERT(results.Length() < 2);
+ if (!results.IsEmpty() && !results[0]->Type()->Is<core::type::Void>()) {
// The original instruction had a result, so return it from the if instruction.
- ifelse->SetResults(Vector{b.InstructionResult(inst->Result()->Type())});
- inst->Result()->ReplaceAllUsesWith(ifelse->Result());
+ ifelse->SetResults(Vector{b.InstructionResult(results[0]->Type())});
+ results[0]->ReplaceAllUsesWith(ifelse->Result(0));
ifelse->True()->Append(b.ExitIf(ifelse, result));
} else {
ifelse->True()->Append(b.ExitIf(ifelse));
@@ -160,7 +161,7 @@
for (auto* inst = *block->begin(); inst;) {
// As we're (potentially) modifying the block that we're iterating over, grab a pointer
// to the next instruction before we make any changes.
- auto* next = inst->next;
+ auto* next = inst->next.Get();
TINT_DEFER(inst = next);
tint::Switch(
@@ -203,6 +204,10 @@
[&](ControlInstruction* ctrl) {
// Recurse into control instructions.
ctrl->ForeachBlock([&](Block* blk) { ProcessBlock(blk); });
+ },
+ [&](BuiltinCall*) {
+ // TODO(crbug.com/tint/2102): Catch this with the validator instead.
+ TINT_UNREACHABLE() << "unexpected non-core instruction";
});
}
}
diff --git a/src/tint/lang/core/ir/transform/direct_variable_access.cc b/src/tint/lang/core/ir/transform/direct_variable_access.cc
index 6a264b9..0c2c27b 100644
--- a/src/tint/lang/core/ir/transform/direct_variable_access.cc
+++ b/src/tint/lang/core/ir/transform/direct_variable_access.cc
@@ -239,7 +239,8 @@
/// Process the module.
void Process() {
// Make a copy of all the functions in the IR module.
- auto input_fns = ir.functions;
+ // Use transform to convert from ConstPropagatingPtr<Function> to Function*
+ auto input_fns = Transform<8>(ir.functions.Slice(), [](auto& fn) { return fn.Get(); });
// Populate #need_forking
GatherFnsThatNeedForking();
@@ -258,7 +259,7 @@
/// Populates #need_forking with all the functions that have pointer parameters which need
/// transforming. These functions will be replaced with variants based on the access shapes.
void GatherFnsThatNeedForking() {
- for (auto* fn : ir.functions) {
+ for (auto& fn : ir.functions) {
for (auto* param : fn->Params()) {
if (ParamNeedsTransforming(param)) {
need_forking.Add(fn, fn_info_allocator.Create());
@@ -271,7 +272,7 @@
/// Adjusts the calls of all the functions that make calls to #need_forking, which aren't in
/// #need_forking themselves. This populates #variants_to_build with the called functions.
void BuildRootFns() {
- for (auto* fn : ir.functions) {
+ for (auto& fn : ir.functions) {
if (!need_forking.Contains(fn)) {
TransformCalls(fn);
}
@@ -330,7 +331,7 @@
if (size_t array_len = chain.indices.Length(); array_len > 0) {
auto* array = ty.array(ty.u32(), static_cast<uint32_t>(array_len));
auto* indices = b.Construct(array, std::move(chain.indices));
- new_args.Push(indices->Result());
+ new_args.Push(indices->Result(0));
}
// Record the parameter shape for the variant's signature.
signature.Add(i, chain.shape);
@@ -409,7 +410,7 @@
value, //
[&](InstructionResult* res) {
// value was emitted by an instruction
- auto* inst = res->Source();
+ auto* inst = res->Instruction();
return tint::Switch(
inst,
[&](Access* access) {
@@ -436,7 +437,7 @@
// Array or matrix access.
// Convert index to u32 if it isn't already.
if (!idx->Type()->Is<type::U32>()) {
- idx = b.Convert(ty.u32(), idx)->Result();
+ idx = b.Convert(ty.u32(), idx)->Result(0);
}
ops.Push(IndexAccess{});
@@ -455,7 +456,7 @@
chain.indices.Push(idx);
}
- TINT_ASSERT(obj_ty == access->Result()->Type()->UnwrapPtr());
+ TINT_ASSERT(obj_ty == access->Result(0)->Type()->UnwrapPtr());
return access->Object();
},
[&](Var* var) {
@@ -466,9 +467,9 @@
} else {
// Root pointer is a function-scope 'var'
chain.shape.root =
- RootPtrParameter{var->Result()->Type()->As<type::Pointer>()};
+ RootPtrParameter{var->Result(0)->Type()->As<type::Pointer>()};
}
- chain.root_ptr = var->Result();
+ chain.root_ptr = var->Result(0);
return nullptr;
},
[&](Let* let) { return let->Value(); }, //
@@ -524,7 +525,7 @@
root_ptr = root_ptr_param;
} else if (auto* global = std::get_if<RootModuleScopeVar>(&shape->root)) {
// Root pointer is a module-scope var
- root_ptr = global->var->Result();
+ root_ptr = global->var->Result(0);
} else {
TINT_ICE() << "unhandled AccessShape root variant";
}
@@ -555,12 +556,12 @@
return b.Constant(u32(m->member->Index()));
}
auto* access = b.Access(ty.u32(), indices_param, u32(index_index++));
- return access->Result();
+ return access->Result(0);
});
auto* access = b.Access(old_param->Type(), root_ptr, std::move(chain));
// Replace the now removed parameter value with the access instruction
- old_param->ReplaceAllUsesWith(access->Result());
+ old_param->ReplaceAllUsesWith(access->Result(0));
old_param->Destroy();
}
@@ -574,7 +575,7 @@
/// @param input_fns the content of #ir.functions before transformation began.
void EmitFunctions(VectorRef<Function*> input_fns) {
ir.functions.Clear();
- for (auto* fn : input_fns) {
+ for (auto& fn : input_fns) {
if (auto info = need_forking.Get(fn)) {
fn->Destroy();
for (auto variant : (*info)->ordered_variants) {
@@ -648,7 +649,7 @@
return; // Only instructions can be removed.
}
value = tint::Switch(
- inst_res->Source(), //
+ inst_res->Instruction(), //
[&](Access* access) {
TINT_DEFER(access->Destroy());
return access->Object();
diff --git a/src/tint/lang/core/ir/transform/direct_variable_access_wgsl_test.cc b/src/tint/lang/core/ir/transform/direct_variable_access_wgsl_test.cc
index f72262b..7b8a407 100644
--- a/src/tint/lang/core/ir/transform/direct_variable_access_wgsl_test.cc
+++ b/src/tint/lang/core/ir/transform/direct_variable_access_wgsl_test.cc
@@ -2168,7 +2168,7 @@
}
fn f() {
- len_S();
+ let n = len_S();
}
)";
@@ -2200,7 +2200,7 @@
}
fn f() {
- load_W();
+ let v = load_W();
}
)";
@@ -2369,33 +2369,33 @@
fn b() {
let I = 3i;
let J = 4i;
- fn_u_U();
- fn_u_U_str_i();
- fn_u_U_arr_X(array<u32, 1u>(u32(0i)));
- fn_u_U_arr_X(array<u32, 1u>(u32(1i)));
- fn_u_U_arr_X(array<u32, 1u>(u32(I)));
- fn_u_U_arr_arr_X_X(array<u32, 2u>(u32(1i), u32(0i)));
- fn_u_U_arr_arr_X_X(array<u32, 2u>(u32(2i), u32(I)));
- fn_u_U_arr_arr_X_X(array<u32, 2u>(u32(I), u32(2i)));
- fn_u_U_arr_arr_X_X(array<u32, 2u>(u32(I), u32(J)));
- fn_s_S();
- fn_s_S_str_i();
- fn_s_S_arr_X(array<u32, 1u>(u32(0i)));
- fn_s_S_arr_X(array<u32, 1u>(u32(1i)));
- fn_s_S_arr_X(array<u32, 1u>(u32(I)));
- fn_s_S_arr_arr_X_X(array<u32, 2u>(u32(1i), u32(0i)));
- fn_s_S_arr_arr_X_X(array<u32, 2u>(u32(2i), u32(I)));
- fn_s_S_arr_arr_X_X(array<u32, 2u>(u32(I), u32(2i)));
- fn_s_S_arr_arr_X_X(array<u32, 2u>(u32(I), u32(J)));
- fn_w_W();
- fn_w_W_str_i();
- fn_w_W_arr_X(array<u32, 1u>(u32(0i)));
- fn_w_W_arr_X(array<u32, 1u>(u32(1i)));
- fn_w_W_arr_X(array<u32, 1u>(u32(I)));
- fn_w_W_arr_arr_X_X(array<u32, 2u>(u32(1i), u32(0i)));
- fn_w_W_arr_arr_X_X(array<u32, 2u>(u32(2i), u32(I)));
- fn_w_W_arr_arr_X_X(array<u32, 2u>(u32(I), u32(2i)));
- fn_w_W_arr_arr_X_X(array<u32, 2u>(u32(I), u32(J)));
+ let u = fn_u_U();
+ let u_str = fn_u_U_str_i();
+ let u_arr0 = fn_u_U_arr_X(array<u32, 1u>(u32(0i)));
+ let u_arr1 = fn_u_U_arr_X(array<u32, 1u>(u32(1i)));
+ let u_arrI = fn_u_U_arr_X(array<u32, 1u>(u32(I)));
+ let u_arr1_arr0 = fn_u_U_arr_arr_X_X(array<u32, 2u>(u32(1i), u32(0i)));
+ let u_arr2_arrI = fn_u_U_arr_arr_X_X(array<u32, 2u>(u32(2i), u32(I)));
+ let u_arrI_arr2 = fn_u_U_arr_arr_X_X(array<u32, 2u>(u32(I), u32(2i)));
+ let u_arrI_arrJ = fn_u_U_arr_arr_X_X(array<u32, 2u>(u32(I), u32(J)));
+ let s = fn_s_S();
+ let s_str = fn_s_S_str_i();
+ let s_arr0 = fn_s_S_arr_X(array<u32, 1u>(u32(0i)));
+ let s_arr1 = fn_s_S_arr_X(array<u32, 1u>(u32(1i)));
+ let s_arrI = fn_s_S_arr_X(array<u32, 1u>(u32(I)));
+ let s_arr1_arr0 = fn_s_S_arr_arr_X_X(array<u32, 2u>(u32(1i), u32(0i)));
+ let s_arr2_arrI = fn_s_S_arr_arr_X_X(array<u32, 2u>(u32(2i), u32(I)));
+ let s_arrI_arr2 = fn_s_S_arr_arr_X_X(array<u32, 2u>(u32(I), u32(2i)));
+ let s_arrI_arrJ = fn_s_S_arr_arr_X_X(array<u32, 2u>(u32(I), u32(J)));
+ let w = fn_w_W();
+ let w_str = fn_w_W_str_i();
+ let w_arr0 = fn_w_W_arr_X(array<u32, 1u>(u32(0i)));
+ let w_arr1 = fn_w_W_arr_X(array<u32, 1u>(u32(1i)));
+ let w_arrI = fn_w_W_arr_X(array<u32, 1u>(u32(I)));
+ let w_arr1_arr0 = fn_w_W_arr_arr_X_X(array<u32, 2u>(u32(1i), u32(0i)));
+ let w_arr2_arrI = fn_w_W_arr_arr_X_X(array<u32, 2u>(u32(2i), u32(I)));
+ let w_arrI_arr2 = fn_w_W_arr_arr_X_X(array<u32, 2u>(u32(I), u32(2i)));
+ let w_arrI_arrJ = fn_w_W_arr_arr_X_X(array<u32, 2u>(u32(I), u32(J)));
}
)";
@@ -2436,7 +2436,7 @@
}
fn c() {
- b_S_X(array<u32, 1u>(u32(42i)));
+ let v = b_S_X(array<u32, 1u>(u32(42i)));
}
)";
@@ -2481,7 +2481,7 @@
}
fn c() {
- b_S_X(array<u32, 1u>(u32(42i)));
+ let v = b_S_X(array<u32, 1u>(u32(42i)));
}
)";
@@ -2525,7 +2525,7 @@
}
fn c() {
- b_S_X_U_X(array<u32, 1u>(u32(42i)), array<u32, 1u>(u32(24i)));
+ let v = b_S_X_U_X(array<u32, 1u>(u32(42i)), array<u32, 1u>(u32(24i)));
}
)";
diff --git a/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc b/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
index 7766c59..d9118c1 100644
--- a/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
+++ b/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
@@ -84,7 +84,7 @@
if (!var) {
continue;
}
- auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+ auto* ptr = var->Result(0)->Type()->As<core::type::Pointer>();
if (ptr->StoreType()->Is<core::type::ExternalTexture>()) {
ReplaceVar(var);
to_remove.Push(var);
@@ -97,7 +97,7 @@
// Find function parameters that need to be replaced.
auto functions = ir.functions;
- for (auto* func : functions) {
+ for (auto& func : functions) {
for (uint32_t index = 0; index < func->Params().Length(); index++) {
auto* param = func->Params()[index];
if (param->Type()->Is<core::type::ExternalTexture>()) {
@@ -148,8 +148,8 @@
}
// Replace all uses of the old variable with the new ones.
- ReplaceUses(old_var->Result(), plane_0->Result(), plane_1->Result(),
- external_texture_params->Result());
+ ReplaceUses(old_var->Result(0), plane_0->Result(0), plane_1->Result(0),
+ external_texture_params->Result(0));
}
/// Replace an external texture function parameter.
@@ -208,11 +208,11 @@
Value* plane_1_load = nullptr;
Value* params_load = nullptr;
b.InsertBefore(load, [&] {
- plane_0_load = b.Load(plane_0)->Result();
- plane_1_load = b.Load(plane_1)->Result();
- params_load = b.Load(params)->Result();
+ plane_0_load = b.Load(plane_0)->Result(0);
+ plane_1_load = b.Load(plane_1)->Result(0);
+ params_load = b.Load(params)->Result(0);
});
- ReplaceUses(load->Result(), plane_0_load, plane_1_load, params_load);
+ ReplaceUses(load->Result(0), plane_0_load, plane_1_load, params_load);
load->Destroy();
},
[&](CoreBuiltinCall* call) {
@@ -225,14 +225,14 @@
if (coords->Type()->is_signed_integer_vector()) {
auto* convert = b.Convert(ty.vec2<u32>(), coords);
convert->InsertBefore(call);
- coords = convert->Result();
+ coords = convert->Result(0);
}
// Call the `TextureLoadExternal()` helper function.
auto* helper = b.Call(ty.vec4<f32>(), TextureLoadExternal(), plane_0,
plane_1, params, coords);
helper->InsertBefore(call);
- call->Result()->ReplaceAllUsesWith(helper->Result());
+ call->Result(0)->ReplaceAllUsesWith(helper->Result(0));
call->Destroy();
} else if (call->Func() == core::BuiltinFn::kTextureSampleBaseClampToEdge) {
// Call the `TextureSampleExternal()` helper function.
@@ -241,7 +241,7 @@
auto* helper = b.Call(ty.vec4<f32>(), TextureSampleExternal(), plane_0,
plane_1, params, sampler, coords);
helper->InsertBefore(call);
- call->Result()->ReplaceAllUsesWith(helper->Result());
+ call->Result(0)->ReplaceAllUsesWith(helper->Result(0));
call->Destroy();
} else {
TINT_ICE() << "unhandled texture_external builtin call: " << call->Func();
diff --git a/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc b/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
index 7ae0828..5e2336a 100644
--- a/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
@@ -197,7 +197,7 @@
auto* func = b.Function("foo", ty.vec2<u32>());
b.Append(func->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
auto* result = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, load);
b.Return(func, result);
mod.SetName(result, "result");
@@ -272,7 +272,7 @@
auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
func->SetParams({coords});
b.Append(func->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load, coords);
b.Return(func, result);
mod.SetName(result, "result");
@@ -416,7 +416,7 @@
auto* coords = b.FunctionParam("coords", ty.vec2<i32>());
func->SetParams({coords});
b.Append(func->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load, coords);
b.Return(func, result);
mod.SetName(result, "result");
@@ -562,7 +562,7 @@
auto* coords = b.FunctionParam("coords", ty.vec2<f32>());
func->SetParams({sampler, coords});
b.Append(func->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBaseClampToEdge, load,
sampler, coords);
b.Return(func, result);
@@ -735,7 +735,7 @@
auto* coords = b.FunctionParam("coords", ty.vec2<f32>());
bar->SetParams({sampler, coords});
b.Append(bar->Block(), [&] {
- auto* load = b.Load(var->Result());
+ auto* load = b.Load(var->Result(0));
auto* result = b.Call(ty.vec4<f32>(), foo, load, sampler, coords);
b.Return(bar, result);
mod.SetName(result, "result");
@@ -920,15 +920,15 @@
auto* coords_f = b.FunctionParam("coords", ty.vec2<f32>());
bar->SetParams({sampler, coords_f});
b.Append(bar->Block(), [&] {
- auto* load_a = b.Load(var->Result());
+ auto* load_a = b.Load(var->Result(0));
b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, load_a);
- auto* load_b = b.Load(var->Result());
+ auto* load_b = b.Load(var->Result(0));
b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBaseClampToEdge, load_b, sampler,
coords_f);
- auto* load_c = b.Load(var->Result());
+ auto* load_c = b.Load(var->Result(0));
b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBaseClampToEdge, load_c, sampler,
coords_f);
- auto* load_d = b.Load(var->Result());
+ auto* load_d = b.Load(var->Result(0));
auto* result_a = b.Call(ty.vec4<f32>(), foo, load_d, sampler, coords_f);
auto* result_b = b.Call(ty.vec4<f32>(), foo, load_d, sampler, coords_f);
b.Return(bar, b.Add(ty.vec4<f32>(), result_a, result_b));
@@ -1129,11 +1129,11 @@
auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
foo->SetParams({coords});
b.Append(foo->Block(), [&] {
- auto* load_a = b.Load(var_a->Result());
+ auto* load_a = b.Load(var_a->Result(0));
b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load_a, coords);
- auto* load_b = b.Load(var_b->Result());
+ auto* load_b = b.Load(var_b->Result(0));
b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load_b, coords);
- auto* load_c = b.Load(var_c->Result());
+ auto* load_c = b.Load(var_c->Result(0));
b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load_c, coords);
b.Return(foo);
});
diff --git a/src/tint/lang/core/ir/transform/preserve_padding.cc b/src/tint/lang/core/ir/transform/preserve_padding.cc
index 0ac5f44..c9a87e8 100644
--- a/src/tint/lang/core/ir/transform/preserve_padding.cc
+++ b/src/tint/lang/core/ir/transform/preserve_padding.cc
@@ -139,7 +139,7 @@
auto* el_ptr =
b.Access(ty.ptr(storage, arr->ElemType()), target, idx);
auto* el_value = b.Access(arr->ElemType(), value_param, idx);
- MakeStore(el_ptr->Result(), el_value->Result());
+ MakeStore(el_ptr->Result(0), el_value->Result(0));
});
},
[&](const type::Matrix* mat) {
@@ -147,7 +147,7 @@
auto* col_ptr =
b.Access(ty.ptr(storage, mat->ColumnType()), target, u32(i));
auto* col_value = b.Access(mat->ColumnType(), value_param, u32(i));
- MakeStore(col_ptr->Result(), col_value->Result());
+ MakeStore(col_ptr->Result(0), col_value->Result(0));
}
},
[&](const type::Struct* str) {
@@ -156,7 +156,7 @@
u32(member->Index()));
auto* sub_value =
b.Access(member->Type(), value_param, u32(member->Index()));
- MakeStore(sub_ptr->Result(), sub_value->Result());
+ MakeStore(sub_ptr->Result(0), sub_value->Result(0));
}
});
diff --git a/src/tint/lang/core/ir/transform/robustness.cc b/src/tint/lang/core/ir/transform/robustness.cc
index e0e4839..25d9d1e 100644
--- a/src/tint/lang/core/ir/transform/robustness.cc
+++ b/src/tint/lang/core/ir/transform/robustness.cc
@@ -186,7 +186,7 @@
if (auto* vec = value->Type()->As<type::Vector>()) {
type = ty.vec(type, vec->Width());
}
- return b.Convert(type, value)->Result();
+ return b.Convert(type, value)->Result(0);
}
/// Clamp operand @p op_idx of @p inst to ensure it is within @p limit.
@@ -205,7 +205,7 @@
const_limit->Value()->ValueAs<uint32_t>())));
} else {
// Clamp it to the dynamic limit.
- clamped_idx = b.Call(ty.u32(), core::BuiltinFn::kMin, CastToU32(idx), limit)->Result();
+ clamped_idx = b.Call(ty.u32(), core::BuiltinFn::kMin, CastToU32(idx), limit)->Result(0);
}
// Replace the index operand with the clamped version.
@@ -251,12 +251,12 @@
TINT_ASSERT_OR_RETURN_VALUE(base_ptr != nullptr, nullptr);
TINT_ASSERT_OR_RETURN_VALUE(i == 1, nullptr);
auto* arr_ptr = ty.ptr(base_ptr->AddressSpace(), arr, base_ptr->Access());
- object = b.Access(arr_ptr, object, indices[0])->Result();
+ object = b.Access(arr_ptr, object, indices[0])->Result(0);
}
// Use the `arrayLength` builtin to get the limit of a runtime-sized array.
auto* length = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, object);
- return b.Subtract(ty.u32(), length, b.Constant(1_u))->Result();
+ return b.Subtract(ty.u32(), length, b.Constant(1_u))->Result(0);
});
// If there's a dynamic limit that needs enforced, clamp the index operand.
@@ -284,7 +284,7 @@
auto* num_levels = b.Call(ty.u32(), core::BuiltinFn::kTextureNumLevels, args[0]);
auto* limit = b.Subtract(ty.u32(), num_levels, 1_u);
clamped_level =
- b.Call(ty.u32(), core::BuiltinFn::kMin, CastToU32(args[idx]), limit)->Result();
+ b.Call(ty.u32(), core::BuiltinFn::kMin, CastToU32(args[idx]), limit)->Result(0);
call->SetOperand(CoreBuiltinCall::kArgsOperandOffset + idx, clamped_level);
};
@@ -302,7 +302,7 @@
auto* limit = b.Subtract(type, dims, one);
call->SetOperand(
CoreBuiltinCall::kArgsOperandOffset + idx,
- b.Call(type, core::BuiltinFn::kMin, CastToU32(args[idx]), limit)->Result());
+ b.Call(type, core::BuiltinFn::kMin, CastToU32(args[idx]), limit)->Result(0));
};
// Helper for clamping the array index.
@@ -311,7 +311,7 @@
auto* limit = b.Subtract(ty.u32(), num_layers, 1_u);
call->SetOperand(
CoreBuiltinCall::kArgsOperandOffset + idx,
- b.Call(ty.u32(), core::BuiltinFn::kMin, CastToU32(args[idx]), limit)->Result());
+ b.Call(ty.u32(), core::BuiltinFn::kMin, CastToU32(args[idx]), limit)->Result(0));
};
// Select which arguments to clamp based on the function overload.
diff --git a/src/tint/lang/core/ir/transform/shader_io.cc b/src/tint/lang/core/ir/transform/shader_io.cc
index 6e5f8a1..ce24b54 100644
--- a/src/tint/lang/core/ir/transform/shader_io.cc
+++ b/src/tint/lang/core/ir/transform/shader_io.cc
@@ -152,7 +152,7 @@
// Call the original function, passing it the inputs and capturing its return value.
auto inner_call_args = BuildInnerCallArgs(wrapper);
auto* inner_result = wrapper.Call(func->ReturnType(), func, std::move(inner_call_args));
- SetOutputs(wrapper, inner_result->Result());
+ SetOutputs(wrapper, inner_result->Result(0));
if (vertex_point_size_index) {
backend->SetOutput(wrapper, vertex_point_size_index.value(), b.Constant(1_f));
}
@@ -245,7 +245,7 @@
for (uint32_t i = 0; i < str->Members().Length(); i++) {
construct_args.Push(backend->GetInput(builder, input_idx++));
}
- args.Push(builder.Construct(param->Type(), construct_args)->Result());
+ args.Push(builder.Construct(param->Type(), construct_args)->Result(0));
} else {
args.Push(backend->GetInput(builder, input_idx++));
}
@@ -261,7 +261,7 @@
if (auto* str = inner_result->Type()->As<core::type::Struct>()) {
for (auto* member : str->Members()) {
Value* from =
- builder.Access(member->Type(), inner_result, u32(member->Index()))->Result();
+ builder.Access(member->Type(), inner_result, u32(member->Index()))->Result(0);
backend->SetOutput(builder, member->Index(), from);
}
} else if (!inner_result->Type()->Is<core::type::Void>()) {
@@ -286,7 +286,7 @@
// Take a copy of the function list since the transform will add new functions to the module.
auto functions = module.functions;
- for (auto* func : functions) {
+ for (auto& func : functions) {
// Only process entry points.
if (func->Stage() == Function::PipelineStage::kUndefined) {
continue;
diff --git a/src/tint/lang/core/ir/transform/std140.cc b/src/tint/lang/core/ir/transform/std140.cc
index 0f2b8f6..85a2036 100644
--- a/src/tint/lang/core/ir/transform/std140.cc
+++ b/src/tint/lang/core/ir/transform/std140.cc
@@ -79,7 +79,7 @@
if (!var || !var->Alive()) {
continue;
}
- auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+ auto* ptr = var->Result(0)->Type()->As<core::type::Pointer>();
if (!ptr || ptr->AddressSpace() != core::AddressSpace::kUniform) {
continue;
}
@@ -93,16 +93,16 @@
for (auto* var : buffer_variables) {
// Create a new variable with the modified store type.
const auto& bp = var->BindingPoint();
- auto* store_type = var->Result()->Type()->As<core::type::Pointer>()->StoreType();
+ auto* store_type = var->Result(0)->Type()->As<core::type::Pointer>()->StoreType();
auto* new_var = b.Var(ty.ptr(uniform, RewriteType(store_type)));
new_var->SetBindingPoint(bp->group, bp->binding);
if (auto name = ir.NameOf(var)) {
- ir.SetName(new_var->Result(), name);
+ ir.SetName(new_var->Result(0), name);
}
// Replace every instruction that uses the original variable.
- var->Result()->ForEachUse(
- [&](Usage use) { Replace(use.instruction, new_var->Result()); });
+ var->Result(0)->ForEachUse(
+ [&](Usage use) { Replace(use.instruction, new_var->Result(0)); });
// Replace the original variable with the new variable.
var->ReplaceWith(new_var);
@@ -201,9 +201,9 @@
for (uint32_t i = 0; i < mat->columns(); i++) {
indices.Back() = b.Constant(u32(first_column + i));
auto* access = b.Access(ty.ptr(uniform, mat->ColumnType()), root, indices);
- args.Push(b.Load(access->Result())->Result());
+ args.Push(b.Load(access->Result(0))->Result(0));
}
- return b.Construct(mat, std::move(args))->Result();
+ return b.Construct(mat, std::move(args))->Result(0);
}
/// Convert a value that may contain decomposed matrices to a value with the original type.
@@ -234,15 +234,15 @@
Vector<Value*, 4> columns;
for (uint32_t i = 0; i < mat->columns(); i++) {
auto* extract = b.Access(mat->ColumnType(), input, u32(index));
- columns.Push(extract->Result());
+ columns.Push(extract->Result(0));
index++;
}
- args.Push(b.Construct(mat, std::move(columns))->Result());
+ args.Push(b.Construct(mat, std::move(columns))->Result(0));
} else {
// Extract and convert the member.
auto* type = input_str->Element(index);
auto* extract = b.Access(type, input, u32(index));
- args.Push(Convert(extract->Result(), member->Type()));
+ args.Push(Convert(extract->Result(0), member->Type()));
index++;
}
}
@@ -254,7 +254,7 @@
});
// Call the helper function to convert the struct.
- return b.Call(str, helper, source)->Result();
+ return b.Call(str, helper, source)->Result(0);
},
[&](const core::type::Array* arr) -> Value* {
// Create a loop that copies and converts each element of the array.
@@ -263,10 +263,10 @@
b.LoopRange(ty, 0_u, u32(arr->ConstantCount().value()), 1_u, [&](Value* idx) {
// Convert arr[idx] and store to new_arr[idx];
auto* to = b.Access(ty.ptr(function, arr->ElemType()), new_arr, idx);
- auto* from = b.Access(el_ty, source, idx)->Result();
+ auto* from = b.Access(el_ty, source, idx)->Result(0);
b.Store(to, Convert(from, arr->ElemType()));
});
- return b.Load(new_arr)->Result();
+ return b.Load(new_arr)->Result(0);
},
[&](Default) { return source; });
}
@@ -309,37 +309,43 @@
current_type = ty.ptr(uniform, RewriteType(current_type));
}
auto* new_access = b.Access(current_type, replacement, std::move(indices));
- replacement = new_access->Result();
+ replacement = new_access->Result(0);
}
// Replace every instruction that uses the original access instruction.
- access->Result()->ForEachUse(
+ access->Result(0)->ForEachUse(
[&](Usage use) { Replace(use.instruction, replacement); });
access->Destroy();
},
[&](Load* load) {
if (!replacement->Type()->Is<core::type::Pointer>()) {
// We have already loaded to a value type, so this load just folds away.
- load->Result()->ReplaceAllUsesWith(replacement);
+ load->Result(0)->ReplaceAllUsesWith(replacement);
} else {
// Load the decomposed value and then convert it to the original type.
auto* decomposed = b.Load(replacement);
- auto* converted = Convert(decomposed->Result(), load->Result()->Type());
- load->Result()->ReplaceAllUsesWith(converted);
+ auto* converted = Convert(decomposed->Result(0), load->Result(0)->Type());
+ load->Result(0)->ReplaceAllUsesWith(converted);
}
load->Destroy();
},
[&](LoadVectorElement* load) {
- // We should have loaded the decomposed matrix, reconstructed it, so this is now
- // extracting from a value type.
- TINT_ASSERT(!replacement->Type()->Is<core::type::Pointer>());
- auto* access = b.Access(load->Result()->Type(), replacement, load->Index());
- load->Result()->ReplaceAllUsesWith(access->Result());
- load->Destroy();
+ if (!replacement->Type()->Is<core::type::Pointer>()) {
+ // We have loaded a decomposed matrix and reconstructed it, so this is now
+ // extracting from a value type.
+ auto* access =
+ b.Access(load->Result(0)->Type(), replacement, load->Index());
+ load->Result(0)->ReplaceAllUsesWith(access->Result(0));
+ load->Destroy();
+ } else {
+ // There was no decomposed matrix on the path to this instruction so just
+ // update the source operand.
+ load->SetOperand(LoadVectorElement::kFromOperandOffset, replacement);
+ }
},
[&](Let* let) {
// Let instructions just fold away.
- let->Result()->ForEachUse(
+ let->Result(0)->ForEachUse(
[&](Usage use) { Replace(use.instruction, replacement); });
let->Destroy();
});
diff --git a/src/tint/lang/core/ir/transform/std140_test.cc b/src/tint/lang/core/ir/transform/std140_test.cc
index 8415529..105f2cd 100644
--- a/src/tint/lang/core/ir/transform/std140_test.cc
+++ b/src/tint/lang/core/ir/transform/std140_test.cc
@@ -1483,6 +1483,283 @@
EXPECT_EQ(expect, str());
}
+TEST_F(IR_Std140Test, NotAllMatricesDecomposed) {
+ auto* mat4x4 = ty.mat4x4<f32>();
+ auto* mat3x2 = ty.mat3x2<f32>();
+ auto* structure = ty.Struct(mod.symbols.New("MyStruct"), {
+ {mod.symbols.New("a"), mat4x4},
+ {mod.symbols.New("b"), mat3x2},
+ });
+ structure->SetStructFlag(core::type::kBlock);
+
+ auto* buffer = b.Var("buffer", ty.ptr(uniform, structure));
+ buffer->SetBindingPoint(0, 0);
+ mod.root_block->Append(buffer);
+
+ {
+ auto* func = b.Function("load_struct_a", mat4x4);
+ b.Append(func->Block(), [&] {
+ auto* load_struct = b.Load(buffer);
+ auto* extract_mat = b.Access(mat4x4, load_struct, 0_u);
+ b.Return(func, extract_mat);
+ });
+ }
+
+ {
+ auto* func = b.Function("load_struct_b", mat3x2);
+ b.Append(func->Block(), [&] {
+ auto* load_struct = b.Load(buffer);
+ auto* extract_mat = b.Access(mat3x2, load_struct, 1_u);
+ b.Return(func, extract_mat);
+ });
+ }
+
+ {
+ auto* func = b.Function("load_mat_a", ty.vec4<f32>());
+ b.Append(func->Block(), [&] {
+ auto* access_mat = b.Access(ty.ptr(uniform, mat4x4), buffer, 0_u);
+ auto* load_mat = b.Load(access_mat);
+ auto* extract_vec = b.Access(ty.vec4<f32>(), load_mat, 0_u);
+ b.Return(func, extract_vec);
+ });
+ }
+
+ {
+ auto* func = b.Function("load_mat_b", ty.vec2<f32>());
+ b.Append(func->Block(), [&] {
+ auto* access_mat = b.Access(ty.ptr(uniform, mat3x2), buffer, 1_u);
+ auto* load_mat = b.Load(access_mat);
+ auto* extract_vec = b.Access(ty.vec2<f32>(), load_mat, 0_u);
+ b.Return(func, extract_vec);
+ });
+ }
+
+ {
+ auto* func = b.Function("load_vec_a", ty.f32());
+ b.Append(func->Block(), [&] {
+ auto* access_vec = b.Access(ty.ptr(uniform, mat4x4->ColumnType()), buffer, 0_u, 1_u);
+ auto* load_vec = b.Load(access_vec);
+ auto* extract_el = b.Access(ty.f32(), load_vec, 1_u);
+ b.Return(func, extract_el);
+ });
+ }
+
+ {
+ auto* func = b.Function("load_vec_b", ty.f32());
+ b.Append(func->Block(), [&] {
+ auto* access_vec = b.Access(ty.ptr(uniform, mat3x2->ColumnType()), buffer, 1_u, 1_u);
+ auto* load_vec = b.Load(access_vec);
+ auto* extract_el = b.Access(ty.f32(), load_vec, 1_u);
+ b.Return(func, extract_el);
+ });
+ }
+
+ {
+ auto* func = b.Function("lve_a", ty.f32());
+ b.Append(func->Block(), [&] {
+ auto* access_vec = b.Access(ty.ptr(uniform, mat4x4->ColumnType()), buffer, 0_u, 1_u);
+ auto* lve = b.LoadVectorElement(access_vec, 1_u);
+ b.Return(func, lve);
+ });
+ }
+
+ {
+ auto* func = b.Function("lve_b", ty.f32());
+ b.Append(func->Block(), [&] {
+ auto* access_vec = b.Access(ty.ptr(uniform, mat3x2->ColumnType()), buffer, 1_u, 1_u);
+ auto* lve = b.LoadVectorElement(access_vec, 1_u);
+ b.Return(func, lve);
+ });
+ }
+
+ auto* src = R"(
+MyStruct = struct @align(16), @block {
+ a:mat4x4<f32> @offset(0)
+ b:mat3x2<f32> @offset(64)
+}
+
+%b1 = block { # root
+ %buffer:ptr<uniform, MyStruct, read_write> = var @binding_point(0, 0)
+}
+
+%load_struct_a = func():mat4x4<f32> -> %b2 {
+ %b2 = block {
+ %3:MyStruct = load %buffer
+ %4:mat4x4<f32> = access %3, 0u
+ ret %4
+ }
+}
+%load_struct_b = func():mat3x2<f32> -> %b3 {
+ %b3 = block {
+ %6:MyStruct = load %buffer
+ %7:mat3x2<f32> = access %6, 1u
+ ret %7
+ }
+}
+%load_mat_a = func():vec4<f32> -> %b4 {
+ %b4 = block {
+ %9:ptr<uniform, mat4x4<f32>, read_write> = access %buffer, 0u
+ %10:mat4x4<f32> = load %9
+ %11:vec4<f32> = access %10, 0u
+ ret %11
+ }
+}
+%load_mat_b = func():vec2<f32> -> %b5 {
+ %b5 = block {
+ %13:ptr<uniform, mat3x2<f32>, read_write> = access %buffer, 1u
+ %14:mat3x2<f32> = load %13
+ %15:vec2<f32> = access %14, 0u
+ ret %15
+ }
+}
+%load_vec_a = func():f32 -> %b6 {
+ %b6 = block {
+ %17:ptr<uniform, vec4<f32>, read_write> = access %buffer, 0u, 1u
+ %18:vec4<f32> = load %17
+ %19:f32 = access %18, 1u
+ ret %19
+ }
+}
+%load_vec_b = func():f32 -> %b7 {
+ %b7 = block {
+ %21:ptr<uniform, vec2<f32>, read_write> = access %buffer, 1u, 1u
+ %22:vec2<f32> = load %21
+ %23:f32 = access %22, 1u
+ ret %23
+ }
+}
+%lve_a = func():f32 -> %b8 {
+ %b8 = block {
+ %25:ptr<uniform, vec4<f32>, read_write> = access %buffer, 0u, 1u
+ %26:f32 = load_vector_element %25, 1u
+ ret %26
+ }
+}
+%lve_b = func():f32 -> %b9 {
+ %b9 = block {
+ %28:ptr<uniform, vec2<f32>, read_write> = access %buffer, 1u, 1u
+ %29:f32 = load_vector_element %28, 1u
+ ret %29
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+MyStruct = struct @align(16), @block {
+ a:mat4x4<f32> @offset(0)
+ b:mat3x2<f32> @offset(64)
+}
+
+MyStruct_std140 = struct @align(16), @block {
+ a:mat4x4<f32> @offset(0)
+ b_col0:vec2<f32> @offset(64)
+ b_col1:vec2<f32> @offset(72)
+ b_col2:vec2<f32> @offset(80)
+}
+
+%b1 = block { # root
+ %buffer:ptr<uniform, MyStruct_std140, read_write> = var @binding_point(0, 0)
+}
+
+%load_struct_a = func():mat4x4<f32> -> %b2 {
+ %b2 = block {
+ %3:MyStruct_std140 = load %buffer
+ %4:MyStruct = call %convert_MyStruct, %3
+ %6:mat4x4<f32> = access %4, 0u
+ ret %6
+ }
+}
+%load_struct_b = func():mat3x2<f32> -> %b3 {
+ %b3 = block {
+ %8:MyStruct_std140 = load %buffer
+ %9:MyStruct = call %convert_MyStruct, %8
+ %10:mat3x2<f32> = access %9, 1u
+ ret %10
+ }
+}
+%load_mat_a = func():vec4<f32> -> %b4 {
+ %b4 = block {
+ %12:ptr<uniform, mat4x4<f32>, read_write> = access %buffer, 0u
+ %13:mat4x4<f32> = load %12
+ %14:vec4<f32> = access %13, 0u
+ ret %14
+ }
+}
+%load_mat_b = func():vec2<f32> -> %b5 {
+ %b5 = block {
+ %16:ptr<uniform, vec2<f32>, read_write> = access %buffer, 1u
+ %17:vec2<f32> = load %16
+ %18:ptr<uniform, vec2<f32>, read_write> = access %buffer, 2u
+ %19:vec2<f32> = load %18
+ %20:ptr<uniform, vec2<f32>, read_write> = access %buffer, 3u
+ %21:vec2<f32> = load %20
+ %22:mat3x2<f32> = construct %17, %19, %21
+ %23:vec2<f32> = access %22, 0u
+ ret %23
+ }
+}
+%load_vec_a = func():f32 -> %b6 {
+ %b6 = block {
+ %25:ptr<uniform, vec4<f32>, read_write> = access %buffer, 0u, 1u
+ %26:vec4<f32> = load %25
+ %27:f32 = access %26, 1u
+ ret %27
+ }
+}
+%load_vec_b = func():f32 -> %b7 {
+ %b7 = block {
+ %29:ptr<uniform, vec2<f32>, read_write> = access %buffer, 1u
+ %30:vec2<f32> = load %29
+ %31:ptr<uniform, vec2<f32>, read_write> = access %buffer, 2u
+ %32:vec2<f32> = load %31
+ %33:ptr<uniform, vec2<f32>, read_write> = access %buffer, 3u
+ %34:vec2<f32> = load %33
+ %35:mat3x2<f32> = construct %30, %32, %34
+ %36:vec2<f32> = access %35, 1u
+ %37:f32 = access %36, 1u
+ ret %37
+ }
+}
+%lve_a = func():f32 -> %b8 {
+ %b8 = block {
+ %39:ptr<uniform, vec4<f32>, read_write> = access %buffer, 0u, 1u
+ %40:f32 = load_vector_element %39, 1u
+ ret %40
+ }
+}
+%lve_b = func():f32 -> %b9 {
+ %b9 = block {
+ %42:ptr<uniform, vec2<f32>, read_write> = access %buffer, 1u
+ %43:vec2<f32> = load %42
+ %44:ptr<uniform, vec2<f32>, read_write> = access %buffer, 2u
+ %45:vec2<f32> = load %44
+ %46:ptr<uniform, vec2<f32>, read_write> = access %buffer, 3u
+ %47:vec2<f32> = load %46
+ %48:mat3x2<f32> = construct %43, %45, %47
+ %49:vec2<f32> = access %48, 1u
+ %50:f32 = access %49, 1u
+ ret %50
+ }
+}
+%convert_MyStruct = func(%input:MyStruct_std140):MyStruct -> %b10 {
+ %b10 = block {
+ %52:mat4x4<f32> = access %input, 0u
+ %53:vec2<f32> = access %input, 1u
+ %54:vec2<f32> = access %input, 2u
+ %55:vec2<f32> = access %input, 3u
+ %56:mat3x2<f32> = construct %53, %54, %55
+ %57:MyStruct = construct %52, %56
+ ret %57
+ }
+}
+)";
+
+ Run(Std140);
+
+ EXPECT_EQ(expect, str());
+}
+
TEST_F(IR_Std140Test, F16) {
auto* structure =
ty.Struct(mod.symbols.New("MyStruct"), {
diff --git a/src/tint/lang/core/ir/transform/value_to_let.cc b/src/tint/lang/core/ir/transform/value_to_let.cc
new file mode 100644
index 0000000..7580900
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/value_to_let.cc
@@ -0,0 +1,186 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/core/ir/transform/value_to_let.h"
+
+#include "src/tint/lang/core/ir/builder.h"
+#include "src/tint/lang/core/ir/validator.h"
+
+using namespace tint::core::fluent_types; // NOLINT
+using namespace tint::core::number_suffixes; // NOLINT
+
+namespace tint::core::ir::transform {
+
+namespace {
+
+/// Access is an enumerator of memory access operations
+enum class Access : uint8_t { kLoad, kStore };
+/// Accesses is a set of of Access
+using Accesses = EnumSet<Access>;
+
+/// @returns the accesses that may be performed by the instruction @p inst
+Accesses AccessesFor(ir::Instruction* inst) {
+ return tint::Switch<Accesses>(
+ inst, //
+ [&](const ir::Load*) { return Access::kLoad; }, //
+ [&](const ir::LoadVectorElement*) { return Access::kLoad; }, //
+ [&](const ir::Store*) { return Access::kStore; }, //
+ [&](const ir::StoreVectorElement*) { return Access::kStore; }, //
+ [&](const ir::Call*) {
+ return Accesses{Access::kLoad, Access::kStore};
+ },
+ [&](Default) { return Accesses{}; });
+}
+
+/// PIMPL state for the transform.
+struct State {
+ /// The IR module.
+ Module& ir;
+
+ /// The IR builder.
+ Builder b{ir};
+
+ /// The type manager.
+ core::type::Manager& ty{ir.Types()};
+
+ /// Process the module.
+ void Process() {
+ // Process each block.
+ for (auto* block : ir.blocks.Objects()) {
+ Process(block);
+ }
+ }
+
+ private:
+ void Process(ir::Block* block) {
+ // A set of possibly-inlinable values returned by a instructions that has not yet been
+ // marked-for or ruled-out-for inlining.
+ Hashset<ir::InstructionResult*, 32> pending_resolution;
+ // The accesses of the values in pending_resolution.
+ Access pending_access = Access::kLoad;
+
+ auto put_pending_in_lets = [&] {
+ for (auto* pending : pending_resolution) {
+ PutInLet(pending);
+ }
+ pending_resolution.Clear();
+ };
+
+ auto maybe_put_in_let = [&](auto* inst) {
+ if (auto* result = inst->Result(0)) {
+ auto& usages = result->Usages();
+ switch (usages.Count()) {
+ case 0: // No usage
+ break;
+ case 1: { // Single usage
+ auto* usage = (*usages.begin()).instruction;
+ if (usage->Block() == inst->Block()) {
+ // Usage in same block. Assign to pending_resolution, as we don't
+ // know whether its safe to inline yet.
+ pending_resolution.Add(result);
+ } else {
+ // Usage from another block. Cannot inline.
+ inst = PutInLet(result);
+ }
+ break;
+ }
+ default: // Value has multiple usages. Cannot inline.
+ inst = PutInLet(result);
+ break;
+ }
+ }
+ };
+
+ for (ir::Instruction* inst = block->Front(); inst; inst = inst->next) {
+ // This transform assumes that all multi-result instructions have been replaced
+ TINT_ASSERT(inst->Results().Length() < 2);
+
+ // The memory accesses of this instruction
+ auto accesses = AccessesFor(inst);
+
+ for (auto* operand : inst->Operands()) {
+ // If the operand is in pending_resolution, then we know it has a single use and
+ // because it hasn't been removed with put_pending_in_lets(), we know its safe to
+ // inline without breaking access ordering. By inlining the operand, we are pulling
+ // the operand's instruction into the same statement as this instruction, so this
+ // instruction adopts the access of the operand.
+ if (auto* result = As<InstructionResult>(operand)) {
+ if (pending_resolution.Remove(result)) {
+ // Var and Let are always statements, and so can never be inlined. As such,
+ // they do not need to propagate the pending resolution through them.
+ if (!inst->IsAnyOf<Var, Let>()) {
+ accesses.Add(pending_access);
+ }
+ }
+ }
+ }
+
+ if (accesses.Contains(Access::kStore)) { // Note: Also handles load + store
+ put_pending_in_lets();
+ maybe_put_in_let(inst);
+ } else if (accesses.Contains(Access::kLoad)) {
+ if (pending_access != Access::kLoad) {
+ put_pending_in_lets();
+ pending_access = Access::kLoad;
+ }
+ maybe_put_in_let(inst);
+ }
+ }
+ }
+
+ /// PutInLet places the value into a new 'let' instruction, immediately after the value's
+ /// instruction
+ /// @param value the value to place into the 'let'
+ /// @return the created 'let' instruction.
+ ir::Let* PutInLet(ir::InstructionResult* value) {
+ auto* inst = value->Instruction();
+ auto* let = b.Let(value->Type());
+ value->ReplaceAllUsesWith(let->Result(0));
+ let->SetValue(value);
+ let->InsertAfter(inst);
+ if (auto name = b.ir.NameOf(value); name.IsValid()) {
+ b.ir.SetName(let->Result(0), name);
+ b.ir.ClearName(value);
+ }
+ return let;
+ }
+};
+
+} // namespace
+
+Result<SuccessType> ValueToLet(Module& ir) {
+ auto result = ValidateAndDumpIfNeeded(ir, "ValueToLet transform");
+ if (!result) {
+ return result;
+ }
+
+ State{ir}.Process();
+
+ return Success;
+}
+
+} // namespace tint::core::ir::transform
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/lang/core/ir/transform/value_to_let.h
similarity index 66%
copy from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
copy to src/tint/lang/core/ir/transform/value_to_let.h
index 6f0f657..895bc09 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/lang/core/ir/transform/value_to_let.h
@@ -25,12 +25,9 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
-#define SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#ifndef SRC_TINT_LANG_CORE_IR_TRANSFORM_VALUE_TO_LET_H_
+#define SRC_TINT_LANG_CORE_IR_TRANSFORM_VALUE_TO_LET_H_
-#include <string>
-
-#include "src/tint/utils/diagnostic/diagnostic.h"
#include "src/tint/utils/result/result.h"
// Forward declarations.
@@ -38,15 +35,20 @@
class Module;
}
-namespace tint::wgsl::writer {
+namespace tint::core::ir::transform {
-/// RenameConflicts is a transform that renames declarations which prevent identifiers from
-/// resolving to the correct declaration, and those with identical identifiers declared in the same
-/// scope.
+/// ValueToLet is a transform that moves "non-inlinable" instruction values to let instructions.
+/// An expression is considered "non-inlinable" if any of the the following are true:
+/// * The value has multiple uses.
+/// * The value's instruction is a load that when inlined would cross a store instruction.
+/// * The value's instruction is a store instruction that when inlined would cross a load or store
+/// instruction.
+/// * The value is used in a block different to the value's instruction.
+///
/// @param module the module to transform
-/// @returns success or failure
-Result<SuccessType> RenameConflicts(core::ir::Module* module);
+/// @returns error diagnostics on failure
+Result<SuccessType> ValueToLet(Module& module);
-} // namespace tint::wgsl::writer
+} // namespace tint::core::ir::transform
-#endif // SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#endif // SRC_TINT_LANG_CORE_IR_TRANSFORM_VALUE_TO_LET_H_
diff --git a/src/tint/lang/core/ir/transform/value_to_let_test.cc b/src/tint/lang/core/ir/transform/value_to_let_test.cc
new file mode 100644
index 0000000..91e04d9
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/value_to_let_test.cc
@@ -0,0 +1,637 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/core/ir/transform/value_to_let.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/ir/transform/helper_test.h"
+
+namespace tint::core::ir::transform {
+namespace {
+
+using namespace tint::core::fluent_types; // NOLINT
+using namespace tint::core::number_suffixes; // NOLINT
+
+using IR_ValueToLetTest = TransformTest;
+
+TEST_F(IR_ValueToLetTest, Empty) {
+ auto* expect = R"(
+)";
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ValueToLetTest, NoModify_Blah) {
+ auto* func = b.Function("F", ty.void_());
+ b.Append(func->Block(), [&] { b.Return(func); });
+
+ auto* src = R"(
+%F = func():void -> %b1 {
+ %b1 = block {
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ValueToLetTest, NoModify_Unsequenced) {
+ auto* fn = b.Function("F", ty.i32());
+ b.Append(fn->Block(), [&] {
+ auto* x = b.Let("x", 1_i);
+ auto* y = b.Let("y", 2_i);
+ auto* z = b.Let("z", b.Add<i32>(x, y));
+ b.Return(fn, z);
+ });
+
+ auto* src = R"(
+%F = func():i32 -> %b1 {
+ %b1 = block {
+ %x:i32 = let 1i
+ %y:i32 = let 2i
+ %4:i32 = add %x, %y
+ %z:i32 = let %4
+ ret %z
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+}
+TEST_F(IR_ValueToLetTest, NoModify_SequencedValueUsedWithNonSequenced) {
+ auto* i = b.Var<private_, i32>("i");
+ b.ir.root_block->Append(i);
+
+ auto* p = b.FunctionParam<i32>("p");
+ auto* rmw = b.Function("rmw", ty.i32());
+ rmw->SetParams({p});
+ b.Append(rmw->Block(), [&] {
+ auto* v = b.Let("v", b.Add<i32>(b.Load(i), p));
+ b.Store(i, v);
+ b.Return(rmw, v);
+ });
+
+ auto* fn = b.Function("F", ty.i32());
+ b.Append(fn->Block(), [&] {
+ auto* x = b.Name("x", b.Call(rmw, 1_i));
+ // select is called with one, inlinable sequenced operand and two non-sequenced values.
+ auto* y = b.Name("y", b.Call<i32>(core::BuiltinFn::kSelect, 2_i, x, false));
+ b.Return(fn, y);
+ });
+
+ auto* src = R"(
+%b1 = block { # root
+ %i:ptr<private, i32, read_write> = var
+}
+
+%rmw = func(%p:i32):i32 -> %b2 {
+ %b2 = block {
+ %4:i32 = load %i
+ %5:i32 = add %4, %p
+ %v:i32 = let %5
+ store %i, %v
+ ret %v
+ }
+}
+%F = func():i32 -> %b3 {
+ %b3 = block {
+ %x:i32 = call %rmw, 1i
+ %y:i32 = select 2i, %x, false
+ ret %y
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ValueToLetTest, NoModify_Inlinable_NestedCalls) {
+ auto* i = b.Var<private_, i32>("i");
+ b.ir.root_block->Append(i);
+
+ auto* p = b.FunctionParam<i32>("p");
+ auto* rmw = b.Function("rmw", ty.i32());
+ rmw->SetParams({p});
+ b.Append(rmw->Block(), [&] {
+ auto* v = b.Let("v", b.Add<i32>(b.Load(i), p));
+ b.Store(i, v);
+ b.Return(rmw, v);
+ });
+
+ auto* fn = b.Function("F", ty.i32());
+ b.Append(fn->Block(), [&] {
+ auto* x = b.Name("x", b.Call(rmw, 1_i));
+ auto* y = b.Name("y", b.Call(rmw, x));
+ auto* z = b.Name("z", b.Call(rmw, y));
+ b.Return(fn, z);
+ });
+
+ auto* src = R"(
+%b1 = block { # root
+ %i:ptr<private, i32, read_write> = var
+}
+
+%rmw = func(%p:i32):i32 -> %b2 {
+ %b2 = block {
+ %4:i32 = load %i
+ %5:i32 = add %4, %p
+ %v:i32 = let %5
+ store %i, %v
+ ret %v
+ }
+}
+%F = func():i32 -> %b3 {
+ %b3 = block {
+ %x:i32 = call %rmw, 1i
+ %y:i32 = call %rmw, %x
+ %z:i32 = call %rmw, %y
+ ret %z
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ValueToLetTest, NoModify_LetUsedTwice) {
+ auto* i = b.Var<private_, i32>("i");
+ b.ir.root_block->Append(i);
+
+ auto* p = b.FunctionParam<i32>("p");
+ auto* rmw = b.Function("rmw", ty.i32());
+ rmw->SetParams({p});
+ b.Append(rmw->Block(), [&] {
+ auto* v = b.Let("v", b.Add<i32>(b.Load(i), p));
+ b.Store(i, v);
+ b.Return(rmw, v);
+ });
+
+ auto* fn = b.Function("F", ty.i32());
+ b.Append(fn->Block(), [&] {
+ // No need to create more lets, as these are already in lets
+ auto* x = b.Let("x", b.Call(rmw, 1_i));
+ auto* y = b.Name("y", b.Add<i32>(x, x));
+ b.Return(fn, y);
+ });
+
+ auto* src = R"(
+%b1 = block { # root
+ %i:ptr<private, i32, read_write> = var
+}
+
+%rmw = func(%p:i32):i32 -> %b2 {
+ %b2 = block {
+ %4:i32 = load %i
+ %5:i32 = add %4, %p
+ %v:i32 = let %5
+ store %i, %v
+ ret %v
+ }
+}
+%F = func():i32 -> %b3 {
+ %b3 = block {
+ %8:i32 = call %rmw, 1i
+ %x:i32 = let %8
+ %y:i32 = add %x, %x
+ ret %y
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ValueToLetTest, NoModify_VarUsedTwice) {
+ auto* p = b.FunctionParam<ptr<function, i32, read_write>>("p");
+ auto* fn_g = b.Function("g", ty.i32());
+ fn_g->SetParams({p});
+ b.Append(fn_g->Block(), [&] { b.Return(fn_g, b.Load(p)); });
+
+ auto* fn = b.Function("F", ty.i32());
+ b.Append(fn->Block(), [&] {
+ auto* v = b.Var<function, i32>("v");
+ auto* x = b.Let("x", b.Call(fn_g, v));
+ auto* y = b.Let("y", b.Call(fn_g, v));
+ b.Return(fn, b.Add<i32>(x, y));
+ });
+
+ auto* src = R"(
+%g = func(%p:ptr<function, i32, read_write>):i32 -> %b1 {
+ %b1 = block {
+ %3:i32 = load %p
+ ret %3
+ }
+}
+%F = func():i32 -> %b2 {
+ %b2 = block {
+ %v:ptr<function, i32, read_write> = var
+ %6:i32 = call %g, %v
+ %x:i32 = let %6
+ %8:i32 = call %g, %v
+ %y:i32 = let %8
+ %10:i32 = add %x, %y
+ ret %10
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ValueToLetTest, VarLoadUsedTwice) {
+ auto* fn = b.Function("F", ty.i32());
+ b.Append(fn->Block(), [&] {
+ auto* v = b.Var<function, i32>("v");
+ auto* l = b.Name("l", b.Load(v));
+ b.Return(fn, b.Add<i32>(l, l));
+ });
+
+ auto* src = R"(
+%F = func():i32 -> %b1 {
+ %b1 = block {
+ %v:ptr<function, i32, read_write> = var
+ %l:i32 = load %v
+ %4:i32 = add %l, %l
+ ret %4
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%F = func():i32 -> %b1 {
+ %b1 = block {
+ %v:ptr<function, i32, read_write> = var
+ %3:i32 = load %v
+ %l:i32 = let %3
+ %5:i32 = add %l, %l
+ ret %5
+ }
+}
+)";
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ValueToLetTest, VarLoad_ThenStore_ThenUse) {
+ auto* fn = b.Function("F", ty.i32());
+ b.Append(fn->Block(), [&] {
+ auto* v = b.Var<function, i32>("v");
+ auto* l = b.Name("l", b.Load(v));
+ b.Store(v, 1_i);
+ b.Return(fn, l);
+ });
+
+ auto* src = R"(
+%F = func():i32 -> %b1 {
+ %b1 = block {
+ %v:ptr<function, i32, read_write> = var
+ %l:i32 = load %v
+ store %v, 1i
+ ret %l
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%F = func():i32 -> %b1 {
+ %b1 = block {
+ %v:ptr<function, i32, read_write> = var
+ %3:i32 = load %v
+ %l:i32 = let %3
+ store %v, 1i
+ ret %l
+ }
+}
+)";
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ValueToLetTest, TwoCalls_ThenUseReturnValues) {
+ auto* i = b.Var<private_, i32>("i");
+ b.ir.root_block->Append(i);
+
+ auto* p = b.FunctionParam<i32>("p");
+ auto* rmw = b.Function("rmw", ty.i32());
+ rmw->SetParams({p});
+ b.Append(rmw->Block(), [&] {
+ auto* v = b.Let("v", b.Add<i32>(b.Load(i), p));
+ b.Store(i, v);
+ b.Return(rmw, v);
+ });
+
+ auto* fn = b.Function("F", ty.i32());
+ b.Append(fn->Block(), [&] {
+ auto* x = b.Name("x", b.Call(rmw, 1_i));
+ auto* y = b.Name("y", b.Call(rmw, 2_i));
+ auto* z = b.Name("z", b.Add<i32>(x, y));
+ b.Return(fn, z);
+ });
+
+ auto* src = R"(
+%b1 = block { # root
+ %i:ptr<private, i32, read_write> = var
+}
+
+%rmw = func(%p:i32):i32 -> %b2 {
+ %b2 = block {
+ %4:i32 = load %i
+ %5:i32 = add %4, %p
+ %v:i32 = let %5
+ store %i, %v
+ ret %v
+ }
+}
+%F = func():i32 -> %b3 {
+ %b3 = block {
+ %x:i32 = call %rmw, 1i
+ %y:i32 = call %rmw, 2i
+ %z:i32 = add %x, %y
+ ret %z
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%b1 = block { # root
+ %i:ptr<private, i32, read_write> = var
+}
+
+%rmw = func(%p:i32):i32 -> %b2 {
+ %b2 = block {
+ %4:i32 = load %i
+ %5:i32 = add %4, %p
+ %v:i32 = let %5
+ store %i, %v
+ ret %v
+ }
+}
+%F = func():i32 -> %b3 {
+ %b3 = block {
+ %8:i32 = call %rmw, 1i
+ %x:i32 = let %8
+ %y:i32 = call %rmw, 2i
+ %z:i32 = add %x, %y
+ ret %z
+ }
+}
+)";
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+
+ Run(ValueToLet); // running a second time should be no-op
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ValueToLetTest, SequencedUsedInDifferentBlock) {
+ auto* i = b.Var<private_, i32>("i");
+ b.ir.root_block->Append(i);
+
+ auto* p = b.FunctionParam<i32>("p");
+ auto* rmw = b.Function("rmw", ty.i32());
+ rmw->SetParams({p});
+ b.Append(rmw->Block(), [&] {
+ auto* v = b.Let("v", b.Add<i32>(b.Load(i), p));
+ b.Store(i, v);
+ b.Return(rmw, v);
+ });
+
+ auto* fn = b.Function("F", ty.i32());
+ b.Append(fn->Block(), [&] {
+ auto* x = b.Name("x", b.Call(rmw, 1_i));
+ auto* if_ = b.If(true);
+ b.Append(if_->True(), [&] { //
+ b.Return(fn, x);
+ });
+ b.Return(fn, 2_i);
+ });
+
+ auto* src = R"(
+%b1 = block { # root
+ %i:ptr<private, i32, read_write> = var
+}
+
+%rmw = func(%p:i32):i32 -> %b2 {
+ %b2 = block {
+ %4:i32 = load %i
+ %5:i32 = add %4, %p
+ %v:i32 = let %5
+ store %i, %v
+ ret %v
+ }
+}
+%F = func():i32 -> %b3 {
+ %b3 = block {
+ %x:i32 = call %rmw, 1i
+ if true [t: %b4] { # if_1
+ %b4 = block { # true
+ ret %x
+ }
+ }
+ ret 2i
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%b1 = block { # root
+ %i:ptr<private, i32, read_write> = var
+}
+
+%rmw = func(%p:i32):i32 -> %b2 {
+ %b2 = block {
+ %4:i32 = load %i
+ %5:i32 = add %4, %p
+ %v:i32 = let %5
+ store %i, %v
+ ret %v
+ }
+}
+%F = func():i32 -> %b3 {
+ %b3 = block {
+ %8:i32 = call %rmw, 1i
+ %x:i32 = let %8
+ if true [t: %b4] { # if_1
+ %b4 = block { # true
+ ret %x
+ }
+ }
+ ret 2i
+ }
+}
+)";
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+
+ Run(ValueToLet); // running a second time should be no-op
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ValueToLetTest, NameMe1) {
+ auto* fn = b.Function("F", ty.i32());
+ b.Append(fn->Block(), [&] {
+ auto* v = b.Var<function, i32>("v");
+ auto* x = b.Load(v);
+ auto* y = b.Add<i32>(x, 1_i);
+ b.Store(v, 2_i);
+ b.Return(fn, y);
+ });
+
+ auto* src = R"(
+%F = func():i32 -> %b1 {
+ %b1 = block {
+ %v:ptr<function, i32, read_write> = var
+ %3:i32 = load %v
+ %4:i32 = add %3, 1i
+ store %v, 2i
+ ret %4
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%F = func():i32 -> %b1 {
+ %b1 = block {
+ %v:ptr<function, i32, read_write> = var
+ %3:i32 = load %v
+ %4:i32 = add %3, 1i
+ %5:i32 = let %4
+ store %v, 2i
+ ret %5
+ }
+}
+)";
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+
+ Run(ValueToLet); // running a second time should be no-op
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ValueToLetTest, NameMe2) {
+ auto* fn = b.Function("F", ty.void_());
+ b.Append(fn->Block(), [&] {
+ auto* i = b.Name("i", b.Call<i32>(core::BuiltinFn::kMax, 1_i, 2_i));
+ auto* v = b.Var<function>("v", i);
+ auto* x = b.Name("x", b.Call<i32>(core::BuiltinFn::kMax, 3_i, 4_i));
+ auto* y = b.Name("y", b.Load(v));
+ auto* z = b.Name("z", b.Add<i32>(y, x));
+ b.Store(v, z);
+ b.Return(fn);
+ });
+
+ auto* src = R"(
+%F = func():void -> %b1 {
+ %b1 = block {
+ %i:i32 = max 1i, 2i
+ %v:ptr<function, i32, read_write> = var, %i
+ %x:i32 = max 3i, 4i
+ %y:i32 = load %v
+ %z:i32 = add %y, %x
+ store %v, %z
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%F = func():void -> %b1 {
+ %b1 = block {
+ %i:i32 = max 1i, 2i
+ %v:ptr<function, i32, read_write> = var, %i
+ %x:i32 = max 3i, 4i
+ %y:i32 = load %v
+ %z:i32 = add %y, %x
+ store %v, %z
+ ret
+ }
+}
+)";
+
+ Run(ValueToLet);
+
+ EXPECT_EQ(expect, str());
+
+ Run(ValueToLet); // running a second time should be no-op
+
+ EXPECT_EQ(expect, str());
+}
+} // namespace
+} // namespace tint::core::ir::transform
diff --git a/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.cc b/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.cc
index 68e365a..134844c 100644
--- a/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.cc
+++ b/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.cc
@@ -57,7 +57,7 @@
Vector<Construct*, 8> worklist;
for (auto inst : ir.instructions.Objects()) {
if (auto* construct = inst->As<Construct>(); construct && construct->Alive()) {
- if (construct->Result()->Type()->As<type::Matrix>()) {
+ if (construct->Result(0)->Type()->As<type::Matrix>()) {
if (construct->Operands().Length() > 0 &&
construct->Operands()[0]->Type()->Is<type::Scalar>()) {
b.InsertBefore(construct, [&] { //
@@ -72,7 +72,7 @@
/// Replace a matrix construct instruction.
/// @param construct the instruction to replace
void ReplaceConstructor(Construct* construct) {
- auto* mat = construct->Result()->Type()->As<type::Matrix>();
+ auto* mat = construct->Result(0)->Type()->As<type::Matrix>();
auto* col = mat->ColumnType();
const auto& scalars = construct->Operands();
@@ -83,12 +83,12 @@
for (uint32_t r = 0; r < col->Width(); r++) {
values.Push(scalars[c * col->Width() + r]);
}
- columns.Push(b.Construct(col, std::move(values))->Result());
+ columns.Push(b.Construct(col, std::move(values))->Result(0));
}
// Construct the matrix from the column vectors and replace the original instruction.
- auto* replacement = b.Construct(mat, std::move(columns))->Result();
- construct->Result()->ReplaceAllUsesWith(replacement);
+ auto* replacement = b.Construct(mat, std::move(columns))->Result(0);
+ construct->Result(0)->ReplaceAllUsesWith(replacement);
construct->Destroy();
}
};
diff --git a/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors_test.cc b/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors_test.cc
index 4f42888..826ba54 100644
--- a/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors_test.cc
+++ b/src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors_test.cc
@@ -45,7 +45,7 @@
auto* func = b.Function("foo", mat);
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -72,7 +72,7 @@
func->SetParams({value});
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat, value);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -101,7 +101,7 @@
func->SetParams({v1, v2, v3});
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat, v1, v2, v3);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -131,7 +131,7 @@
func->SetParams({v1, v2, v3, v4});
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat, v1, v2, v3, v4);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -172,7 +172,7 @@
func->SetParams({v1, v2, v3, v4, v5, v6});
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -215,7 +215,7 @@
func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8});
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -256,7 +256,7 @@
func->SetParams({v1, v2, v3, v4, v5, v6});
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -301,7 +301,7 @@
func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8, v9});
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8, v9);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -349,7 +349,7 @@
func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12});
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -393,7 +393,7 @@
func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8});
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -442,7 +442,7 @@
func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12});
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -496,7 +496,7 @@
b.Append(func->Block(), [&] {
auto* construct =
b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
@@ -542,7 +542,7 @@
func->SetParams({v1, v2, v3, v4, v5, v6, v7, v8, v9});
b.Append(func->Block(), [&] {
auto* construct = b.Construct(mat, v1, v2, v3, v4, v5, v6, v7, v8, v9);
- b.Return(func, construct->Result());
+ b.Return(func, construct->Result(0));
});
auto* src = R"(
diff --git a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
index 927844b..4bfa2cf 100644
--- a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
@@ -101,10 +101,10 @@
uint32_t next_id = 0;
for (auto inst : *ir.root_block) {
if (auto* var = inst->As<Var>()) {
- auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+ auto* ptr = var->Result(0)->Type()->As<core::type::Pointer>();
if (ptr && ptr->AddressSpace() == core::AddressSpace::kWorkgroup) {
// Record the usage of the variable for each block that references it.
- var->Result()->ForEachUse([&](const Usage& use) {
+ var->Result(0)->ForEachUse([&](const Usage& use) {
block_to_direct_vars.GetOrZero(use.instruction->Block())->Add(var);
});
var_to_id.Add(var, next_id++);
@@ -113,7 +113,7 @@
}
// Process each entry point function.
- for (auto* func : ir.functions) {
+ for (auto& func : ir.functions) {
if (func->Stage() == Function::PipelineStage::kCompute) {
ProcessEntryPoint(func);
}
@@ -138,7 +138,7 @@
// Build list of store descriptors for all workgroup variables.
StoreMap stores;
for (auto* var : sorted_vars) {
- PrepareStores(var, var->Result()->Type()->UnwrapPtr(), 1, {}, stores);
+ PrepareStores(var, var->Result(0)->Type()->UnwrapPtr(), 1, {}, stores);
}
// Sort the iteration counts to get deterministic output in tests.
@@ -279,7 +279,7 @@
BuiltinValue::kLocalInvocationIndex) {
auto* access = b.Access(ty.u32(), param, u32(member->Index()));
access->InsertBefore(func->Block()->Front());
- return access->Result();
+ return access->Result(0);
}
}
} else {
@@ -305,7 +305,7 @@
/// @param total_count the total number of elements that will be zeroed
/// @param linear_index the linear index of the single element that will be zeroed
void GenerateStore(const Store& store, uint32_t total_count, Value* linear_index) {
- auto* to = store.var->Result();
+ auto* to = store.var->Result(0);
if (!store.indices.IsEmpty()) {
// Build the access indices to get to the target element.
// We walk backwards along the index list so that adjacent invocation store to
@@ -319,10 +319,10 @@
auto array_index = std::get<ArrayIndex>(idx);
Value* index = linear_index;
if (count > 1) {
- index = b.Divide(ty.u32(), index, u32(count))->Result();
+ index = b.Divide(ty.u32(), index, u32(count))->Result(0);
}
if (total_count > count * array_index.count) {
- index = b.Modulo(ty.u32(), index, u32(array_index.count))->Result();
+ index = b.Modulo(ty.u32(), index, u32(array_index.count))->Result(0);
}
indices.Push(index);
count *= array_index.count;
@@ -332,7 +332,7 @@
}
}
indices.Reverse();
- to = b.Access(ty.ptr(workgroup, store.store_type), to, indices)->Result();
+ to = b.Access(ty.ptr(workgroup, store.store_type), to, indices)->Result(0);
}
// Generate the store instruction.
diff --git a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory_test.cc b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory_test.cc
index 3546b1e..d0a972e 100644
--- a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory_test.cc
+++ b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory_test.cc
@@ -1579,7 +1579,7 @@
auto* ifelse = b.If(true);
b.Append(ifelse->True(), [&] { //
auto* sw = b.Switch(42_i);
- auto* def_case = b.Case(sw, Vector{core::ir::Switch::CaseSelector()});
+ auto* def_case = b.DefaultCase(sw);
b.Append(def_case, [&] { //
auto* loop = b.Loop();
b.Append(loop->Body(), [&] { //
@@ -1703,7 +1703,7 @@
auto* ifelse = b.If(true);
b.Append(ifelse->True(), [&] { //
auto* sw = b.Switch(42_i);
- auto* def_case = b.Case(sw, Vector{core::ir::Switch::CaseSelector()});
+ auto* def_case = b.DefaultCase(sw);
b.Append(def_case, [&] { //
auto* loop = b.Loop();
b.Append(loop->Body(), [&] { //
diff --git a/src/tint/lang/core/ir/traverse.h b/src/tint/lang/core/ir/traverse.h
index 56257bc..6e20a84 100644
--- a/src/tint/lang/core/ir/traverse.h
+++ b/src/tint/lang/core/ir/traverse.h
@@ -54,7 +54,7 @@
callback(as_t);
}
if (auto* ctrl = inst->As<ControlInstruction>()) {
- if (auto* next = inst->next) {
+ if (Instruction* next = inst->next) {
queue.Push(next); // Resume iteration of this block
}
diff --git a/src/tint/lang/core/ir/traverse_test.cc b/src/tint/lang/core/ir/traverse_test.cc
index 0fc7397..d792c24 100644
--- a/src/tint/lang/core/ir/traverse_test.cc
+++ b/src/tint/lang/core/ir/traverse_test.cc
@@ -71,10 +71,10 @@
auto* switch_ = b.Switch(1_i);
expect.Push(switch_);
- auto* case_0 = b.Case(switch_, {Switch::CaseSelector{b.Constant(0_i)}});
+ auto* case_0 = b.Case(switch_, {b.Constant(0_i)});
b.Append(case_0, [&] { expect.Push(b.Var<function, i32>()); });
- auto* case_1 = b.Case(switch_, {Switch::CaseSelector{b.Constant(1_i)}});
+ auto* case_1 = b.Case(switch_, {b.Constant(1_i)});
b.Append(case_1, [&] { expect.Push(b.Var<function, i32>()); });
expect.Push(b.Var<function, i32>());
@@ -113,10 +113,10 @@
auto* switch_ = b.Switch(1_i);
- auto* case_0 = b.Case(switch_, {Switch::CaseSelector{b.Constant(0_i)}});
+ auto* case_0 = b.Case(switch_, {b.Constant(0_i)});
b.Append(case_0, [&] { b.Var<function, i32>(); });
- auto* case_1 = b.Case(switch_, {Switch::CaseSelector{b.Constant(1_i)}});
+ auto* case_1 = b.Case(switch_, {b.Constant(1_i)});
b.Append(case_1, [&] { b.Var<function, i32>(); });
b.Var<function, i32>();
diff --git a/src/tint/lang/core/ir/unary.cc b/src/tint/lang/core/ir/unary.cc
index 2b81d7b..b79a23c 100644
--- a/src/tint/lang/core/ir/unary.cc
+++ b/src/tint/lang/core/ir/unary.cc
@@ -42,7 +42,7 @@
Unary::~Unary() = default;
Unary* Unary::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto* val = ctx.Remap(Val());
return ctx.ir.instructions.Create<Unary>(new_result, op_, val);
}
diff --git a/src/tint/lang/core/ir/unary.h b/src/tint/lang/core/ir/unary.h
index c25f5fc..af03473 100644
--- a/src/tint/lang/core/ir/unary.h
+++ b/src/tint/lang/core/ir/unary.h
@@ -60,11 +60,14 @@
/// @returns the value for the instruction
Value* Val() { return operands_[kValueOperandOffset]; }
+ /// @returns the value for the instruction
+ const Value* Val() const { return operands_[kValueOperandOffset]; }
+
/// @returns the unary operator
- UnaryOp Op() { return op_; }
+ UnaryOp Op() const { return op_; }
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "unary"; }
+ std::string FriendlyName() const override { return "unary"; }
private:
UnaryOp op_;
diff --git a/src/tint/lang/core/ir/unary_test.cc b/src/tint/lang/core/ir/unary_test.cc
index bbdccdd..a984045 100644
--- a/src/tint/lang/core/ir/unary_test.cc
+++ b/src/tint/lang/core/ir/unary_test.cc
@@ -75,10 +75,9 @@
TEST_F(IR_UnaryTest, Result) {
auto* inst = b.Negation(mod.Types().i32(), 4_i);
- EXPECT_TRUE(inst->HasResults());
- EXPECT_FALSE(inst->HasMultiResults());
- EXPECT_TRUE(inst->Result()->Is<InstructionResult>());
- EXPECT_EQ(inst->Result()->Source(), inst);
+ EXPECT_EQ(inst->Results().Length(), 1u);
+ EXPECT_TRUE(inst->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(inst->Result(0)->Instruction(), inst);
}
TEST_F(IR_UnaryTest, Fail_NullType) {
@@ -96,8 +95,8 @@
auto* new_inst = clone_ctx.Clone(inst);
EXPECT_NE(inst, new_inst);
- EXPECT_NE(nullptr, new_inst->Result());
- EXPECT_NE(inst->Result(), new_inst->Result());
+ EXPECT_NE(nullptr, new_inst->Result(0));
+ EXPECT_NE(inst->Result(0), new_inst->Result(0));
EXPECT_EQ(UnaryOp::kComplement, new_inst->Op());
diff --git a/src/tint/lang/core/ir/unreachable.h b/src/tint/lang/core/ir/unreachable.h
index 577b2f9..43cddc9 100644
--- a/src/tint/lang/core/ir/unreachable.h
+++ b/src/tint/lang/core/ir/unreachable.h
@@ -43,7 +43,7 @@
Unreachable* Clone(CloneContext& ctx) override;
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "unreachable"; }
+ std::string FriendlyName() const override { return "unreachable"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/unreachable_test.cc b/src/tint/lang/core/ir/unreachable_test.cc
index 23359f3..97a56dd 100644
--- a/src/tint/lang/core/ir/unreachable_test.cc
+++ b/src/tint/lang/core/ir/unreachable_test.cc
@@ -43,8 +43,7 @@
TEST_F(IR_UnreachableTest, Result) {
auto* inst = b.Unreachable();
- EXPECT_FALSE(inst->HasResults());
- EXPECT_FALSE(inst->HasMultiResults());
+ EXPECT_TRUE(inst->Results().IsEmpty());
}
TEST_F(IR_UnreachableTest, Clone) {
diff --git a/src/tint/lang/core/ir/user_call.cc b/src/tint/lang/core/ir/user_call.cc
index 0407fa9..698cb62 100644
--- a/src/tint/lang/core/ir/user_call.cc
+++ b/src/tint/lang/core/ir/user_call.cc
@@ -46,7 +46,7 @@
UserCall::~UserCall() = default;
UserCall* UserCall::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto* target = ctx.Remap(Target());
auto args = ctx.Remap<UserCall::kDefaultNumOperands>(Args());
return ctx.ir.instructions.Create<UserCall>(new_result, target, args);
diff --git a/src/tint/lang/core/ir/user_call.h b/src/tint/lang/core/ir/user_call.h
index 4f74824..4036208 100644
--- a/src/tint/lang/core/ir/user_call.h
+++ b/src/tint/lang/core/ir/user_call.h
@@ -55,8 +55,8 @@
/// @copydoc Instruction::Clone()
UserCall* Clone(CloneContext& ctx) override;
- /// @returns the call arguments
- tint::Slice<Value*> Args() override { return operands_.Slice().Offset(kArgsOperandOffset); }
+ /// @returns the offset of the arguments in Operands()
+ size_t ArgsOperandOffset() const override { return kArgsOperandOffset; }
/// Replaces the call arguments to @p arguments
/// @param arguments the new call arguments
@@ -65,12 +65,15 @@
/// @returns the called function
Function* Target() { return operands_[kFunctionOperandOffset]->As<ir::Function>(); }
+ /// @returns the called function
+ const Function* Target() const { return operands_[kFunctionOperandOffset]->As<ir::Function>(); }
+
/// Sets called function
/// @param target the new target of the call
void SetTarget(Function* target) { SetOperand(kFunctionOperandOffset, target); }
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "call"; }
+ std::string FriendlyName() const override { return "call"; }
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/user_call_test.cc b/src/tint/lang/core/ir/user_call_test.cc
index 1758bae..a0d65ee 100644
--- a/src/tint/lang/core/ir/user_call_test.cc
+++ b/src/tint/lang/core/ir/user_call_test.cc
@@ -53,10 +53,9 @@
auto* arg2 = b.Constant(2_u);
auto* e = b.Call(mod.Types().void_(), func, Vector{arg1, arg2});
- EXPECT_TRUE(e->HasResults());
- EXPECT_FALSE(e->HasMultiResults());
- EXPECT_TRUE(e->Result()->Is<InstructionResult>());
- EXPECT_EQ(e->Result()->Source(), e);
+ EXPECT_EQ(e->Results().Length(), 1u);
+ EXPECT_TRUE(e->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(e->Result(0)->Instruction(), e);
}
TEST_F(IR_UserCallTest, Fail_NullType) {
@@ -77,8 +76,8 @@
auto* new_e = clone_ctx.Clone(e);
EXPECT_NE(e, new_e);
- EXPECT_NE(nullptr, new_e->Result());
- EXPECT_NE(e->Result(), new_e->Result());
+ EXPECT_NE(nullptr, new_e->Result(0));
+ EXPECT_NE(e->Result(0), new_e->Result(0));
EXPECT_EQ(new_func, new_e->Target());
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index 037610f..a3a83df 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -90,7 +90,7 @@
public:
/// Create a core validator
/// @param mod the module to be validated
- explicit Validator(Module& mod);
+ explicit Validator(const Module& mod);
/// Destructor
~Validator();
@@ -103,47 +103,47 @@
/// @param inst the instruction
/// @param err the error message
/// @returns a string with the instruction name name and error message formatted
- std::string InstError(Instruction* inst, std::string err);
+ std::string InstError(const Instruction* inst, std::string err);
/// Adds an error for the @p inst and highlights the instruction in the disassembly
/// @param inst the instruction
/// @param err the error string
- void AddError(Instruction* inst, std::string err);
+ void AddError(const Instruction* inst, std::string err);
/// Adds an error for the @p inst operand at @p idx and highlights the operand in the
/// disassembly
/// @param inst the instaruction
/// @param idx the operand index
/// @param err the error string
- void AddError(Instruction* inst, size_t idx, std::string err);
+ void AddError(const Instruction* inst, size_t idx, std::string err);
/// Adds an error for the @p inst result at @p idx and highlgihts the result in the disassembly
/// @param inst the instruction
/// @param idx the result index
/// @param err the error string
- void AddResultError(Instruction* inst, size_t idx, std::string err);
+ void AddResultError(const Instruction* inst, size_t idx, std::string err);
/// Adds an error the @p block and highlights the block header in the disassembly
/// @param blk the block
/// @param err the error string
- void AddError(Block* blk, std::string err);
+ void AddError(const Block* blk, std::string err);
/// Adds a note to @p inst and highlights the instruction in the disassembly
/// @param inst the instruction
/// @param err the message to emit
- void AddNote(Instruction* inst, std::string err);
+ void AddNote(const Instruction* inst, std::string err);
/// Adds a note to @p inst for operand @p idx and highlights the operand in the
/// disassembly
/// @param inst the instruction
/// @param idx the operand index
/// @param err the message string
- void AddNote(Instruction* inst, size_t idx, std::string err);
+ void AddNote(const Instruction* inst, size_t idx, std::string err);
/// Adds a note to @p blk and highlights the block in the disassembly
/// @param blk the block
/// @param err the message to emit
- void AddNote(Block* blk, std::string err);
+ void AddNote(const Block* blk, std::string err);
/// Adds an error to the diagnostics
/// @param err the message to emit
@@ -157,160 +157,163 @@
/// @param v the value to get the name for
/// @returns the name for the given value
- std::string Name(Value* v);
+ std::string Name(const Value* v);
/// Checks the given operand is not null
- /// @param inst the instruciton
+ /// @param inst the instruction
/// @param operand the operand
/// @param idx the operand index
- void CheckOperandNotNull(ir::Instruction* inst, ir::Value* operand, size_t idx);
+ void CheckOperandNotNull(const ir::Instruction* inst, const ir::Value* operand, size_t idx);
/// Checks all operands in the given range (inclusive) for @p inst are not null
/// @param inst the instruction
/// @param start_operand the first operand to check
/// @param end_operand the last operand to check
- void CheckOperandsNotNull(ir::Instruction* inst, size_t start_operand, size_t end_operand);
+ void CheckOperandsNotNull(const ir::Instruction* inst,
+ size_t start_operand,
+ size_t end_operand);
/// Validates the root block
/// @param blk the block
- void CheckRootBlock(Block* blk);
+ void CheckRootBlock(const Block* blk);
/// Validates the given function
/// @param func the function validate
- void CheckFunction(Function* func);
+ void CheckFunction(const Function* func);
/// Validates the given block
/// @param blk the block to validate
- void CheckBlock(Block* blk);
+ void CheckBlock(const Block* blk);
/// Validates the given instruction
/// @param inst the instruction to validate
- void CheckInstruction(Instruction* inst);
+ void CheckInstruction(const Instruction* inst);
/// Validates the given var
/// @param var the var to validate
- void CheckVar(Var* var);
+ void CheckVar(const Var* var);
/// Validates the given let
/// @param let the let to validate
- void CheckLet(Let* let);
+ void CheckLet(const Let* let);
/// Validates the given call
/// @param call the call to validate
- void CheckCall(Call* call);
+ void CheckCall(const Call* call);
/// Validates the given builtin call
/// @param call the call to validate
- void CheckBuiltinCall(BuiltinCall* call);
+ void CheckBuiltinCall(const BuiltinCall* call);
/// Validates the given user call
/// @param call the call to validate
- void CheckUserCall(UserCall* call);
+ void CheckUserCall(const UserCall* call);
/// Validates the given access
/// @param a the access to validate
- void CheckAccess(ir::Access* a);
+ void CheckAccess(const Access* a);
/// Validates the given binary
/// @param b the binary to validate
- void CheckBinary(ir::Binary* b);
+ void CheckBinary(const Binary* b);
/// Validates the given unary
/// @param u the unary to validate
- void CheckUnary(ir::Unary* u);
+ void CheckUnary(const Unary* u);
/// Validates the given if
/// @param if_ the if to validate
- void CheckIf(If* if_);
+ void CheckIf(const If* if_);
/// Validates the given loop
/// @param l the loop to validate
- void CheckLoop(Loop* l);
+ void CheckLoop(const Loop* l);
/// Validates the given switch
/// @param s the switch to validate
- void CheckSwitch(Switch* s);
+ void CheckSwitch(const Switch* s);
/// Validates the given terminator
/// @param b the terminator to validate
- void CheckTerminator(ir::Terminator* b);
+ void CheckTerminator(const Terminator* b);
/// Validates the given exit
/// @param e the exit to validate
- void CheckExit(ir::Exit* e);
+ void CheckExit(const Exit* e);
/// Validates the given exit if
/// @param e the exit if to validate
- void CheckExitIf(ExitIf* e);
+ void CheckExitIf(const ExitIf* e);
/// Validates the given return
/// @param r the return to validate
- void CheckReturn(Return* r);
+ void CheckReturn(const Return* r);
/// Validates the @p exit targets a valid @p control instruction where the instruction may jump
/// over if control instructions.
/// @param exit the exit to validate
/// @param control the control instruction targeted
- void CheckControlsAllowingIf(Exit* exit, Instruction* control);
+ void CheckControlsAllowingIf(const Exit* exit, const Instruction* control);
/// Validates the given exit switch
/// @param s the exit switch to validate
- void CheckExitSwitch(ExitSwitch* s);
+ void CheckExitSwitch(const ExitSwitch* s);
/// Validates the given exit loop
/// @param l the exit loop to validate
- void CheckExitLoop(ExitLoop* l);
+ void CheckExitLoop(const ExitLoop* l);
/// Validates the given store
/// @param s the store to validate
- void CheckStore(Store* s);
+ void CheckStore(const Store* s);
/// Validates the given load vector element
/// @param l the load vector element to validate
- void CheckLoadVectorElement(LoadVectorElement* l);
+ void CheckLoadVectorElement(const LoadVectorElement* l);
/// Validates the given store vector element
/// @param s the store vector element to validate
- void CheckStoreVectorElement(StoreVectorElement* s);
+ void CheckStoreVectorElement(const StoreVectorElement* s);
/// @param inst the instruction
/// @param idx the operand index
/// @returns the vector pointer type for the given instruction operand
- const core::type::Type* GetVectorPtrElementType(Instruction* inst, size_t idx);
+ const core::type::Type* GetVectorPtrElementType(const Instruction* inst, size_t idx);
private:
- Module& mod_;
+ const Module& mod_;
+ std::shared_ptr<Source::File> disassembly_file;
diag::List diagnostics_;
Disassembler dis_{mod_};
- Block* current_block_ = nullptr;
- Hashset<Function*, 4> all_functions_;
- Hashset<Instruction*, 4> visited_instructions_;
- Vector<ControlInstruction*, 8> control_stack_;
+ const Block* current_block_ = nullptr;
+ Hashset<const Function*, 4> all_functions_;
+ Hashset<const Instruction*, 4> visited_instructions_;
+ Vector<const ControlInstruction*, 8> control_stack_;
void DisassembleIfNeeded();
};
-Validator::Validator(Module& mod) : mod_(mod) {}
+Validator::Validator(const Module& mod) : mod_(mod) {}
Validator::~Validator() = default;
void Validator::DisassembleIfNeeded() {
- if (mod_.disassembly_file) {
+ if (disassembly_file) {
return;
}
- mod_.disassembly_file = std::make_unique<Source::File>("", dis_.Disassemble());
+ disassembly_file = std::make_unique<Source::File>("", dis_.Disassemble());
}
Result<SuccessType> Validator::Run() {
CheckRootBlock(mod_.root_block);
- for (auto* func : mod_.functions) {
- if (!all_functions_.Add(func)) {
- AddError("function '" + Name(func) + "' added to module multiple times");
+ for (auto& func : mod_.functions) {
+ if (!all_functions_.Add(func.Get())) {
+ AddError("function '" + Name(func.Get()) + "' added to module multiple times");
}
}
- for (auto* func : mod_.functions) {
+ for (auto& func : mod_.functions) {
CheckFunction(func);
}
@@ -326,20 +329,19 @@
if (diagnostics_.contains_errors()) {
DisassembleIfNeeded();
diagnostics_.add_note(tint::diag::System::IR,
- "# Disassembly\n" + mod_.disassembly_file->content.data, {});
+ "# Disassembly\n" + disassembly_file->content.data, {});
return Failure{std::move(diagnostics_)};
}
return Success;
}
-std::string Validator::InstError(Instruction* inst, std::string err) {
+std::string Validator::InstError(const Instruction* inst, std::string err) {
return std::string(inst->FriendlyName()) + ": " + err;
}
-void Validator::AddError(Instruction* inst, std::string err) {
+void Validator::AddError(const Instruction* inst, std::string err) {
DisassembleIfNeeded();
auto src = dis_.InstructionSource(inst);
- src.file = mod_.disassembly_file.get();
AddError(std::move(err), src);
if (current_block_) {
@@ -347,10 +349,9 @@
}
}
-void Validator::AddError(Instruction* inst, size_t idx, std::string err) {
+void Validator::AddError(const Instruction* inst, size_t idx, std::string err) {
DisassembleIfNeeded();
- auto src = dis_.OperandSource(Usage{inst, static_cast<uint32_t>(idx)});
- src.file = mod_.disassembly_file.get();
+ auto src = dis_.OperandSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
AddError(std::move(err), src);
if (current_block_) {
@@ -358,10 +359,9 @@
}
}
-void Validator::AddResultError(Instruction* inst, size_t idx, std::string err) {
+void Validator::AddResultError(const Instruction* inst, size_t idx, std::string err) {
DisassembleIfNeeded();
- auto src = dis_.ResultSource(Usage{inst, static_cast<uint32_t>(idx)});
- src.file = mod_.disassembly_file.get();
+ auto src = dis_.ResultSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
AddError(std::move(err), src);
if (current_block_) {
@@ -369,53 +369,57 @@
}
}
-void Validator::AddError(Block* blk, std::string err) {
+void Validator::AddError(const Block* blk, std::string err) {
DisassembleIfNeeded();
auto src = dis_.BlockSource(blk);
- src.file = mod_.disassembly_file.get();
AddError(std::move(err), src);
}
-void Validator::AddNote(Instruction* inst, std::string err) {
+void Validator::AddNote(const Instruction* inst, std::string err) {
DisassembleIfNeeded();
auto src = dis_.InstructionSource(inst);
- src.file = mod_.disassembly_file.get();
AddNote(std::move(err), src);
}
-void Validator::AddNote(Instruction* inst, size_t idx, std::string err) {
+void Validator::AddNote(const Instruction* inst, size_t idx, std::string err) {
DisassembleIfNeeded();
- auto src = dis_.OperandSource(Usage{inst, static_cast<uint32_t>(idx)});
- src.file = mod_.disassembly_file.get();
+ auto src = dis_.OperandSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
AddNote(std::move(err), src);
}
-void Validator::AddNote(Block* blk, std::string err) {
+void Validator::AddNote(const Block* blk, std::string err) {
DisassembleIfNeeded();
auto src = dis_.BlockSource(blk);
- src.file = mod_.disassembly_file.get();
AddNote(std::move(err), src);
}
void Validator::AddError(std::string err, Source src) {
- diagnostics_.add_error(tint::diag::System::IR, std::move(err), src);
+ auto& diag = diagnostics_.add_error(tint::diag::System::IR, std::move(err), src);
+ if (src.range != Source::Range{{}}) {
+ diag.source.file = disassembly_file.get();
+ diag.owned_file = disassembly_file;
+ }
}
void Validator::AddNote(std::string note, Source src) {
- diagnostics_.add_note(tint::diag::System::IR, std::move(note), src);
+ auto& diag = diagnostics_.add_note(tint::diag::System::IR, std::move(note), src);
+ if (src.range != Source::Range{{}}) {
+ diag.source.file = disassembly_file.get();
+ diag.owned_file = disassembly_file;
+ }
}
-std::string Validator::Name(Value* v) {
+std::string Validator::Name(const Value* v) {
return mod_.NameOf(v).Name();
}
-void Validator::CheckOperandNotNull(ir::Instruction* inst, ir::Value* operand, size_t idx) {
+void Validator::CheckOperandNotNull(const Instruction* inst, const ir::Value* operand, size_t idx) {
if (operand == nullptr) {
AddError(inst, idx, InstError(inst, "operand is undefined"));
}
}
-void Validator::CheckOperandsNotNull(ir::Instruction* inst,
+void Validator::CheckOperandsNotNull(const Instruction* inst,
size_t start_operand,
size_t end_operand) {
auto operands = inst->Operands();
@@ -424,7 +428,7 @@
}
}
-void Validator::CheckRootBlock(Block* blk) {
+void Validator::CheckRootBlock(const Block* blk) {
TINT_SCOPED_ASSIGNMENT(current_block_, blk);
for (auto* inst : *blk) {
@@ -444,14 +448,14 @@
}
}
-void Validator::CheckFunction(Function* func) {
+void Validator::CheckFunction(const Function* func) {
CheckBlock(func->Block());
}
-void Validator::CheckBlock(Block* blk) {
+void Validator::CheckBlock(const Block* blk) {
TINT_SCOPED_ASSIGNMENT(current_block_, blk);
- if (!blk->HasTerminator()) {
+ if (!blk->Terminator()) {
AddError(blk, "block: does not end in a terminator instruction");
}
@@ -470,27 +474,25 @@
}
}
-void Validator::CheckInstruction(Instruction* inst) {
+void Validator::CheckInstruction(const Instruction* inst) {
visited_instructions_.Add(inst);
if (!inst->Alive()) {
AddError(inst, InstError(inst, "destroyed instruction found in instruction list"));
return;
}
- if (inst->HasResults()) {
- auto results = inst->Results();
- for (size_t i = 0; i < results.Length(); ++i) {
- auto* res = results[i];
- if (!res) {
- AddResultError(inst, i, InstError(inst, "instruction result is undefined"));
- continue;
- }
+ auto results = inst->Results();
+ for (size_t i = 0; i < results.Length(); ++i) {
+ auto* res = results[i];
+ if (!res) {
+ AddResultError(inst, i, InstError(inst, "instruction result is undefined"));
+ continue;
+ }
- if (res->Source() == nullptr) {
- AddResultError(inst, i, InstError(inst, "instruction result source is undefined"));
- } else if (res->Source() != inst) {
- AddResultError(inst, i,
- InstError(inst, "instruction result source has wrong instruction"));
- }
+ if (res->Instruction() == nullptr) {
+ AddResultError(inst, i, InstError(inst, "instruction result source is undefined"));
+ } else if (res->Instruction() != inst) {
+ AddResultError(inst, i,
+ InstError(inst, "instruction result source has wrong instruction"));
}
}
@@ -508,7 +510,7 @@
InstError(inst, "instruction operand " + std::to_string(i) + " is not alive"));
}
- if (!op->Usages().Contains({inst, i})) {
+ if (!op->HasUsage(inst, i)) {
AddError(
inst, i,
InstError(inst, "instruction operand " + std::to_string(i) + " missing usage"));
@@ -516,78 +518,86 @@
}
tint::Switch(
- inst, //
- [&](Access* a) { CheckAccess(a); }, //
- [&](Binary* b) { CheckBinary(b); }, //
- [&](Call* c) { CheckCall(c); }, //
- [&](If* if_) { CheckIf(if_); }, //
- [&](Let* let) { CheckLet(let); }, //
- [&](Load*) {}, //
- [&](LoadVectorElement* l) { CheckLoadVectorElement(l); }, //
- [&](Loop* l) { CheckLoop(l); }, //
- [&](Store* s) { CheckStore(s); }, //
- [&](StoreVectorElement* s) { CheckStoreVectorElement(s); }, //
- [&](Switch* s) { CheckSwitch(s); }, //
- [&](Swizzle*) {}, //
- [&](Terminator* b) { CheckTerminator(b); }, //
- [&](Unary* u) { CheckUnary(u); }, //
- [&](Var* var) { CheckVar(var); }, //
- [&](Default) { AddError(inst, InstError(inst, "missing validation")); });
+ inst, //
+ [&](const Access* a) { CheckAccess(a); }, //
+ [&](const Binary* b) { CheckBinary(b); }, //
+ [&](const Call* c) { CheckCall(c); }, //
+ [&](const If* if_) { CheckIf(if_); }, //
+ [&](const Let* let) { CheckLet(let); }, //
+ [&](const Load*) {}, //
+ [&](const LoadVectorElement* l) { CheckLoadVectorElement(l); }, //
+ [&](const Loop* l) { CheckLoop(l); }, //
+ [&](const Store* s) { CheckStore(s); }, //
+ [&](const StoreVectorElement* s) { CheckStoreVectorElement(s); }, //
+ [&](const Switch* s) { CheckSwitch(s); }, //
+ [&](const Swizzle*) {}, //
+ [&](const Terminator* b) { CheckTerminator(b); }, //
+ [&](const Unary* u) { CheckUnary(u); }, //
+ [&](const Var* var) { CheckVar(var); }, //
+ [&](const Default) { AddError(inst, InstError(inst, "missing validation")); });
}
-void Validator::CheckVar(Var* var) {
- if (var->Result() && var->Initializer()) {
- if (var->Initializer()->Type() != var->Result()->Type()->UnwrapPtr()) {
+void Validator::CheckVar(const Var* var) {
+ if (var->Result(0) && var->Initializer()) {
+ if (var->Initializer()->Type() != var->Result(0)->Type()->UnwrapPtr()) {
AddError(var, InstError(var, "initializer has incorrect type"));
}
}
}
-void Validator::CheckLet(Let* let) {
+void Validator::CheckLet(const Let* let) {
CheckOperandNotNull(let, let->Value(), Let::kValueOperandOffset);
- if (let->Result() && let->Value()) {
- if (let->Result()->Type() != let->Value()->Type()) {
+ if (let->Result(0) && let->Value()) {
+ if (let->Result(0)->Type() != let->Value()->Type()) {
AddError(let, InstError(let, "result type does not match value type"));
}
}
}
-void Validator::CheckCall(Call* call) {
+void Validator::CheckCall(const Call* call) {
tint::Switch(
- call, //
- [&](Bitcast*) {}, //
- [&](BuiltinCall* c) { CheckBuiltinCall(c); }, //
- [&](Construct*) {}, //
- [&](Convert*) {}, //
- [&](Discard*) {}, //
- [&](UserCall* c) { CheckUserCall(c); }, //
+ call, //
+ [&](const Bitcast*) {}, //
+ [&](const BuiltinCall* c) { CheckBuiltinCall(c); }, //
+ [&](const Construct*) {}, //
+ [&](const Convert*) {}, //
+ [&](const Discard*) {}, //
+ [&](const UserCall* c) { CheckUserCall(c); }, //
[&](Default) {
// Validation of custom IR instructions
});
}
-void Validator::CheckBuiltinCall(BuiltinCall* call) {
- auto args = Transform<8>(call->Args(), [&](ir::Value* v) { return v->Type(); });
- intrinsic::Context context{call->TableData(), mod_.Types(), mod_.symbols, diagnostics_};
+void Validator::CheckBuiltinCall(const BuiltinCall* call) {
+ auto symbols = SymbolTable::Wrap(mod_.symbols);
+ auto type_mgr = type::Manager::Wrap(mod_.Types());
+
+ auto args = Transform<8>(call->Args(), [&](const ir::Value* v) { return v->Type(); });
+ intrinsic::Context context{
+ call->TableData(),
+ type_mgr,
+ symbols,
+ diagnostics_,
+ };
auto result = core::intrinsic::LookupFn(context, call->FriendlyName().c_str(), call->FuncId(),
args, core::EvaluationStage::kRuntime, Source{});
if (result) {
- if (result->return_type != call->Result()->Type()) {
+ if (result->return_type != call->Result(0)->Type()) {
AddError(call, InstError(call, "call result type does not match builtin return type"));
}
}
}
-void Validator::CheckUserCall(UserCall* call) {
+void Validator::CheckUserCall(const UserCall* call) {
if (!all_functions_.Contains(call->Target())) {
AddError(call, UserCall::kFunctionOperandOffset,
InstError(call, "call target is not part of the module"));
}
}
-void Validator::CheckAccess(ir::Access* a) {
+void Validator::CheckAccess(const Access* a) {
bool is_ptr = a->Object()->Type()->Is<core::type::Pointer>();
auto* ty = a->Object()->Type()->UnwrapPtr();
@@ -645,8 +655,8 @@
}
}
- auto* want_ty = a->Result()->Type()->UnwrapPtr();
- bool want_ptr = a->Result()->Type()->Is<core::type::Pointer>();
+ auto* want_ty = a->Result(0)->Type()->UnwrapPtr();
+ bool want_ptr = a->Result(0)->Type()->Is<core::type::Pointer>();
if (TINT_UNLIKELY(ty != want_ty || is_ptr != want_ptr)) {
std::string want =
want_ptr ? "ptr<" + want_ty->FriendlyName() + ">" : want_ty->FriendlyName();
@@ -656,21 +666,21 @@
}
}
-void Validator::CheckBinary(ir::Binary* b) {
+void Validator::CheckBinary(const Binary* b) {
CheckOperandsNotNull(b, Binary::kLhsOperandOffset, Binary::kRhsOperandOffset);
}
-void Validator::CheckUnary(ir::Unary* u) {
+void Validator::CheckUnary(const Unary* u) {
CheckOperandNotNull(u, u->Val(), Unary::kValueOperandOffset);
- if (u->Result() && u->Val()) {
- if (u->Result()->Type() != u->Val()->Type()) {
+ if (u->Result(0) && u->Val()) {
+ if (u->Result(0)->Type() != u->Val()->Type()) {
AddError(u, InstError(u, "result type must match value type"));
}
}
}
-void Validator::CheckIf(If* if_) {
+void Validator::CheckIf(const If* if_) {
CheckOperandNotNull(if_, if_->Condition(), If::kConditionOperandOffset);
if (if_->Condition() && !if_->Condition()->Type()->Is<core::type::Bool>()) {
@@ -687,7 +697,7 @@
}
}
-void Validator::CheckLoop(Loop* l) {
+void Validator::CheckLoop(const Loop* l) {
control_stack_.Push(l);
TINT_DEFER(control_stack_.Pop());
@@ -701,7 +711,7 @@
}
}
-void Validator::CheckSwitch(Switch* s) {
+void Validator::CheckSwitch(const Switch* s) {
control_stack_.Push(s);
TINT_DEFER(control_stack_.Pop());
@@ -710,23 +720,23 @@
}
}
-void Validator::CheckTerminator(ir::Terminator* b) {
+void Validator::CheckTerminator(const Terminator* b) {
// Note, transforms create `undef` terminator arguments (this is done in MergeReturn and
// DemoteToHelper) so we can't add validation.
tint::Switch(
- b, //
- [&](ir::BreakIf*) {}, //
- [&](ir::Continue*) {}, //
- [&](ir::Exit* e) { CheckExit(e); }, //
- [&](ir::NextIteration*) {}, //
- [&](ir::Return* ret) { CheckReturn(ret); }, //
- [&](ir::TerminateInvocation*) {}, //
- [&](ir::Unreachable*) {}, //
+ b, //
+ [&](const ir::BreakIf*) {}, //
+ [&](const ir::Continue*) {}, //
+ [&](const ir::Exit* e) { CheckExit(e); }, //
+ [&](const ir::NextIteration*) {}, //
+ [&](const ir::Return* ret) { CheckReturn(ret); }, //
+ [&](const ir::TerminateInvocation*) {}, //
+ [&](const ir::Unreachable*) {}, //
[&](Default) { AddError(b, InstError(b, "missing validation")); });
}
-void Validator::CheckExit(ir::Exit* e) {
+void Validator::CheckExit(const Exit* e) {
if (e->ControlInstruction() == nullptr) {
AddError(e, InstError(e, "has no parent control instruction"));
return;
@@ -759,21 +769,21 @@
}
tint::Switch(
- e, //
- [&](ir::ExitIf* i) { CheckExitIf(i); }, //
- [&](ir::ExitLoop* l) { CheckExitLoop(l); }, //
- [&](ir::ExitSwitch* s) { CheckExitSwitch(s); }, //
+ e, //
+ [&](const ir::ExitIf* i) { CheckExitIf(i); }, //
+ [&](const ir::ExitLoop* l) { CheckExitLoop(l); }, //
+ [&](const ir::ExitSwitch* s) { CheckExitSwitch(s); }, //
[&](Default) { AddError(e, InstError(e, "missing validation")); });
}
-void Validator::CheckExitIf(ExitIf* e) {
+void Validator::CheckExitIf(const ExitIf* e) {
if (control_stack_.Back() != e->If()) {
AddError(e, InstError(e, "if target jumps over other control instructions"));
AddNote(control_stack_.Back(), "first control instruction jumped");
}
}
-void Validator::CheckReturn(Return* ret) {
+void Validator::CheckReturn(const Return* ret) {
auto* func = ret->Func();
if (func == nullptr) {
AddError(ret, InstError(ret, "undefined function"));
@@ -792,7 +802,7 @@
}
}
-void Validator::CheckControlsAllowingIf(Exit* exit, Instruction* control) {
+void Validator::CheckControlsAllowingIf(const Exit* exit, const Instruction* control) {
bool found = false;
for (auto ctrl : tint::Reverse(control_stack_)) {
if (ctrl == control) {
@@ -813,15 +823,15 @@
}
}
-void Validator::CheckExitSwitch(ExitSwitch* s) {
+void Validator::CheckExitSwitch(const ExitSwitch* s) {
CheckControlsAllowingIf(s, s->ControlInstruction());
}
-void Validator::CheckExitLoop(ExitLoop* l) {
+void Validator::CheckExitLoop(const ExitLoop* l) {
CheckControlsAllowingIf(l, l->ControlInstruction());
- Instruction* inst = l;
- Loop* control = l->Loop();
+ const Instruction* inst = l;
+ const Loop* control = l->Loop();
while (inst) {
// Found parent loop
if (inst->Block()->Parent() == control) {
@@ -842,7 +852,7 @@
}
}
-void Validator::CheckStore(Store* s) {
+void Validator::CheckStore(const Store* s) {
CheckOperandsNotNull(s, Store::kToOperandOffset, Store::kFromOperandOffset);
if (auto* from = s->From()) {
@@ -855,12 +865,12 @@
}
}
-void Validator::CheckLoadVectorElement(LoadVectorElement* l) {
+void Validator::CheckLoadVectorElement(const LoadVectorElement* l) {
CheckOperandsNotNull(l, //
LoadVectorElement::kFromOperandOffset,
LoadVectorElement::kIndexOperandOffset);
- if (auto* res = l->Result()) {
+ if (auto* res = l->Result(0)) {
if (auto* el_ty = GetVectorPtrElementType(l, LoadVectorElement::kFromOperandOffset)) {
if (res->Type() != el_ty) {
AddResultError(l, 0, "result type does not match vector pointer element type");
@@ -869,7 +879,7 @@
}
}
-void Validator::CheckStoreVectorElement(StoreVectorElement* s) {
+void Validator::CheckStoreVectorElement(const StoreVectorElement* s) {
CheckOperandsNotNull(s, //
StoreVectorElement::kToOperandOffset,
StoreVectorElement::kValueOperandOffset);
@@ -884,7 +894,7 @@
}
}
-const core::type::Type* Validator::GetVectorPtrElementType(Instruction* inst, size_t idx) {
+const core::type::Type* Validator::GetVectorPtrElementType(const Instruction* inst, size_t idx) {
auto* operand = inst->Operands()[idx];
if (TINT_UNLIKELY(!operand)) {
return nullptr;
@@ -909,12 +919,12 @@
} // namespace
-Result<SuccessType> Validate(Module& mod) {
+Result<SuccessType> Validate(const Module& mod) {
Validator v(mod);
return v.Run();
}
-Result<SuccessType> ValidateAndDumpIfNeeded([[maybe_unused]] Module& ir,
+Result<SuccessType> ValidateAndDumpIfNeeded([[maybe_unused]] const Module& ir,
[[maybe_unused]] const char* msg) {
#if TINT_DUMP_IR_WHEN_VALIDATING
std::cout << "=========================================================" << std::endl;
diff --git a/src/tint/lang/core/ir/validator.h b/src/tint/lang/core/ir/validator.h
index cfc6a81..d6b0843 100644
--- a/src/tint/lang/core/ir/validator.h
+++ b/src/tint/lang/core/ir/validator.h
@@ -42,13 +42,13 @@
/// Validates that a given IR module is correctly formed
/// @param mod the module to validate
/// @returns success or failure
-Result<SuccessType> Validate(Module& mod);
+Result<SuccessType> Validate(const Module& mod);
/// Validates the module @p ir and dumps its contents if required by the build configuration.
/// @param ir the module to transform
/// @param msg the msg to accompany the output
/// @returns success or failure
-Result<SuccessType> ValidateAndDumpIfNeeded(Module& ir, const char* msg);
+Result<SuccessType> ValidateAndDumpIfNeeded(const Module& ir, const char* msg);
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index d9f6abf..37cbbcc 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -1112,7 +1112,7 @@
auto* v = sb.Var(ty.ptr<function, f32>());
sb.Return(f);
- v->Result()->SetSource(nullptr);
+ v->Result(0)->SetInstruction(nullptr);
auto res = ir::Validate(mod);
ASSERT_FALSE(res);
@@ -1682,7 +1682,7 @@
b.ExitIf(if_outer);
});
- auto* c = b.Case(switch_inner, {Switch::CaseSelector{b.Constant(1_i)}});
+ auto* c = b.Case(switch_inner, {b.Constant(1_i)});
b.Append(c, [&] { b.ExitIf(if_outer); });
b.Append(f->Block(), [&] {
@@ -1779,7 +1779,7 @@
TEST_F(IR_ValidatorTest, ExitSwitch) {
auto* switch_ = b.Switch(true);
- auto* def = b.Case(switch_, {Switch::CaseSelector{}});
+ auto* def = b.DefaultCase(switch_);
def->Append(b.ExitSwitch(switch_));
auto* f = b.Function("my_func", ty.void_());
@@ -1794,7 +1794,7 @@
TEST_F(IR_ValidatorTest, ExitSwitch_NullSwitch) {
auto* switch_ = b.Switch(true);
- auto* def = b.Case(switch_, {Switch::CaseSelector{}});
+ auto* def = b.DefaultCase(switch_);
def->Append(mod.instructions.Create<ExitSwitch>(nullptr));
auto* f = b.Function("my_func", ty.void_());
@@ -1834,7 +1834,7 @@
auto* r2 = b.InstructionResult(ty.f32());
switch_->SetResults(Vector{r1, r2});
- auto* def = b.Case(switch_, {Switch::CaseSelector{}});
+ auto* def = b.DefaultCase(switch_);
def->Append(b.ExitSwitch(switch_, 1_i));
auto* f = b.Function("my_func", ty.void_());
@@ -1878,7 +1878,7 @@
auto* r2 = b.InstructionResult(ty.f32());
switch_->SetResults(Vector{r1, r2});
- auto* def = b.Case(switch_, {Switch::CaseSelector{}});
+ auto* def = b.DefaultCase(switch_);
def->Append(b.ExitSwitch(switch_, 1_i, 2_f, 3_i));
auto* f = b.Function("my_func", ty.void_());
@@ -1922,7 +1922,7 @@
auto* r2 = b.InstructionResult(ty.f32());
switch_->SetResults(Vector{r1, r2});
- auto* def = b.Case(switch_, {Switch::CaseSelector{}});
+ auto* def = b.DefaultCase(switch_);
def->Append(b.ExitSwitch(switch_, 1_i, 2_f));
auto* f = b.Function("my_func", ty.void_());
@@ -1940,7 +1940,7 @@
auto* r2 = b.InstructionResult(ty.f32());
switch_->SetResults(Vector{r1, r2});
- auto* def = b.Case(switch_, {Switch::CaseSelector{}});
+ auto* def = b.DefaultCase(switch_);
def->Append(b.ExitSwitch(switch_, 1_i, 2_i));
auto* f = b.Function("my_func", ty.void_());
@@ -1983,7 +1983,7 @@
auto* f = b.Function("my_func", ty.void_());
- auto* def = b.Case(switch_, {Switch::CaseSelector{}});
+ auto* def = b.DefaultCase(switch_);
def->Append(b.Return(f));
auto sb = b.Append(f->Block());
@@ -2037,7 +2037,7 @@
auto* f = b.Function("my_func", ty.void_());
- auto* def = b.Case(switch_, {Switch::CaseSelector{}});
+ auto* def = b.DefaultCase(switch_);
b.Append(def, [&] {
auto* if_ = b.If(true);
b.Append(if_->True(), [&] {
@@ -2059,12 +2059,12 @@
TEST_F(IR_ValidatorTest, ExitSwitch_InvalidJumpOverSwitch) {
auto* switch_ = b.Switch(true);
- auto* def = b.Case(switch_, {Switch::CaseSelector{}});
+ auto* def = b.DefaultCase(switch_);
b.Append(def, [&] {
auto* inner = b.Switch(false);
b.ExitSwitch(switch_);
- auto* inner_def = b.Case(inner, {Switch::CaseSelector{}});
+ auto* inner_def = b.DefaultCase(inner);
b.Append(inner_def, [&] { b.ExitSwitch(switch_); });
});
@@ -2112,7 +2112,7 @@
TEST_F(IR_ValidatorTest, ExitSwitch_InvalidJumpOverLoop) {
auto* switch_ = b.Switch(true);
- auto* def = b.Case(switch_, {Switch::CaseSelector{}});
+ auto* def = b.DefaultCase(switch_);
b.Append(def, [&] {
auto* loop = b.Loop();
b.Append(loop->Body(), [&] { b.ExitSwitch(switch_); });
@@ -2458,7 +2458,7 @@
auto* inner = b.Switch(false);
b.ExitLoop(loop);
- auto* inner_def = b.Case(inner, {Switch::CaseSelector{}});
+ auto* inner_def = b.DefaultCase(inner);
b.Append(inner_def, [&] { b.ExitLoop(loop); });
});
@@ -2916,7 +2916,7 @@
b.Append(f->Block(), [&] {
auto* var = b.Var(ty.ptr<function, i32>());
- b.Append(mod.instructions.Create<ir::Store>(var->Result(), nullptr));
+ b.Append(mod.instructions.Create<ir::Store>(var->Result(0), nullptr));
b.Return(f);
});
@@ -2946,7 +2946,7 @@
b.Append(f->Block(), [&] {
auto* var = b.Var(ty.ptr<function, i32>());
- b.Append(mod.instructions.Create<ir::Store>(var->Result(), b.Constant(42_u)));
+ b.Append(mod.instructions.Create<ir::Store>(var->Result(0), b.Constant(42_u)));
b.Return(f);
});
@@ -2977,7 +2977,7 @@
b.Append(f->Block(), [&] {
auto* var = b.Var(ty.ptr<function, vec3<f32>>());
- b.Append(mod.instructions.Create<ir::LoadVectorElement>(nullptr, var->Result(),
+ b.Append(mod.instructions.Create<ir::LoadVectorElement>(nullptr, var->Result(0),
b.Constant(1_i)));
b.Return(f);
});
@@ -3039,7 +3039,7 @@
b.Append(f->Block(), [&] {
auto* var = b.Var(ty.ptr<function, vec3<f32>>());
b.Append(mod.instructions.Create<ir::LoadVectorElement>(b.InstructionResult(ty.f32()),
- var->Result(), nullptr));
+ var->Result(0), nullptr));
b.Return(f);
});
@@ -3098,7 +3098,7 @@
b.Append(f->Block(), [&] {
auto* var = b.Var(ty.ptr<function, vec3<f32>>());
- b.Append(mod.instructions.Create<ir::StoreVectorElement>(var->Result(), nullptr,
+ b.Append(mod.instructions.Create<ir::StoreVectorElement>(var->Result(0), nullptr,
b.Constant(2_i)));
b.Return(f);
});
@@ -3137,7 +3137,7 @@
b.Append(f->Block(), [&] {
auto* var = b.Var(ty.ptr<function, vec3<f32>>());
- b.Append(mod.instructions.Create<ir::StoreVectorElement>(var->Result(), b.Constant(1_i),
+ b.Append(mod.instructions.Create<ir::StoreVectorElement>(var->Result(0), b.Constant(1_i),
nullptr));
b.Return(f);
});
diff --git a/src/tint/lang/core/ir/value.h b/src/tint/lang/core/ir/value.h
index f309206..55f7463 100644
--- a/src/tint/lang/core/ir/value.h
+++ b/src/tint/lang/core/ir/value.h
@@ -47,14 +47,8 @@
/// The index of the operand that is the value being used.
size_t operand_index = 0u;
- /// A specialization of Hasher for Usage.
- struct Hasher {
- /// @param u the usage to hash
- /// @returns a hash of the usage
- inline std::size_t operator()(const Usage& u) const {
- return Hash(u.instruction, u.operand_index);
- }
- };
+ /// @returns the hash code of the Usage
+ size_t HashCode() const { return Hash(instruction, operand_index); }
/// An equality helper for Usage.
/// @param other the usage to compare against
@@ -71,7 +65,7 @@
~Value() override;
/// @returns the type of the value
- virtual const core::type::Type* Type() { return nullptr; }
+ virtual const core::type::Type* Type() const { return nullptr; }
/// Destroys the Value. Once called, the Value must not be used again.
/// The Value must not be in use by any instruction.
@@ -94,7 +88,20 @@
/// @returns the set of usages of this value. An instruction may appear multiple times if it
/// uses the value for multiple different operands.
- const Hashset<Usage, 4, Usage::Hasher>& Usages() { return uses_; }
+ const Hashset<Usage, 4>& Usages() { return uses_; }
+
+ /// @returns true if this Value has any usages
+ bool IsUsed() const { return !uses_.IsEmpty(); }
+
+ /// @returns the number of usages of this Value
+ size_t NumUsages() const { return uses_.Count(); }
+
+ /// @returns true if the usages contains the instruction and operand index pair.
+ /// @param instruction the instruction
+ /// @param operand_index the in
+ bool HasUsage(const Instruction* instruction, size_t operand_index) const {
+ return uses_.Contains({const_cast<Instruction*>(instruction), operand_index});
+ }
/// Apply a function to all uses of the value that exist prior to calling this method.
/// @param func the function will be applied to each use
@@ -119,7 +126,7 @@
kDead,
};
- Hashset<Usage, 4, Usage::Hasher> uses_;
+ Hashset<Usage, 4> uses_;
/// Bitset of value flags
tint::EnumSet<Flag> flags_;
diff --git a/src/tint/lang/core/ir/value_test.cc b/src/tint/lang/core/ir/value_test.cc
index 6ea04e7..a1adee2 100644
--- a/src/tint/lang/core/ir/value_test.cc
+++ b/src/tint/lang/core/ir/value_test.cc
@@ -71,7 +71,7 @@
{
Module mod;
Builder b{mod};
- auto* val = b.Add(mod.Types().i32(), 1_i, 2_i)->Result();
+ auto* val = b.Add(mod.Types().i32(), 1_i, 2_i)->Result(0);
val->Destroy();
},
"");
diff --git a/src/tint/lang/core/ir/var.cc b/src/tint/lang/core/ir/var.cc
index 9c8cb74..b9a8f91 100644
--- a/src/tint/lang/core/ir/var.cc
+++ b/src/tint/lang/core/ir/var.cc
@@ -50,7 +50,7 @@
Var::~Var() = default;
Var* Var::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto* new_var = ctx.ir.instructions.Create<Var>(new_result);
new_var->binding_point_ = binding_point_;
@@ -68,7 +68,7 @@
}
void Var::DestroyIfOnlyAssigned() {
- auto* result = Result();
+ auto* result = Result(0);
if (result->Usages().All([](const Usage& u) { return u.instruction->Is<ir::Store>(); })) {
while (!result->Usages().IsEmpty()) {
auto& usage = *result->Usages().begin();
diff --git a/src/tint/lang/core/ir/var.h b/src/tint/lang/core/ir/var.h
index 29d1ad4..cd72271 100644
--- a/src/tint/lang/core/ir/var.h
+++ b/src/tint/lang/core/ir/var.h
@@ -71,25 +71,27 @@
void SetInitializer(Value* initializer);
/// @returns the initializer
Value* Initializer() { return operands_[kInitializerOperandOffset]; }
+ /// @returns the initializer
+ const Value* Initializer() const { return operands_[kInitializerOperandOffset]; }
/// Sets the binding point
/// @param group the group
/// @param binding the binding
void SetBindingPoint(uint32_t group, uint32_t binding) { binding_point_ = {group, binding}; }
/// @returns the binding points if `Attributes` contains `kBindingPoint`
- std::optional<struct BindingPoint> BindingPoint() { return binding_point_; }
+ std::optional<struct BindingPoint> BindingPoint() const { return binding_point_; }
/// Sets the IO attributes
/// @param attrs the attributes
void SetAttributes(const IOAttributes& attrs) { attributes_ = attrs; }
/// @returns the IO attributes
- const IOAttributes& Attributes() { return attributes_; }
+ const IOAttributes& Attributes() const { return attributes_; }
/// Destroys this instruction along with any assignment instructions, if the var is never read.
void DestroyIfOnlyAssigned();
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return "var"; }
+ std::string FriendlyName() const override { return "var"; }
private:
std::optional<struct BindingPoint> binding_point_;
diff --git a/src/tint/lang/core/ir/var_test.cc b/src/tint/lang/core/ir/var_test.cc
index bd3d59a..f49c79b 100644
--- a/src/tint/lang/core/ir/var_test.cc
+++ b/src/tint/lang/core/ir/var_test.cc
@@ -53,10 +53,9 @@
TEST_F(IR_VarTest, Results) {
auto* var = b.Var(ty.ptr<function, f32>());
- EXPECT_TRUE(var->HasResults());
- EXPECT_FALSE(var->HasMultiResults());
- EXPECT_TRUE(var->Result()->Is<InstructionResult>());
- EXPECT_EQ(var->Result()->Source(), var);
+ EXPECT_EQ(var->Results().Length(), 1u);
+ EXPECT_TRUE(var->Result(0)->Is<InstructionResult>());
+ EXPECT_EQ(var->Result(0)->Instruction(), var);
}
TEST_F(IR_VarTest, Initializer_Usage) {
@@ -83,9 +82,9 @@
auto* new_v = clone_ctx.Clone(v);
EXPECT_NE(v, new_v);
- ASSERT_NE(nullptr, new_v->Result());
- EXPECT_NE(v->Result(), new_v->Result());
- EXPECT_EQ(new_v->Result()->Type(),
+ ASSERT_NE(nullptr, new_v->Result(0));
+ EXPECT_NE(v->Result(0), new_v->Result(0));
+ EXPECT_EQ(new_v->Result(0)->Type(),
mod.Types().ptr(core::AddressSpace::kFunction, mod.Types().f32()));
auto new_val = v->Initializer()->As<Constant>()->Value();
diff --git a/src/tint/lang/core/texel_format_test.cc b/src/tint/lang/core/texel_format_test.cc
index e31030c..1500656 100644
--- a/src/tint/lang/core/texel_format_test.cc
+++ b/src/tint/lang/core/texel_format_test.cc
@@ -113,7 +113,7 @@
TEST_P(TexelFormatPrintTest, Print) {
TexelFormat value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, TexelFormatPrintTest, testing::ValuesIn(kValidCases));
diff --git a/src/tint/lang/core/type/BUILD.bazel b/src/tint/lang/core/type/BUILD.bazel
index 0f0cbe4..f813fdc 100644
--- a/src/tint/lang/core/type/BUILD.bazel
+++ b/src/tint/lang/core/type/BUILD.bazel
@@ -166,6 +166,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/core/type/BUILD.cmake b/src/tint/lang/core/type/BUILD.cmake
index 2885687..273cb07 100644
--- a/src/tint/lang/core/type/BUILD.cmake
+++ b/src/tint/lang/core/type/BUILD.cmake
@@ -165,6 +165,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
diff --git a/src/tint/lang/core/type/BUILD.gn b/src/tint/lang/core/type/BUILD.gn
index 0abcd11..7da2908 100644
--- a/src/tint/lang/core/type/BUILD.gn
+++ b/src/tint/lang/core/type/BUILD.gn
@@ -167,6 +167,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/core/type/manager.h b/src/tint/lang/core/type/manager.h
index 6d204c4..ada8c7e 100644
--- a/src/tint/lang/core/type/manager.h
+++ b/src/tint/lang/core/type/manager.h
@@ -84,8 +84,8 @@
/// Wrap returns a new Manager created with the types of `inner`.
/// The Manager returned by Wrap is intended to temporarily extend the types
/// of an existing immutable Manager.
- /// As the copied types are owned by `inner`, `inner` must not be destructed
- /// or assigned while using the returned Manager.
+ /// @warning As the copied types are owned by `inner`, `inner` must not be destructed or
+ /// assigned while using the returned Manager.
/// TODO(bclayton) - Evaluate whether there are safer alternatives to this
/// function. See crbug.com/tint/460.
/// @param inner the immutable Manager to extend
diff --git a/src/tint/lang/glsl/writer/BUILD.bazel b/src/tint/lang/glsl/writer/BUILD.bazel
index d5272f1..3dac23b 100644
--- a/src/tint/lang/glsl/writer/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/BUILD.bazel
@@ -51,13 +51,12 @@
"//src/tint/api/options",
"//src/tint/lang/core",
"//src/tint/lang/core/constant",
- "//src/tint/lang/core/ir",
"//src/tint/lang/core/type",
"//src/tint/lang/glsl/writer/raise",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
- "//src/tint/lang/wgsl/reader/lower",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
@@ -80,11 +79,6 @@
"//src/tint/lang/glsl/writer/printer",
],
"//conditions:default": [],
- }) + select({
- ":tint_build_wgsl_reader": [
- "//src/tint/lang/wgsl/reader/program_to_ir",
- ],
- "//conditions:default": [],
}),
copts = COPTS,
visibility = ["//visibility:public"],
@@ -104,6 +98,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
@@ -136,8 +131,3 @@
actual = "//src/tint:tint_build_glsl_writer_true",
)
-alias(
- name = "tint_build_wgsl_reader",
- actual = "//src/tint:tint_build_wgsl_reader_true",
-)
-
diff --git a/src/tint/lang/glsl/writer/BUILD.cmake b/src/tint/lang/glsl/writer/BUILD.cmake
index f266bae..cb302d8 100644
--- a/src/tint/lang/glsl/writer/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/BUILD.cmake
@@ -58,13 +58,12 @@
tint_api_options
tint_lang_core
tint_lang_core_constant
- tint_lang_core_ir
tint_lang_core_type
tint_lang_glsl_writer_raise
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
- tint_lang_wgsl_reader_lower
tint_lang_wgsl_sem
tint_utils_containers
tint_utils_diagnostic
@@ -90,12 +89,6 @@
)
endif(TINT_BUILD_GLSL_WRITER)
-if(TINT_BUILD_WGSL_READER)
- tint_target_add_dependencies(tint_lang_glsl_writer lib
- tint_lang_wgsl_reader_program_to_ir
- )
-endif(TINT_BUILD_WGSL_READER)
-
endif(TINT_BUILD_GLSL_WRITER)
if(TINT_BUILD_GLSL_WRITER)
################################################################################
@@ -116,6 +109,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/glsl/writer/BUILD.gn b/src/tint/lang/glsl/writer/BUILD.gn
index 0ed5983..4d5bfda 100644
--- a/src/tint/lang/glsl/writer/BUILD.gn
+++ b/src/tint/lang/glsl/writer/BUILD.gn
@@ -54,13 +54,12 @@
"${tint_src_dir}/api/options",
"${tint_src_dir}/lang/core",
"${tint_src_dir}/lang/core/constant",
- "${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/glsl/writer/raise",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
- "${tint_src_dir}/lang/wgsl/reader/lower",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
@@ -85,10 +84,6 @@
"${tint_src_dir}/lang/glsl/writer/printer",
]
}
-
- if (tint_build_wgsl_reader) {
- deps += [ "${tint_src_dir}/lang/wgsl/reader/program_to_ir" ]
- }
}
}
if (tint_build_benchmarks) {
@@ -105,6 +100,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/glsl/writer/ast_printer/BUILD.bazel b/src/tint/lang/glsl/writer/ast_printer/BUILD.bazel
index 29e2970..2841719 100644
--- a/src/tint/lang/glsl/writer/ast_printer/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/ast_printer/BUILD.bazel
@@ -53,6 +53,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/helpers",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
@@ -128,6 +129,7 @@
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/ast:test",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/glsl/writer/ast_printer/BUILD.cmake b/src/tint/lang/glsl/writer/ast_printer/BUILD.cmake
index 0b6dd27..a8e36cc 100644
--- a/src/tint/lang/glsl/writer/ast_printer/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/ast_printer/BUILD.cmake
@@ -54,6 +54,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
+ tint_lang_wgsl_features
tint_lang_wgsl_helpers
tint_lang_wgsl_program
tint_lang_wgsl_sem
@@ -133,6 +134,7 @@
tint_lang_wgsl_ast_transform
tint_lang_wgsl_ast_test
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
diff --git a/src/tint/lang/glsl/writer/ast_printer/BUILD.gn b/src/tint/lang/glsl/writer/ast_printer/BUILD.gn
index 955ffa0..692ca9b 100644
--- a/src/tint/lang/glsl/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/glsl/writer/ast_printer/BUILD.gn
@@ -56,6 +56,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/helpers",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
@@ -132,6 +133,7 @@
"${tint_src_dir}/lang/wgsl/ast:unittests",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
index 738844e..9694635 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -267,7 +267,6 @@
wgsl::Extension::kChromiumExperimentalDp4A,
wgsl::Extension::kChromiumExperimentalFullPtrParameters,
wgsl::Extension::kChromiumInternalDualSourceBlending,
- wgsl::Extension::kChromiumExperimentalReadWriteStorageTexture,
wgsl::Extension::kChromiumExperimentalPushConstant,
wgsl::Extension::kF16,
})) {
diff --git a/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel b/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel
index 72bd733..8e05047 100644
--- a/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel
@@ -60,6 +60,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
@@ -100,6 +101,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake b/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake
index 6617049..8fd03ab 100644
--- a/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake
@@ -61,6 +61,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
@@ -104,6 +105,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/glsl/writer/ast_raise/BUILD.gn b/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
index 5a7980b..38e3359 100644
--- a/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
@@ -63,6 +63,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
@@ -104,6 +105,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/glsl/writer/common/options.h b/src/tint/lang/glsl/writer/common/options.h
index e9de953..8068595 100644
--- a/src/tint/lang/glsl/writer/common/options.h
+++ b/src/tint/lang/glsl/writer/common/options.h
@@ -61,9 +61,6 @@
/// Set to `true` to disable workgroup memory zero initialization
bool disable_workgroup_init = false;
- /// Set to `true` to generate GLSL via the Tint IR instead of from the AST.
- bool use_tint_ir = false;
-
/// The GLSL version to emit
Version version;
diff --git a/src/tint/lang/glsl/writer/common/printer_support.cc b/src/tint/lang/glsl/writer/common/printer_support.cc
index d57f019..d4c62de 100644
--- a/src/tint/lang/glsl/writer/common/printer_support.cc
+++ b/src/tint/lang/glsl/writer/common/printer_support.cc
@@ -51,7 +51,7 @@
} else if (std::isnan(value)) {
out << "0.0f /* nan */";
} else {
- out << tint::writer::FloatToString(value) << "f";
+ out << tint::strconv::FloatToString(value) << "f";
}
}
@@ -61,7 +61,7 @@
} else if (std::isnan(value)) {
out << "0.0hf /* nan */";
} else {
- out << tint::writer::FloatToString(value) << "hf";
+ out << tint::strconv::FloatToString(value) << "hf";
}
}
diff --git a/src/tint/lang/glsl/writer/printer/printer.cc b/src/tint/lang/glsl/writer/printer/printer.cc
index f3dda8c..790931d 100644
--- a/src/tint/lang/glsl/writer/printer/printer.cc
+++ b/src/tint/lang/glsl/writer/printer/printer.cc
@@ -50,7 +50,7 @@
public:
/// Constructor
/// @param module the Tint IR module to generate
- explicit Printer(core::ir::Module& module) : ir_(module) {}
+ explicit Printer(const core::ir::Module& module) : ir_(module) {}
/// @param version the GLSL version information
/// @returns the generated GLSL shader
@@ -74,7 +74,7 @@
EmitBlockInstructions(ir_.root_block);
// Emit functions.
- for (auto* func : ir_.functions) {
+ for (auto& func : ir_.functions) {
EmitFunction(func);
}
@@ -84,19 +84,19 @@
}
private:
- core::ir::Module& ir_;
+ const core::ir::Module& ir_;
/// The buffer holding preamble text
TextBuffer preamble_buffer_;
/// The current function being emitted
- core::ir::Function* current_function_ = nullptr;
+ const core::ir::Function* current_function_ = nullptr;
/// The current block being emitted
- core::ir::Block* current_block_ = nullptr;
+ const core::ir::Block* current_block_ = nullptr;
/// Emit the function
/// @param func the function to emit
- void EmitFunction(core::ir::Function* func) {
+ void EmitFunction(const core::ir::Function* func) {
TINT_SCOPED_ASSIGNMENT(current_function_, func);
{
@@ -120,7 +120,7 @@
/// Emit a block
/// @param block the block to emit
- void EmitBlock(core::ir::Block* block) {
+ void EmitBlock(const core::ir::Block* block) {
// TODO(dsinclair): Handle marking inline
// MarkInlinable(block);
@@ -129,14 +129,14 @@
/// Emit the instructions in a block
/// @param block the block with the instructions to emit
- void EmitBlockInstructions(core::ir::Block* block) {
+ void EmitBlockInstructions(const core::ir::Block* block) {
TINT_SCOPED_ASSIGNMENT(current_block_, block);
for (auto* inst : *block) {
Switch(
- inst, //
- [&](core::ir::Return* r) { EmitReturn(r); }, //
- [&](core::ir::Unreachable*) { EmitUnreachable(); }, //
+ inst, //
+ [&](const core::ir::Return* r) { EmitReturn(r); }, //
+ [&](const core::ir::Unreachable*) { EmitUnreachable(); }, //
TINT_ICE_ON_NO_MATCH);
}
}
@@ -148,7 +148,7 @@
/// Emit a return instruction
/// @param r the return instruction
- void EmitReturn(core::ir::Return* r) {
+ void EmitReturn(const core::ir::Return* r) {
// If this return has no arguments and the current block is for the function which is
// being returned, skip the return.
if (current_block_ == current_function_->Block() && r->Args().IsEmpty()) {
@@ -169,7 +169,7 @@
};
} // namespace
-Result<std::string> Print(core::ir::Module& module, const Version& version) {
+Result<std::string> Print(const core::ir::Module& module, const Version& version) {
return Printer{module}.Generate(version);
}
diff --git a/src/tint/lang/glsl/writer/printer/printer.h b/src/tint/lang/glsl/writer/printer/printer.h
index 49c6301..6f75b39 100644
--- a/src/tint/lang/glsl/writer/printer/printer.h
+++ b/src/tint/lang/glsl/writer/printer/printer.h
@@ -45,7 +45,7 @@
/// @returns the generated GLSL shader on success, or failure
/// @param module the Tint IR module to generate
/// @param version the GLSL version information
-Result<std::string> Print(core::ir::Module& module, const Version& version);
+Result<std::string> Print(const core::ir::Module& module, const Version& version);
} // namespace tint::glsl::writer
diff --git a/src/tint/lang/glsl/writer/writer.cc b/src/tint/lang/glsl/writer/writer.cc
index 452bd4b..7283deb 100644
--- a/src/tint/lang/glsl/writer/writer.cc
+++ b/src/tint/lang/glsl/writer/writer.cc
@@ -34,13 +34,26 @@
#include "src/tint/lang/glsl/writer/printer/printer.h"
#include "src/tint/lang/glsl/writer/raise/raise.h"
-#if TINT_BUILD_WGSL_READER
-#include "src/tint/lang/wgsl/reader/lower/lower.h"
-#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
-#endif // TINT_BUILD_WGSL_REAdDER
-
namespace tint::glsl::writer {
+Result<Output> Generate(core::ir::Module& ir, const Options& options, const std::string&) {
+ Output output;
+
+ // Raise from core-dialect to GLSL-dialect.
+ if (auto res = raise::Raise(ir); !res) {
+ return res.Failure();
+ }
+
+ // Generate the GLSL code.
+ auto result = Print(ir, options.version);
+ if (!result) {
+ return result.Failure();
+ }
+ output.glsl = result.Get();
+
+ return output;
+}
+
Result<Output> Generate(const Program& program,
const Options& options,
const std::string& entry_point) {
@@ -50,58 +63,27 @@
Output output;
- if (options.use_tint_ir) {
-#if TINT_BUILD_WGSL_READER
- // Convert the AST program to an IR module.
- auto converted = wgsl::reader::ProgramToIR(program);
- if (!converted) {
- return converted.Failure();
- }
+ // Sanitize the program.
+ auto sanitized_result = Sanitize(program, options, entry_point);
+ if (!sanitized_result.program.IsValid()) {
+ return Failure{sanitized_result.program.Diagnostics()};
+ }
- auto ir = converted.Move();
+ // Generate the GLSL code.
+ auto impl = std::make_unique<ASTPrinter>(sanitized_result.program, options.version);
+ if (!impl->Generate()) {
+ return Failure{impl->Diagnostics()};
+ }
- // Lower from WGSL-dialect to core-dialect
- if (auto res = wgsl::reader::Lower(ir); !res) {
- return res.Failure();
- }
+ output.glsl = impl->Result();
+ output.needs_internal_uniform_buffer = sanitized_result.needs_internal_uniform_buffer;
+ output.bindpoint_to_data = std::move(sanitized_result.bindpoint_to_data);
- // Raise from core-dialect to GLSL-dialect.
- if (auto res = raise::Raise(ir); !res) {
- return res.Failure();
- }
-
- // Generate the GLSL code.
- auto result = Print(ir, options.version);
- if (!result) {
- return result.Failure();
- }
- output.glsl = result.Get();
-#else
- return Failure{"use_tint_ir requires building with TINT_BUILD_WGSL_READER"};
-#endif
- } else {
- // Sanitize the program.
- auto sanitized_result = Sanitize(program, options, entry_point);
- if (!sanitized_result.program.IsValid()) {
- return Failure{sanitized_result.program.Diagnostics()};
- }
-
- // Generate the GLSL code.
- auto impl = std::make_unique<ASTPrinter>(sanitized_result.program, options.version);
- if (!impl->Generate()) {
- return Failure{impl->Diagnostics()};
- }
-
- output.glsl = impl->Result();
- output.needs_internal_uniform_buffer = sanitized_result.needs_internal_uniform_buffer;
- output.bindpoint_to_data = std::move(sanitized_result.bindpoint_to_data);
-
- // Collect the list of entry points in the sanitized program.
- for (auto* func : sanitized_result.program.AST().Functions()) {
- if (func->IsEntryPoint()) {
- auto name = func->name->symbol.Name();
- output.entry_points.push_back({name, func->PipelineStage()});
- }
+ // Collect the list of entry points in the sanitized program.
+ for (auto* func : sanitized_result.program.AST().Functions()) {
+ if (func->IsEntryPoint()) {
+ auto name = func->name->symbol.Name();
+ output.entry_points.push_back({name, func->PipelineStage()});
}
}
diff --git a/src/tint/lang/glsl/writer/writer.h b/src/tint/lang/glsl/writer/writer.h
index a2aa79c..299ee08 100644
--- a/src/tint/lang/glsl/writer/writer.h
+++ b/src/tint/lang/glsl/writer/writer.h
@@ -39,12 +39,26 @@
namespace tint {
class Program;
} // namespace tint
+namespace tint::core::ir {
+class Module;
+} // namespace tint::core::ir
namespace tint::glsl::writer {
/// Generate GLSL for a program, according to a set of configuration options.
/// The result will contain the GLSL and supplementary information, or failure.
/// information.
+/// @param ir the IR module to translate to GLSL
+/// @param options the configuration options to use when generating GLSL
+/// @param entry_point the entry point to generate GLSL for
+/// @returns the resulting GLSL and supplementary information, or failure
+Result<Output> Generate(core::ir::Module& ir,
+ const Options& options,
+ const std::string& entry_point);
+
+/// Generate GLSL for a program, according to a set of configuration options.
+/// The result will contain the GLSL and supplementary information, or failure.
+/// information.
/// @param program the program to translate to GLSL
/// @param options the configuration options to use when generating GLSL
/// @param entry_point the entry point to generate GLSL for
diff --git a/src/tint/lang/hlsl/writer/BUILD.bazel b/src/tint/lang/hlsl/writer/BUILD.bazel
index 13ff49e..71c0cbd 100644
--- a/src/tint/lang/hlsl/writer/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/BUILD.bazel
@@ -56,6 +56,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/hlsl/writer/BUILD.cmake b/src/tint/lang/hlsl/writer/BUILD.cmake
index ad00144..b9d641d 100644
--- a/src/tint/lang/hlsl/writer/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/BUILD.cmake
@@ -61,6 +61,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/hlsl/writer/BUILD.gn b/src/tint/lang/hlsl/writer/BUILD.gn
index f43dace..6b8a8fc 100644
--- a/src/tint/lang/hlsl/writer/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/BUILD.gn
@@ -59,6 +59,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/hlsl/writer/ast_printer/BUILD.bazel b/src/tint/lang/hlsl/writer/ast_printer/BUILD.bazel
index 3bd3f35..f0031c3 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/ast_printer/BUILD.bazel
@@ -54,6 +54,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/helpers",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
@@ -129,6 +130,7 @@
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/ast:test",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/hlsl/writer/ast_printer/BUILD.cmake b/src/tint/lang/hlsl/writer/ast_printer/BUILD.cmake
index 8ce9a91..a700a8f 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/ast_printer/BUILD.cmake
@@ -55,6 +55,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
+ tint_lang_wgsl_features
tint_lang_wgsl_helpers
tint_lang_wgsl_program
tint_lang_wgsl_sem
@@ -134,6 +135,7 @@
tint_lang_wgsl_ast_transform
tint_lang_wgsl_ast_test
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
diff --git a/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn b/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn
index 3788b50..b61ed79 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn
@@ -57,6 +57,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/helpers",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
@@ -131,6 +132,7 @@
"${tint_src_dir}/lang/wgsl/ast:unittests",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
index 6f883e5..d66be8d 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
@@ -27,11 +27,9 @@
#include "src/tint/lang/hlsl/writer/ast_printer/ast_printer.h"
-#include <algorithm>
#include <cmath>
#include <functional>
#include <iomanip>
-#include <set>
#include <utility>
#include <vector>
@@ -41,7 +39,6 @@
#include "src/tint/lang/core/type/array.h"
#include "src/tint/lang/core/type/atomic.h"
#include "src/tint/lang/core/type/depth_multisampled_texture.h"
-#include "src/tint/lang/core/type/depth_texture.h"
#include "src/tint/lang/core/type/multisampled_texture.h"
#include "src/tint/lang/core/type/sampled_texture.h"
#include "src/tint/lang/core/type/storage_texture.h"
@@ -50,10 +47,10 @@
#include "src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.h"
#include "src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment.h"
#include "src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.h"
+#include "src/tint/lang/hlsl/writer/ast_raise/pixel_local.h"
#include "src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch.h"
#include "src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h"
#include "src/tint/lang/wgsl/ast/call_statement.h"
-#include "src/tint/lang/wgsl/ast/id_attribute.h"
#include "src/tint/lang/wgsl/ast/internal_attribute.h"
#include "src/tint/lang/wgsl/ast/interpolate_attribute.h"
#include "src/tint/lang/wgsl/ast/transform/add_empty_entry_point.h"
@@ -140,7 +137,7 @@
} else if (std::isnan(value)) {
out << "0.0f /* nan */";
} else {
- out << tint::writer::FloatToString(value) << "f";
+ out << tint::strconv::FloatToString(value) << "f";
}
}
@@ -150,7 +147,7 @@
} else if (std::isnan(value)) {
out << "0.0h /* nan */";
} else {
- out << tint::writer::FloatToString(value) << "h";
+ out << tint::strconv::FloatToString(value) << "h";
}
}
@@ -270,6 +267,34 @@
manager.Add<ast::transform::ZeroInitWorkgroupMemory>();
}
+ {
+ PixelLocal::Config cfg;
+ for (auto it : options.pixel_local_options.attachments) {
+ cfg.pls_member_to_rov_reg.Add(it.first, it.second);
+ }
+ for (auto it : options.pixel_local_options.attachment_formats) {
+ core::TexelFormat format = core::TexelFormat::kUndefined;
+ switch (it.second) {
+ case PixelLocalOptions::TexelFormat::kR32Sint:
+ format = core::TexelFormat::kR32Sint;
+ break;
+ case PixelLocalOptions::TexelFormat::kR32Uint:
+ format = core::TexelFormat::kR32Uint;
+ break;
+ case PixelLocalOptions::TexelFormat::kR32Float:
+ format = core::TexelFormat::kR32Float;
+ break;
+ default:
+ TINT_ICE() << "missing texel format for pixel local storage attachment";
+ return SanitizedResult();
+ }
+ cfg.pls_member_to_rov_format.Add(it.first, format);
+ }
+ cfg.rov_group_index = options.pixel_local_options.pixel_local_group_index;
+ data.Add<PixelLocal::Config>(cfg);
+ manager.Add<PixelLocal>();
+ }
+
// CanonicalizeEntryPointIO must come after Robustness
manager.Add<ast::transform::CanonicalizeEntryPointIO>();
@@ -357,10 +382,10 @@
wgsl::Extension::kChromiumExperimentalDp4A,
wgsl::Extension::kChromiumExperimentalFullPtrParameters,
wgsl::Extension::kChromiumExperimentalPushConstant,
- wgsl::Extension::kChromiumExperimentalReadWriteStorageTexture,
wgsl::Extension::kChromiumExperimentalSubgroups,
wgsl::Extension::kF16,
wgsl::Extension::kChromiumInternalDualSourceBlending,
+ wgsl::Extension::kChromiumExperimentalPixelLocal,
})) {
return false;
}
@@ -3378,7 +3403,22 @@
auto name = var->name->symbol.Name();
auto* type = sem->Type()->UnwrapRef();
- if (!EmitTypeAndName(out, type, sem->AddressSpace(), sem->Access(), name)) {
+ if (ast::HasAttribute<PixelLocal::RasterizerOrderedView>(var->attributes)) {
+ TINT_ASSERT(!type->Is<core::type::MultisampledTexture>());
+ auto* storage = type->As<core::type::StorageTexture>();
+ if (!storage) {
+ TINT_ICE() << "Rasterizer Ordered View type isn't storage texture";
+ return false;
+ }
+ out << "RasterizerOrderedTexture2D";
+ auto* component = image_format_to_rwtexture_type(storage->texel_format());
+ if (TINT_UNLIKELY(!component)) {
+ TINT_ICE() << "Unsupported StorageTexture TexelFormat: "
+ << static_cast<int>(storage->texel_format());
+ return false;
+ }
+ out << "<" << component << "> " << name;
+ } else if (!EmitTypeAndName(out, type, sem->AddressSpace(), sem->Access(), name)) {
return false;
}
diff --git a/src/tint/lang/hlsl/writer/ast_raise/BUILD.bazel b/src/tint/lang/hlsl/writer/ast_raise/BUILD.bazel
index 5ea675c..1af1d58 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/ast_raise/BUILD.bazel
@@ -65,6 +65,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
@@ -107,6 +108,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/hlsl/writer/ast_raise/BUILD.cmake b/src/tint/lang/hlsl/writer/ast_raise/BUILD.cmake
index a7a9437..ad2de08 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/ast_raise/BUILD.cmake
@@ -66,6 +66,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
@@ -111,6 +112,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn b/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn
index 3200039..c009305 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn
@@ -68,6 +68,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
@@ -111,6 +112,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/hlsl/writer/common/options.h b/src/tint/lang/hlsl/writer/common/options.h
index e8d5cc0..1ff17bb 100644
--- a/src/tint/lang/hlsl/writer/common/options.h
+++ b/src/tint/lang/hlsl/writer/common/options.h
@@ -37,6 +37,7 @@
#include "src/tint/api/options/array_length_from_uniform.h"
#include "src/tint/api/options/binding_remapper.h"
#include "src/tint/api/options/external_texture.h"
+#include "src/tint/api/options/pixel_local.h"
#include "src/tint/lang/core/access.h"
#include "src/tint/utils/reflection/reflection.h"
@@ -93,6 +94,9 @@
/// AccessControls is a map of old binding point to new access control
std::unordered_map<BindingPoint, core::Access> access_controls;
+ /// Options used to deal with pixel local storage variables
+ PixelLocalOptions pixel_local_options = {};
+
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(disable_robustness,
disable_workgroup_init,
@@ -104,7 +108,8 @@
external_texture_options,
binding_remapper_options,
binding_points_ignored_in_robustness_transform,
- access_controls);
+ access_controls,
+ pixel_local_options);
};
} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/msl/validate/BUILD.bazel b/src/tint/lang/msl/validate/BUILD.bazel
index 5ea0d1a..0606047 100644
--- a/src/tint/lang/msl/validate/BUILD.bazel
+++ b/src/tint/lang/msl/validate/BUILD.bazel
@@ -41,7 +41,7 @@
srcs = [
"validate.cc",
] + select({
- ":is_mac": [
+ ":tint_build_is_mac": [
"validate_metal.mm",
],
"//conditions:default": [],
@@ -55,6 +55,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/command",
@@ -72,7 +73,7 @@
"//src/tint/utils/text",
"//src/tint/utils/traits",
] + select({
- ":is_mac": [
+ ":tint_build_is_mac": [
],
"//conditions:default": [],
@@ -82,8 +83,8 @@
)
alias(
- name = "is_mac",
- actual = "//src/tint:is_mac_true",
+ name = "tint_build_is_mac",
+ actual = "//src/tint:tint_build_is_mac_true",
)
alias(
diff --git a/src/tint/lang/msl/validate/BUILD.cmake b/src/tint/lang/msl/validate/BUILD.cmake
index 14012fe..e51eab9 100644
--- a/src/tint/lang/msl/validate/BUILD.cmake
+++ b/src/tint/lang/msl/validate/BUILD.cmake
@@ -51,6 +51,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_command
@@ -69,13 +70,13 @@
tint_utils_traits
)
-if(IS_MAC)
+if(TINT_BUILD_IS_MAC)
tint_target_add_sources(tint_lang_msl_validate lib
"lang/msl/validate/validate_metal.mm"
)
tint_target_add_external_dependencies(tint_lang_msl_validate lib
"metal"
)
-endif(IS_MAC)
+endif(TINT_BUILD_IS_MAC)
endif(TINT_BUILD_MSL_WRITER)
\ No newline at end of file
diff --git a/src/tint/lang/msl/validate/BUILD.gn b/src/tint/lang/msl/validate/BUILD.gn
index 5789793..2d587b1 100644
--- a/src/tint/lang/msl/validate/BUILD.gn
+++ b/src/tint/lang/msl/validate/BUILD.gn
@@ -49,6 +49,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/command",
@@ -67,7 +68,7 @@
"${tint_src_dir}/utils/traits",
]
- if (is_mac) {
+ if (tint_build_is_mac) {
sources += [ "validate_metal.mm" ]
deps += [ "${tint_src_dir}:metal" ]
}
diff --git a/src/tint/lang/msl/validate/validate.h b/src/tint/lang/msl/validate/validate.h
index 89581d6..1a303d5 100644
--- a/src/tint/lang/msl/validate/validate.h
+++ b/src/tint/lang/msl/validate/validate.h
@@ -61,7 +61,7 @@
std::string output;
};
-/// Msl attempts to compile the shader with the Metal Shader Compiler,
+/// Validate attempts to compile the shader with the Metal Shader Compiler,
/// verifying that the shader compiles successfully.
/// @param xcrun_path path to xcrun
/// @param source the generated MSL source
@@ -70,7 +70,7 @@
Result Validate(const std::string& xcrun_path, const std::string& source, MslVersion version);
#ifdef __APPLE__
-/// Msl attempts to compile the shader with the runtime Metal Shader Compiler
+/// ValidateUsingMetal attempts to compile the shader with the runtime Metal Shader Compiler
/// API, verifying that the shader compiles successfully.
/// @param source the generated MSL source
/// @param version the version of MSL to validate against
diff --git a/src/tint/lang/msl/validate/validate_metal.mm b/src/tint/lang/msl/validate/validate_metal.mm
index 4669e6c..9a1b090 100644
--- a/src/tint/lang/msl/validate/validate_metal.mm
+++ b/src/tint/lang/msl/validate/validate_metal.mm
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// GEN_BUILD:CONDITION(is_mac)
+// GEN_BUILD:CONDITION(tint_build_is_mac)
#import <Metal/Metal.h>
diff --git a/src/tint/lang/msl/writer/BUILD.bazel b/src/tint/lang/msl/writer/BUILD.bazel
index f57979e..b2c8ad1 100644
--- a/src/tint/lang/msl/writer/BUILD.bazel
+++ b/src/tint/lang/msl/writer/BUILD.bazel
@@ -53,9 +53,9 @@
"//src/tint/lang/core/constant",
"//src/tint/lang/core/ir",
"//src/tint/lang/core/type",
- "//src/tint/lang/msl/writer/raise",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/reader/lower",
"//src/tint/lang/wgsl/sem",
@@ -78,6 +78,7 @@
"//src/tint/lang/msl/writer/ast_printer",
"//src/tint/lang/msl/writer/common",
"//src/tint/lang/msl/writer/printer",
+ "//src/tint/lang/msl/writer/raise",
],
"//conditions:default": [],
}) + select({
@@ -104,6 +105,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/msl/writer/BUILD.cmake b/src/tint/lang/msl/writer/BUILD.cmake
index 243f93b..d1b3c1a 100644
--- a/src/tint/lang/msl/writer/BUILD.cmake
+++ b/src/tint/lang/msl/writer/BUILD.cmake
@@ -61,9 +61,9 @@
tint_lang_core_constant
tint_lang_core_ir
tint_lang_core_type
- tint_lang_msl_writer_raise
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_reader_lower
tint_lang_wgsl_sem
@@ -88,6 +88,7 @@
tint_lang_msl_writer_ast_printer
tint_lang_msl_writer_common
tint_lang_msl_writer_printer
+ tint_lang_msl_writer_raise
)
endif(TINT_BUILD_MSL_WRITER)
@@ -117,6 +118,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/msl/writer/BUILD.gn b/src/tint/lang/msl/writer/BUILD.gn
index 2b379e5..e3f3066 100644
--- a/src/tint/lang/msl/writer/BUILD.gn
+++ b/src/tint/lang/msl/writer/BUILD.gn
@@ -56,9 +56,9 @@
"${tint_src_dir}/lang/core/constant",
"${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/type",
- "${tint_src_dir}/lang/msl/writer/raise",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/reader/lower",
"${tint_src_dir}/lang/wgsl/sem",
@@ -83,6 +83,7 @@
"${tint_src_dir}/lang/msl/writer/ast_printer",
"${tint_src_dir}/lang/msl/writer/common",
"${tint_src_dir}/lang/msl/writer/printer",
+ "${tint_src_dir}/lang/msl/writer/raise",
]
}
@@ -105,6 +106,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/msl/writer/ast_printer/BUILD.bazel b/src/tint/lang/msl/writer/ast_printer/BUILD.bazel
index 5ffc9c4..87734c8 100644
--- a/src/tint/lang/msl/writer/ast_printer/BUILD.bazel
+++ b/src/tint/lang/msl/writer/ast_printer/BUILD.bazel
@@ -53,6 +53,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/helpers",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
@@ -125,6 +126,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast:test",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/msl/writer/ast_printer/BUILD.cmake b/src/tint/lang/msl/writer/ast_printer/BUILD.cmake
index c1c315b..e678ba3 100644
--- a/src/tint/lang/msl/writer/ast_printer/BUILD.cmake
+++ b/src/tint/lang/msl/writer/ast_printer/BUILD.cmake
@@ -54,6 +54,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
+ tint_lang_wgsl_features
tint_lang_wgsl_helpers
tint_lang_wgsl_program
tint_lang_wgsl_sem
@@ -130,6 +131,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_test
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
diff --git a/src/tint/lang/msl/writer/ast_printer/BUILD.gn b/src/tint/lang/msl/writer/ast_printer/BUILD.gn
index 9f46788..75dc19a 100644
--- a/src/tint/lang/msl/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/msl/writer/ast_printer/BUILD.gn
@@ -56,6 +56,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/helpers",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
@@ -129,6 +130,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast:unittests",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
index 60f7f81..712eddb 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
@@ -278,7 +278,6 @@
wgsl::Extension::kChromiumExperimentalDp4A,
wgsl::Extension::kChromiumExperimentalFullPtrParameters,
wgsl::Extension::kChromiumExperimentalPixelLocal,
- wgsl::Extension::kChromiumExperimentalReadWriteStorageTexture,
wgsl::Extension::kChromiumExperimentalSubgroups,
wgsl::Extension::kChromiumExperimentalFramebufferFetch,
wgsl::Extension::kChromiumInternalDualSourceBlending,
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_type_test.cc b/src/tint/lang/msl/writer/ast_printer/ast_type_test.cc
index f341c21..dcca0d6 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_type_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_type_test.cc
@@ -39,6 +39,10 @@
#include "src/tint/lang/msl/writer/ast_printer/helper_test.h"
#include "src/tint/utils/text/string_stream.h"
+// Done except for two questions on:
+// TEST_F(MslASTPrinterTest, EmitType_Struct_WithAttribute) {
+// TEST_F(MslASTPrinterTest, EmitType_Pointer) {
+
namespace tint::msl::writer {
namespace {
@@ -102,6 +106,7 @@
using MslASTPrinterTest = TestHelper;
+// MslPrinterTest.EmitType_Array
TEST_F(MslASTPrinterTest, EmitType_Array) {
auto arr = ty.array<bool, 4>();
ast::Type type = GlobalVar("G", arr, core::AddressSpace::kPrivate)->type;
@@ -113,6 +118,7 @@
EXPECT_EQ(out.str(), "tint_array<bool, 4>");
}
+// MslPrinterTest.EmitType_ArrayOfArray
TEST_F(MslASTPrinterTest, EmitType_ArrayOfArray) {
auto a = ty.array<bool, 4>();
auto b = ty.array(a, 5_u);
@@ -125,6 +131,7 @@
EXPECT_EQ(out.str(), "tint_array<tint_array<bool, 4>, 5>");
}
+// MslPrinterTest.EmitType_ArrayOfArrayOfArray
TEST_F(MslASTPrinterTest, EmitType_ArrayOfArrayOfArray) {
auto a = ty.array<bool, 4>();
auto b = ty.array(a, 5_u);
@@ -138,6 +145,7 @@
EXPECT_EQ(out.str(), "tint_array<tint_array<tint_array<bool, 4>, 5>, 6>");
}
+// TODO(dsinclair): Port? Not sure if this is relevant ...
TEST_F(MslASTPrinterTest, EmitType_Array_WithoutName) {
auto arr = ty.array<bool, 4>();
ast::Type type = GlobalVar("G", arr, core::AddressSpace::kPrivate)->type;
@@ -149,6 +157,7 @@
EXPECT_EQ(out.str(), "tint_array<bool, 4>");
}
+// MslPrinterTest.EmitType_RuntimeArray
TEST_F(MslASTPrinterTest, EmitType_RuntimeArray) {
auto arr = ty.array<bool, 1>();
ast::Type type = GlobalVar("G", arr, core::AddressSpace::kPrivate)->type;
@@ -160,6 +169,7 @@
EXPECT_EQ(out.str(), "tint_array<bool, 1>");
}
+// MSLPrinterTest.EmitType_Bool
TEST_F(MslASTPrinterTest, EmitType_Bool) {
auto* bool_ = create<core::type::Bool>();
@@ -170,6 +180,7 @@
EXPECT_EQ(out.str(), "bool");
}
+// MSLPrintertest.EmitType_F32
TEST_F(MslASTPrinterTest, EmitType_F32) {
auto* f32 = create<core::type::F32>();
@@ -180,6 +191,7 @@
EXPECT_EQ(out.str(), "float");
}
+// MSLPrinterTest.EmitType_F16
TEST_F(MslASTPrinterTest, EmitType_F16) {
auto* f16 = create<core::type::F16>();
@@ -190,6 +202,7 @@
EXPECT_EQ(out.str(), "half");
}
+// MSLPrinterTest.EmitType_I32
TEST_F(MslASTPrinterTest, EmitType_I32) {
auto* i32 = create<core::type::I32>();
@@ -200,6 +213,7 @@
EXPECT_EQ(out.str(), "int");
}
+// MSLPrinterTest.EmitType_Matrix_F32
TEST_F(MslASTPrinterTest, EmitType_Matrix_F32) {
auto* f32 = create<core::type::F32>();
auto* vec3 = create<core::type::Vector>(f32, 3u);
@@ -212,6 +226,7 @@
EXPECT_EQ(out.str(), "float2x3");
}
+// MSLPrinterTest.EmitType_Matrix_F16
TEST_F(MslASTPrinterTest, EmitType_Matrix_F16) {
auto* f16 = create<core::type::F16>();
auto* vec3 = create<core::type::Vector>(f16, 3u);
@@ -224,6 +239,7 @@
EXPECT_EQ(out.str(), "half2x3");
}
+// TODO(dsinclair): Not sure if this is relevant? MslPrinterTest.EmitType_Pointer_Workgroup
TEST_F(MslASTPrinterTest, EmitType_Pointer) {
auto* f32 = create<core::type::F32>();
auto* p =
@@ -249,6 +265,7 @@
EXPECT_EQ(out.str(), "S");
}
+// MSLPrinterTest.EmitType_Struct
TEST_F(MslASTPrinterTest, EmitType_StructDecl) {
auto* s = Structure("S", Vector{
Member("a", ty.i32()),
@@ -267,6 +284,7 @@
)");
}
+// MSLPrinterTest.EmitType_Struct_Layout_NonComposites
TEST_F(MslASTPrinterTest, EmitType_Struct_Layout_NonComposites) {
auto* s =
Structure("S", Vector{
@@ -384,6 +402,7 @@
#undef ALL_FIELDS
}
+// MSLPrinterTest.EmitType_Struct_Layout_Structures
TEST_F(MslASTPrinterTest, EmitType_Struct_Layout_Structures) {
// inner_x: size(1024), align(512)
auto* inner_x = Structure("inner_x", Vector{
@@ -472,6 +491,7 @@
#undef ALL_FIELDS
}
+// MSLPrinterTest.EmitType_Struct_Layout_ArrayDefaultStride
TEST_F(MslASTPrinterTest, EmitType_Struct_Layout_ArrayDefaultStride) {
// inner: size(1024), align(512)
auto* inner = Structure("inner", Vector{
@@ -571,6 +591,7 @@
#undef ALL_FIELDS
}
+// MslPrinterTest.EmitType_Struct_Layout_ArrayVec3DefaultStride
TEST_F(MslASTPrinterTest, EmitType_Struct_Layout_ArrayVec3DefaultStride) {
// array: size(64), align(16)
auto array = ty.array<vec3<f32>, 4>();
@@ -611,6 +632,7 @@
EXPECT_EQ(buf.String(), expect.str());
}
+// MslPrinterTest.AttemptTintPadSymbolCollision
TEST_F(MslASTPrinterTest, AttemptTintPadSymbolCollision) {
auto* s = Structure(
"S", Vector{
@@ -696,6 +718,7 @@
)");
}
+// TODO(dsinclair): Missing from IR tests, but test also doesn't look right.
TEST_F(MslASTPrinterTest, EmitType_Struct_WithAttribute) {
auto* s = Structure("S", Vector{
Member("a", ty.i32()),
@@ -718,6 +741,7 @@
)");
}
+// MSLPrinterTest.EmitType_U32
TEST_F(MslASTPrinterTest, EmitType_U32) {
auto* u32 = create<core::type::U32>();
@@ -728,6 +752,7 @@
EXPECT_EQ(out.str(), "uint");
}
+// MSLPrinterTest.EmitType_Vector
TEST_F(MslASTPrinterTest, EmitType_Vector) {
auto* f32 = create<core::type::F32>();
auto* vec3 = create<core::type::Vector>(f32, 3u);
@@ -739,6 +764,7 @@
EXPECT_EQ(out.str(), "float3");
}
+// MSLPrinterTest.EmitType_Void
TEST_F(MslASTPrinterTest, EmitType_Void) {
auto* void_ = create<core::type::Void>();
@@ -749,6 +775,7 @@
EXPECT_EQ(out.str(), "void");
}
+// MSLPrinterTest.EmitType_Sampler
TEST_F(MslASTPrinterTest, EmitType_Sampler) {
auto* sampler = create<core::type::Sampler>(core::type::SamplerKind::kSampler);
@@ -759,6 +786,7 @@
EXPECT_EQ(out.str(), "sampler");
}
+// MSLPrinterTest.EmitType_SamplerComparison
TEST_F(MslASTPrinterTest, EmitType_SamplerComparison) {
auto* sampler = create<core::type::Sampler>(core::type::SamplerKind::kComparisonSampler);
@@ -780,6 +808,7 @@
return out;
}
using MslDepthTexturesTest = TestParamHelper<MslDepthTextureData>;
+// MslPrinterDepthTexturesTest.Emit
TEST_P(MslDepthTexturesTest, Emit) {
auto params = GetParam();
@@ -804,6 +833,7 @@
"depthcube_array<float, access::sample>"}));
using MslDepthMultisampledTexturesTest = TestHelper;
+// MSLPrinterTest.EmitType_DepthMultisampledTexture
TEST_F(MslDepthMultisampledTexturesTest, Emit) {
core::type::DepthMultisampledTexture s(core::type::TextureDimension::k2d);
@@ -825,6 +855,7 @@
return out;
}
using MslSampledtexturesTest = TestParamHelper<MslTextureData>;
+// MslPrinterSampledTexturesTest.Emit
TEST_P(MslSampledtexturesTest, Emit) {
auto params = GetParam();
@@ -850,6 +881,7 @@
MslTextureData{core::type::TextureDimension::kCubeArray,
"texturecube_array<float, access::sample>"}));
+// MslPrinterTest.Emit_TypeMultisampledTexture
TEST_F(MslASTPrinterTest, Emit_TypeMultisampledTexture) {
auto* u32 = create<core::type::U32>();
auto* ms = create<core::type::MultisampledTexture>(core::type::TextureDimension::k2d, u32);
@@ -871,6 +903,7 @@
return out << str.str();
}
using MslStorageTexturesTest = TestParamHelper<MslStorageTextureData>;
+// MslPrinterStorageTexturesTest.Emit
TEST_P(MslStorageTexturesTest, Emit) {
auto params = GetParam();
diff --git a/src/tint/lang/msl/writer/ast_printer/binary_test.cc b/src/tint/lang/msl/writer/ast_printer/binary_test.cc
index e3bf09c..70601fc 100644
--- a/src/tint/lang/msl/writer/ast_printer/binary_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/binary_test.cc
@@ -29,6 +29,8 @@
#include "src/tint/lang/msl/writer/ast_printer/helper_test.h"
#include "src/tint/utils/text/string_stream.h"
+// All ported to IR.
+
using namespace tint::core::fluent_types; // NOLINT
namespace tint::msl::writer {
@@ -44,6 +46,8 @@
out << str.str();
return out;
}
+
+// MSLPrinterBinaryTest.Emit
using MslBinaryTest = TestParamHelper<BinaryData>;
TEST_P(MslBinaryTest, Emit) {
auto params = GetParam();
@@ -89,6 +93,7 @@
BinaryData{"(left / right)", core::BinaryOp::kDivide},
BinaryData{"(left % right)", core::BinaryOp::kModulo}));
+// MSLPrinterBinaryTest_SignedOverflowDefinedBehaviour.Emit
using MslBinaryTest_SignedOverflowDefinedBehaviour = TestParamHelper<BinaryData>;
TEST_P(MslBinaryTest_SignedOverflowDefinedBehaviour, Emit) {
auto params = GetParam();
@@ -122,6 +127,7 @@
MslBinaryTest_SignedOverflowDefinedBehaviour,
testing::ValuesIn(signed_overflow_defined_behaviour_cases));
+// MSLPrinterBinaryTest_ShiftSignedOverflowDefinedBehaviour_Chained.Emit
using MslBinaryTest_SignedOverflowDefinedBehaviour_Chained = TestParamHelper<BinaryData>;
TEST_P(MslBinaryTest_SignedOverflowDefinedBehaviour_Chained, Emit) {
auto params = GetParam();
@@ -160,6 +166,7 @@
MslBinaryTest_SignedOverflowDefinedBehaviour_Chained,
testing::ValuesIn(signed_overflow_defined_behaviour_chained_cases));
+// MslPrinterTest.BinaryModF32
TEST_F(MslBinaryTest, ModF32) {
auto* left = Var("left", ty.f32());
auto* right = Var("right", ty.f32());
@@ -173,6 +180,7 @@
EXPECT_EQ(out.str(), "fmod(left, right)");
}
+// MslPrinterTest.BinaryModF16
TEST_F(MslBinaryTest, ModF16) {
Enable(wgsl::Extension::kF16);
@@ -188,6 +196,7 @@
EXPECT_EQ(out.str(), "fmod(left, right)");
}
+// MslBinaryTest.BinaryModVecF32
TEST_F(MslBinaryTest, ModVec3F32) {
auto* left = Var("left", ty.vec3<f32>());
auto* right = Var("right", ty.vec3<f32>());
@@ -201,6 +210,7 @@
EXPECT_EQ(out.str(), "fmod(left, right)");
}
+// MslPrinterTest.BinaryModVec3F16
TEST_F(MslBinaryTest, ModVec3F16) {
Enable(wgsl::Extension::kF16);
@@ -216,6 +226,7 @@
EXPECT_EQ(out.str(), "fmod(left, right)");
}
+// MslPrinterTest.BinaryBoolAnd
TEST_F(MslBinaryTest, BoolAnd) {
auto* left = Var("left", Expr(true));
auto* right = Var("right", Expr(false));
@@ -229,6 +240,7 @@
EXPECT_EQ(out.str(), "bool(left & right)");
}
+// MslPrinterTest.BinaryBoolOr
TEST_F(MslBinaryTest, BoolOr) {
auto* left = Var("left", Expr(true));
auto* right = Var("right", Expr(false));
diff --git a/src/tint/lang/msl/writer/ast_printer/discard_test.cc b/src/tint/lang/msl/writer/ast_printer/discard_test.cc
index f86373e..d1fdd53 100644
--- a/src/tint/lang/msl/writer/ast_printer/discard_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/discard_test.cc
@@ -32,6 +32,7 @@
using MslASTPrinterTest = TestHelper;
+// MslPrinterTest.Discard
TEST_F(MslASTPrinterTest, Emit_Discard) {
auto* stmt = Discard();
diff --git a/src/tint/lang/msl/writer/ast_printer/if_test.cc b/src/tint/lang/msl/writer/ast_printer/if_test.cc
index cc074e1..1f4a8f0 100644
--- a/src/tint/lang/msl/writer/ast_printer/if_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/if_test.cc
@@ -32,6 +32,7 @@
using MslASTPrinterTest = TestHelper;
+// MSLPrinterTest.If
TEST_F(MslASTPrinterTest, Emit_If) {
auto* cond = Var("cond", ty.bool_());
auto* i = If(cond, Block(Return()));
@@ -48,6 +49,7 @@
)");
}
+// MSLPrinterTest.IfWithElseIf
TEST_F(MslASTPrinterTest, Emit_IfWithElseIf) {
auto* cond = Var("cond", ty.bool_());
auto* else_cond = Var("else_cond", ty.bool_());
@@ -69,6 +71,7 @@
)");
}
+// MSLPrinterTest.IfWithElse
TEST_F(MslASTPrinterTest, Emit_IfWithElse) {
auto* cond = Var("cond", ty.bool_());
auto* i = If(cond, Block(Return()), Else(Block(Return())));
@@ -87,6 +90,7 @@
)");
}
+// TODO(dj2): Port to MSLPrinterTest
TEST_F(MslASTPrinterTest, Emit_IfWithMultiple) {
auto* cond = Var("cond", ty.bool_());
auto* else_cond = Var("else_cond", ty.bool_());
diff --git a/src/tint/lang/msl/writer/ast_printer/return_test.cc b/src/tint/lang/msl/writer/ast_printer/return_test.cc
index ac26018..4ea89a6 100644
--- a/src/tint/lang/msl/writer/ast_printer/return_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/return_test.cc
@@ -32,8 +32,11 @@
namespace tint::msl::writer {
namespace {
+// All ported to IR tests
+
using MslASTPrinterTest = TestHelper;
+// MslPrinterTest.Return
TEST_F(MslASTPrinterTest, Emit_Return) {
auto* r = Return();
WrapInFunction(r);
@@ -46,6 +49,7 @@
EXPECT_EQ(gen.Result(), " return;\n");
}
+// MslPrinterTest.ReturnWithValue
TEST_F(MslASTPrinterTest, Emit_ReturnWithValue) {
auto* r = Return(123_i);
Func("f", tint::Empty, ty.i32(), Vector{r});
diff --git a/src/tint/lang/msl/writer/ast_raise/BUILD.bazel b/src/tint/lang/msl/writer/ast_raise/BUILD.bazel
index a264fb7..8b2b905 100644
--- a/src/tint/lang/msl/writer/ast_raise/BUILD.bazel
+++ b/src/tint/lang/msl/writer/ast_raise/BUILD.bazel
@@ -59,6 +59,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
@@ -98,6 +99,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/msl/writer/ast_raise/BUILD.cmake b/src/tint/lang/msl/writer/ast_raise/BUILD.cmake
index f0a8790..93fb394 100644
--- a/src/tint/lang/msl/writer/ast_raise/BUILD.cmake
+++ b/src/tint/lang/msl/writer/ast_raise/BUILD.cmake
@@ -60,6 +60,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
@@ -102,6 +103,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
diff --git a/src/tint/lang/msl/writer/ast_raise/BUILD.gn b/src/tint/lang/msl/writer/ast_raise/BUILD.gn
index 6dff3c9..f5d025c 100644
--- a/src/tint/lang/msl/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/msl/writer/ast_raise/BUILD.gn
@@ -62,6 +62,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
@@ -102,6 +103,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/msl/writer/common/BUILD.bazel b/src/tint/lang/msl/writer/common/BUILD.bazel
index c8f2c0d..51256e7 100644
--- a/src/tint/lang/msl/writer/common/BUILD.bazel
+++ b/src/tint/lang/msl/writer/common/BUILD.bazel
@@ -61,6 +61,7 @@
"//src/tint/utils/math",
"//src/tint/utils/memory",
"//src/tint/utils/reflection",
+ "//src/tint/utils/result",
"//src/tint/utils/rtti",
"//src/tint/utils/strconv",
"//src/tint/utils/symbol",
diff --git a/src/tint/lang/msl/writer/common/BUILD.cmake b/src/tint/lang/msl/writer/common/BUILD.cmake
index 177f390..728427a 100644
--- a/src/tint/lang/msl/writer/common/BUILD.cmake
+++ b/src/tint/lang/msl/writer/common/BUILD.cmake
@@ -62,6 +62,7 @@
tint_utils_math
tint_utils_memory
tint_utils_reflection
+ tint_utils_result
tint_utils_rtti
tint_utils_strconv
tint_utils_symbol
diff --git a/src/tint/lang/msl/writer/common/BUILD.gn b/src/tint/lang/msl/writer/common/BUILD.gn
index 0ea4cc8..befabfe 100644
--- a/src/tint/lang/msl/writer/common/BUILD.gn
+++ b/src/tint/lang/msl/writer/common/BUILD.gn
@@ -64,6 +64,7 @@
"${tint_src_dir}/utils/math",
"${tint_src_dir}/utils/memory",
"${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
"${tint_src_dir}/utils/rtti",
"${tint_src_dir}/utils/strconv",
"${tint_src_dir}/utils/symbol",
diff --git a/src/tint/lang/msl/writer/common/option_helpers.cc b/src/tint/lang/msl/writer/common/option_helpers.cc
index cd44e5e..cda70c6 100644
--- a/src/tint/lang/msl/writer/common/option_helpers.cc
+++ b/src/tint/lang/msl/writer/common/option_helpers.cc
@@ -27,6 +27,8 @@
#include "src/tint/lang/msl/writer/common/option_helpers.h"
+#include <utility>
+
#include "src/tint/utils/containers/hashset.h"
namespace tint::msl::writer {
@@ -34,7 +36,9 @@
/// binding::BindingInfo to tint::BindingPoint map
using InfoToPointMap = tint::Hashmap<binding::BindingInfo, tint::BindingPoint, 8>;
-bool ValidateBindingOptions(const Options& options, diag::List& diagnostics) {
+Result<SuccessType> ValidateBindingOptions(const Options& options) {
+ diag::List diagnostics;
+
tint::Hashmap<tint::BindingPoint, binding::BindingInfo, 8> seen_wgsl_bindings{};
InfoToPointMap seen_msl_buffer_bindings{};
@@ -94,27 +98,27 @@
// Storage and uniform are both [[buffer()]]
if (!valid(seen_msl_buffer_bindings, options.bindings.uniform)) {
diagnostics.add_note(diag::System::Writer, "when processing uniform", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
if (!valid(seen_msl_buffer_bindings, options.bindings.storage)) {
diagnostics.add_note(diag::System::Writer, "when processing storage", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
// Sampler is [[sampler()]]
if (!valid(seen_msl_sampler_bindings, options.bindings.sampler)) {
diagnostics.add_note(diag::System::Writer, "when processing sampler", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
// Texture and storage texture are [[texture()]]
if (!valid(seen_msl_texture_bindings, options.bindings.texture)) {
diagnostics.add_note(diag::System::Writer, "when processing texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
if (!valid(seen_msl_texture_bindings, options.bindings.storage_texture)) {
diagnostics.add_note(diag::System::Writer, "when processing storage_texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
for (const auto& it : options.bindings.external_texture) {
@@ -126,26 +130,26 @@
// Validate with the actual source regardless of what the remapper will do
if (wgsl_seen(src_binding, plane0)) {
diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
// Plane0 & Plane1 are [[texture()]]
if (msl_seen(seen_msl_texture_bindings, plane0, src_binding)) {
diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
if (msl_seen(seen_msl_texture_bindings, plane1, src_binding)) {
diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
// Metadata is [[buffer()]]
if (msl_seen(seen_msl_buffer_bindings, metadata, src_binding)) {
diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
}
- return true;
+ return Success;
}
// The remapped binding data and external texture data need to coordinate in order to put things in
diff --git a/src/tint/lang/msl/writer/common/option_helpers.h b/src/tint/lang/msl/writer/common/option_helpers.h
index 1abf984..6f21fbd 100644
--- a/src/tint/lang/msl/writer/common/option_helpers.h
+++ b/src/tint/lang/msl/writer/common/option_helpers.h
@@ -34,6 +34,7 @@
#include "src/tint/api/options/external_texture.h"
#include "src/tint/lang/msl/writer/common/options.h"
#include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/result/result.h"
namespace tint::msl::writer {
@@ -41,9 +42,8 @@
using RemapperData = std::unordered_map<BindingPoint, BindingPoint>;
/// @param options the options
-/// @param diagnostics the diagnostics
-/// @returns true if the binding points are valid
-bool ValidateBindingOptions(const Options& options, diag::List& diagnostics);
+/// @returns success or failure
+Result<SuccessType> ValidateBindingOptions(const Options& options);
/// Populates data from the writer options for the remapper and external texture.
/// @param options the writer options
diff --git a/src/tint/lang/msl/writer/common/options.h b/src/tint/lang/msl/writer/common/options.h
index d085a66..66623d9 100644
--- a/src/tint/lang/msl/writer/common/options.h
+++ b/src/tint/lang/msl/writer/common/options.h
@@ -130,9 +130,6 @@
/// for all vertex shaders in the module.
bool emit_vertex_point_size = false;
- /// Set to `true` to generate MSL via the Tint IR instead of from the AST.
- bool use_tint_ir = false;
-
/// The index to use when generating a UBO to receive storage buffer sizes.
/// Defaults to 30, which is the last valid buffer slot.
uint32_t buffer_size_ubo_index = 30;
@@ -155,7 +152,6 @@
TINT_REFLECT(disable_robustness,
disable_workgroup_init,
emit_vertex_point_size,
- use_tint_ir,
buffer_size_ubo_index,
fixed_sample_mask,
pixel_local_options,
diff --git a/src/tint/lang/msl/writer/common/printer_support.cc b/src/tint/lang/msl/writer/common/printer_support.cc
index d9e74c4..037e54e 100644
--- a/src/tint/lang/msl/writer/common/printer_support.cc
+++ b/src/tint/lang/msl/writer/common/printer_support.cc
@@ -235,7 +235,7 @@
} else if (std::isnan(value)) {
out << "NAN";
} else {
- out << tint::writer::FloatToString(value) << "f";
+ out << tint::strconv::FloatToString(value) << "f";
}
}
@@ -249,7 +249,7 @@
// There is no NaN expr for half in MSL, "NAN" is of float type.
out << "NAN";
} else {
- out << tint::writer::FloatToString(value) << "h";
+ out << tint::strconv::FloatToString(value) << "h";
}
}
diff --git a/src/tint/lang/msl/writer/common/printer_support.h b/src/tint/lang/msl/writer/common/printer_support.h
index 3cb135e..dde098f 100644
--- a/src/tint/lang/msl/writer/common/printer_support.h
+++ b/src/tint/lang/msl/writer/common/printer_support.h
@@ -32,7 +32,8 @@
#include <string>
#include "src/tint/lang/core/builtin_value.h"
-#include "src/tint/lang/core/interpolation.h"
+#include "src/tint/lang/core/interpolation_sampling.h"
+#include "src/tint/lang/core/interpolation_type.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/utils/text/string_stream.h"
diff --git a/src/tint/lang/msl/writer/helpers/BUILD.bazel b/src/tint/lang/msl/writer/helpers/BUILD.bazel
index 095cd37..9d7a77b 100644
--- a/src/tint/lang/msl/writer/helpers/BUILD.bazel
+++ b/src/tint/lang/msl/writer/helpers/BUILD.bazel
@@ -52,6 +52,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/msl/writer/helpers/BUILD.cmake b/src/tint/lang/msl/writer/helpers/BUILD.cmake
index 1e27fed..9efd6c6 100644
--- a/src/tint/lang/msl/writer/helpers/BUILD.cmake
+++ b/src/tint/lang/msl/writer/helpers/BUILD.cmake
@@ -53,6 +53,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/msl/writer/helpers/BUILD.gn b/src/tint/lang/msl/writer/helpers/BUILD.gn
index 3b0713b..f1c9918 100644
--- a/src/tint/lang/msl/writer/helpers/BUILD.gn
+++ b/src/tint/lang/msl/writer/helpers/BUILD.gn
@@ -51,6 +51,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/msl/writer/output.cc b/src/tint/lang/msl/writer/output.cc
index ed184eb..cc2f3a0 100644
--- a/src/tint/lang/msl/writer/output.cc
+++ b/src/tint/lang/msl/writer/output.cc
@@ -35,4 +35,6 @@
Output::Output(const Output&) = default;
+Output& Output::operator=(const Output&) = default;
+
} // namespace tint::msl::writer
diff --git a/src/tint/lang/msl/writer/output.h b/src/tint/lang/msl/writer/output.h
index 6e873af..219e2a6 100644
--- a/src/tint/lang/msl/writer/output.h
+++ b/src/tint/lang/msl/writer/output.h
@@ -47,6 +47,10 @@
/// Copy constructor
Output(const Output&);
+ /// Copy assignment
+ /// @returns this
+ Output& operator=(const Output&);
+
/// The generated MSL.
std::string msl = "";
diff --git a/src/tint/lang/msl/writer/printer/BUILD.bazel b/src/tint/lang/msl/writer/printer/BUILD.bazel
index c72bc54..7de0377 100644
--- a/src/tint/lang/msl/writer/printer/BUILD.bazel
+++ b/src/tint/lang/msl/writer/printer/BUILD.bazel
@@ -48,6 +48,7 @@
"//src/tint/api/common",
"//src/tint/lang/core",
"//src/tint/lang/core/constant",
+ "//src/tint/lang/core/intrinsic",
"//src/tint/lang/core/ir",
"//src/tint/lang/core/type",
"//src/tint/utils/containers",
@@ -79,6 +80,7 @@
srcs = [
"binary_test.cc",
"constant_test.cc",
+ "discard_test.cc",
"function_test.cc",
"helper_test.h",
"if_test.cc",
@@ -89,12 +91,12 @@
],
deps = [
"//src/tint/api/common",
+ "//src/tint/api/options",
"//src/tint/lang/core",
"//src/tint/lang/core/constant",
"//src/tint/lang/core/intrinsic",
"//src/tint/lang/core/ir",
"//src/tint/lang/core/type",
- "//src/tint/lang/msl/writer/raise",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
"//src/tint/utils/ice",
@@ -111,7 +113,9 @@
"@gtest",
] + select({
":tint_build_msl_writer": [
+ "//src/tint/lang/msl/writer/common",
"//src/tint/lang/msl/writer/printer",
+ "//src/tint/lang/msl/writer/raise",
],
"//conditions:default": [],
}),
diff --git a/src/tint/lang/msl/writer/printer/BUILD.cmake b/src/tint/lang/msl/writer/printer/BUILD.cmake
index 8992d6c..37d0fcb 100644
--- a/src/tint/lang/msl/writer/printer/BUILD.cmake
+++ b/src/tint/lang/msl/writer/printer/BUILD.cmake
@@ -49,6 +49,7 @@
tint_api_common
tint_lang_core
tint_lang_core_constant
+ tint_lang_core_intrinsic
tint_lang_core_ir
tint_lang_core_type
tint_utils_containers
@@ -83,6 +84,7 @@
tint_add_target(tint_lang_msl_writer_printer_test test
lang/msl/writer/printer/binary_test.cc
lang/msl/writer/printer/constant_test.cc
+ lang/msl/writer/printer/discard_test.cc
lang/msl/writer/printer/function_test.cc
lang/msl/writer/printer/helper_test.h
lang/msl/writer/printer/if_test.cc
@@ -94,12 +96,12 @@
tint_target_add_dependencies(tint_lang_msl_writer_printer_test test
tint_api_common
+ tint_api_options
tint_lang_core
tint_lang_core_constant
tint_lang_core_intrinsic
tint_lang_core_ir
tint_lang_core_type
- tint_lang_msl_writer_raise
tint_utils_containers
tint_utils_diagnostic
tint_utils_ice
@@ -121,7 +123,9 @@
if(TINT_BUILD_MSL_WRITER)
tint_target_add_dependencies(tint_lang_msl_writer_printer_test test
+ tint_lang_msl_writer_common
tint_lang_msl_writer_printer
+ tint_lang_msl_writer_raise
)
endif(TINT_BUILD_MSL_WRITER)
diff --git a/src/tint/lang/msl/writer/printer/BUILD.gn b/src/tint/lang/msl/writer/printer/BUILD.gn
index bfd0975..ce460cc 100644
--- a/src/tint/lang/msl/writer/printer/BUILD.gn
+++ b/src/tint/lang/msl/writer/printer/BUILD.gn
@@ -51,6 +51,7 @@
"${tint_src_dir}/api/common",
"${tint_src_dir}/lang/core",
"${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/intrinsic",
"${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/utils/containers",
@@ -80,6 +81,7 @@
sources = [
"binary_test.cc",
"constant_test.cc",
+ "discard_test.cc",
"function_test.cc",
"helper_test.h",
"if_test.cc",
@@ -91,12 +93,12 @@
deps = [
"${tint_src_dir}:gmock_and_gtest",
"${tint_src_dir}/api/common",
+ "${tint_src_dir}/api/options",
"${tint_src_dir}/lang/core",
"${tint_src_dir}/lang/core/constant",
"${tint_src_dir}/lang/core/intrinsic",
"${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/type",
- "${tint_src_dir}/lang/msl/writer/raise",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
"${tint_src_dir}/utils/ice",
@@ -113,7 +115,11 @@
]
if (tint_build_msl_writer) {
- deps += [ "${tint_src_dir}/lang/msl/writer/printer" ]
+ deps += [
+ "${tint_src_dir}/lang/msl/writer/common",
+ "${tint_src_dir}/lang/msl/writer/printer",
+ "${tint_src_dir}/lang/msl/writer/raise",
+ ]
}
}
}
diff --git a/src/tint/lang/msl/writer/printer/binary_test.cc b/src/tint/lang/msl/writer/printer/binary_test.cc
index 8f87403..74808bf 100644
--- a/src/tint/lang/msl/writer/printer/binary_test.cc
+++ b/src/tint/lang/msl/writer/printer/binary_test.cc
@@ -76,13 +76,96 @@
testing::Values(BinaryData{"(left + right)", core::ir::BinaryOp::kAdd},
BinaryData{"(left - right)", core::ir::BinaryOp::kSubtract},
BinaryData{"(left * right)", core::ir::BinaryOp::kMultiply},
- BinaryData{"(left / right)", core::ir::BinaryOp::kDivide},
- BinaryData{"(left % right)", core::ir::BinaryOp::kModulo},
BinaryData{"(left & right)", core::ir::BinaryOp::kAnd},
BinaryData{"(left | right)", core::ir::BinaryOp::kOr},
- BinaryData{"(left ^ right)", core::ir::BinaryOp::kXor},
- BinaryData{"(left << right)", core::ir::BinaryOp::kShiftLeft},
- BinaryData{"(left >> right)", core::ir::BinaryOp::kShiftRight}));
+ BinaryData{"(left ^ right)", core::ir::BinaryOp::kXor}));
+
+TEST_F(MslPrinterTest, BinaryDivU32) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* l = b.Let("left", b.Constant(1_u));
+ auto* r = b.Let("right", b.Constant(2_u));
+ auto* bin = b.Binary(core::ir::BinaryOp::kDivide, ty.u32(), l, r);
+ b.Let("val", bin);
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_;
+ EXPECT_EQ(output_, MetalHeader() + R"(
+void foo() {
+ uint const left = 1u;
+ uint const right = 2u;
+ uint const val = tint_div_u32(left, right);
+}
+uint tint_div_u32(uint lhs, uint rhs) {
+ return (lhs / select(rhs, 1u, (rhs == 0u)));
+}
+)");
+}
+
+TEST_F(MslPrinterTest, BinaryModU32) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* l = b.Let("left", b.Constant(1_u));
+ auto* r = b.Let("right", b.Constant(2_u));
+ auto* bin = b.Binary(core::ir::BinaryOp::kModulo, ty.u32(), l, r);
+ b.Let("val", bin);
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_;
+ EXPECT_EQ(output_, MetalHeader() + R"(
+void foo() {
+ uint const left = 1u;
+ uint const right = 2u;
+ uint const val = tint_mod_u32(left, right);
+}
+uint tint_mod_u32(uint lhs, uint rhs) {
+ uint const v = select(rhs, 1u, (rhs == 0u));
+ return (lhs - ((lhs / v) * v));
+}
+)");
+}
+
+TEST_F(MslPrinterTest, BinaryShiftLeft) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* l = b.Let("left", b.Constant(1_u));
+ auto* r = b.Let("right", b.Constant(2_u));
+ auto* bin = b.Binary(core::ir::BinaryOp::kShiftLeft, ty.u32(), l, r);
+ b.Let("val", bin);
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_;
+ EXPECT_EQ(output_, MetalHeader() + R"(
+void foo() {
+ uint const left = 1u;
+ uint const right = 2u;
+ uint const val = (left << (right & 31u));
+}
+)");
+}
+
+TEST_F(MslPrinterTest, BinaryShiftRight) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* l = b.Let("left", b.Constant(1_u));
+ auto* r = b.Let("right", b.Constant(2_u));
+ auto* bin = b.Binary(core::ir::BinaryOp::kShiftRight, ty.u32(), l, r);
+ b.Let("val", bin);
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_;
+ EXPECT_EQ(output_, MetalHeader() + R"(
+void foo() {
+ uint const left = 1u;
+ uint const right = 2u;
+ uint const val = (left >> (right & 31u));
+}
+)");
+}
using MslPrinterBinaryBoolTest = MslPrinterTestWithParam<BinaryData>;
TEST_P(MslPrinterBinaryBoolTest, Emit) {
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/lang/msl/writer/printer/discard_test.cc
similarity index 61%
copy from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
copy to src/tint/lang/msl/writer/printer/discard_test.cc
index 6f0f657..64451a3 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/lang/msl/writer/printer/discard_test.cc
@@ -25,28 +25,47 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
-#define SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#include "src/tint/lang/msl/writer/printer/helper_test.h"
-#include <string>
+using namespace tint::core::number_suffixes; // NOLINT
-#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/result/result.h"
+namespace tint::msl::writer {
+namespace {
-// Forward declarations.
-namespace tint::core::ir {
-class Module;
+TEST_F(MslPrinterTest, Discard) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* if_ = b.If(true);
+ b.Append(if_->True(), [&] {
+ b.Discard();
+ b.ExitIf(if_);
+ });
+ b.Return(func);
+ });
+
+ auto* ep = b.Function("main", ty.void_());
+ ep->SetStage(core::ir::Function::PipelineStage::kFragment);
+ b.Append(ep->Block(), [&] {
+ b.Call(func);
+ b.Return(ep);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_;
+ EXPECT_EQ(output_, MetalHeader() + R"(
+thread bool continue_execution = true;
+void foo() {
+ if (true) {
+ continue_execution = false;
+ }
+}
+fragment void main() {
+ foo();
+ if (!(continue_execution)) {
+ discard_fragment();
+ }
+}
+)");
}
-namespace tint::wgsl::writer {
-
-/// RenameConflicts is a transform that renames declarations which prevent identifiers from
-/// resolving to the correct declaration, and those with identical identifiers declared in the same
-/// scope.
-/// @param module the module to transform
-/// @returns success or failure
-Result<SuccessType> RenameConflicts(core::ir::Module* module);
-
-} // namespace tint::wgsl::writer
-
-#endif // SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+} // namespace
+} // namespace tint::msl::writer
diff --git a/src/tint/lang/msl/writer/printer/helper_test.h b/src/tint/lang/msl/writer/printer/helper_test.h
index f77774b..bf14aa6 100644
--- a/src/tint/lang/msl/writer/printer/helper_test.h
+++ b/src/tint/lang/msl/writer/printer/helper_test.h
@@ -80,7 +80,7 @@
/// Run the writer on the IR module and validate the result.
/// @returns true if generation and validation succeeded
bool Generate() {
- if (auto raised = raise::Raise(mod); !raised) {
+ if (auto raised = raise::Raise(mod, {}); !raised) {
err_ = raised.Failure().reason.str();
return false;
}
diff --git a/src/tint/lang/msl/writer/printer/if_test.cc b/src/tint/lang/msl/writer/printer/if_test.cc
index 5892a86..2f1a583 100644
--- a/src/tint/lang/msl/writer/printer/if_test.cc
+++ b/src/tint/lang/msl/writer/printer/if_test.cc
@@ -116,7 +116,8 @@
)");
}
-TEST_F(MslPrinterTest, IfWithSinglePhi) {
+// Requires a transform to turn PHIs into lets
+TEST_F(MslPrinterTest, DISABLED_IfWithSinglePhi) {
auto* func = b.Function("foo", ty.void_());
b.Append(func->Block(), [&] {
auto* i = b.If(true);
@@ -143,7 +144,8 @@
)");
}
-TEST_F(MslPrinterTest, IfWithMultiPhi) {
+// Requires a transform to turn PHIs into lets
+TEST_F(MslPrinterTest, DISABLED_IfWithMultiPhi) {
auto* func = b.Function("foo", ty.void_());
b.Append(func->Block(), [&] {
auto* i = b.If(true);
@@ -173,7 +175,8 @@
)");
}
-TEST_F(MslPrinterTest, IfWithMultiPhiReturn1) {
+// Requires a transform to turn PHIs into lets
+TEST_F(MslPrinterTest, DISABLED_IfWithMultiPhiReturn1) {
auto* func = b.Function("foo", ty.i32());
b.Append(func->Block(), [&] {
auto* i = b.If(true);
@@ -204,7 +207,8 @@
)");
}
-TEST_F(MslPrinterTest, IfWithMultiPhiReturn2) {
+// Requires a transform to turn PHIs into lets
+TEST_F(MslPrinterTest, DISABLED_IfWithMultiPhiReturn2) {
auto* func = b.Function("foo", ty.bool_());
b.Append(func->Block(), [&] {
auto* i = b.If(true);
diff --git a/src/tint/lang/msl/writer/printer/printer.cc b/src/tint/lang/msl/writer/printer/printer.cc
index 02fb9c5..2ededba 100644
--- a/src/tint/lang/msl/writer/printer/printer.cc
+++ b/src/tint/lang/msl/writer/printer/printer.cc
@@ -34,16 +34,35 @@
#include "src/tint/lang/core/constant/composite.h"
#include "src/tint/lang/core/constant/splat.h"
#include "src/tint/lang/core/fluent_types.h"
+#include "src/tint/lang/core/ir/access.h"
#include "src/tint/lang/core/ir/binary.h"
+#include "src/tint/lang/core/ir/bitcast.h"
+#include "src/tint/lang/core/ir/break_if.h"
#include "src/tint/lang/core/ir/constant.h"
+#include "src/tint/lang/core/ir/construct.h"
+#include "src/tint/lang/core/ir/continue.h"
+#include "src/tint/lang/core/ir/convert.h"
+#include "src/tint/lang/core/ir/core_builtin_call.h"
+#include "src/tint/lang/core/ir/discard.h"
#include "src/tint/lang/core/ir/exit_if.h"
+#include "src/tint/lang/core/ir/exit_loop.h"
+#include "src/tint/lang/core/ir/exit_switch.h"
+#include "src/tint/lang/core/ir/ice.h"
#include "src/tint/lang/core/ir/if.h"
#include "src/tint/lang/core/ir/let.h"
#include "src/tint/lang/core/ir/load.h"
+#include "src/tint/lang/core/ir/load_vector_element.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/core/ir/multi_in_block.h"
+#include "src/tint/lang/core/ir/next_iteration.h"
#include "src/tint/lang/core/ir/return.h"
+#include "src/tint/lang/core/ir/store.h"
+#include "src/tint/lang/core/ir/store_vector_element.h"
+#include "src/tint/lang/core/ir/switch.h"
+#include "src/tint/lang/core/ir/swizzle.h"
+#include "src/tint/lang/core/ir/terminate_invocation.h"
#include "src/tint/lang/core/ir/unreachable.h"
+#include "src/tint/lang/core/ir/user_call.h"
#include "src/tint/lang/core/ir/validator.h"
#include "src/tint/lang/core/ir/var.h"
#include "src/tint/lang/core/type/array.h"
@@ -100,7 +119,7 @@
EmitBlockInstructions(ir_.root_block);
// Emit functions.
- for (auto* func : ir_.functions) {
+ for (auto& func : ir_.functions) {
EmitFunction(func);
}
@@ -115,6 +134,9 @@
core::ir::Module& ir_;
+ /// A hashmap of value to name
+ Hashmap<const core::ir::Value*, std::string, 32> names_;
+
/// The buffer holding preamble text
TextBuffer preamble_buffer_;
@@ -164,6 +186,9 @@
/// Values that can be inlined.
Hashset<core::ir::Value*, 64> can_inline_;
+ /// Block to emit for a continuing
+ std::function<void()> emit_continuing_;
+
/// @returns the name of the templated `tint_array` helper type, generating it if needed
const std::string& ArrayTemplateName() {
if (!array_template_name_.empty()) {
@@ -202,13 +227,83 @@
{
auto out = Line();
- // TODO(dsinclair): Emit function stage if any
+ switch (func->Stage()) {
+ case core::ir::Function::PipelineStage::kCompute:
+ out << "kernel ";
+ break;
+ case core::ir::Function::PipelineStage::kFragment:
+ out << "fragment ";
+ break;
+ case core::ir::Function::PipelineStage::kVertex:
+ out << "vertex ";
+ break;
+ case core::ir::Function::PipelineStage::kUndefined:
+ break;
+ }
+
// TODO(dsinclair): Handle return type attributes
EmitType(out, func->ReturnType());
- out << " " << ir_.NameOf(func).Name() << "() {";
+ out << " " << NameOf(func) << "(";
- // TODO(dsinclair): Emit Function parameters
+ size_t i = 0;
+ for (auto* param : func->Params()) {
+ if (i > 0) {
+ out << ", ";
+ }
+ ++i;
+
+ // TODO(dsinclair): Handle parameter attributes
+ EmitType(out, param->Type());
+ out << " ";
+
+ // Non-entrypoint pointers are set to `const` for the value
+ if (func->Stage() == core::ir::Function::PipelineStage::kUndefined &&
+ param->Type()->Is<core::type::Pointer>()) {
+ out << "const ";
+ }
+
+ out << NameOf(param);
+
+ if (param->Builtin().has_value()) {
+ out << " [[";
+ switch (param->Builtin().value()) {
+ case core::ir::FunctionParam::Builtin::kFrontFacing:
+ out << "front_facing";
+ break;
+ case core::ir::FunctionParam::Builtin::kGlobalInvocationId:
+ out << "thread_position_in_grid";
+ break;
+ case core::ir::FunctionParam::Builtin::kLocalInvocationId:
+ out << "thread_position_in_threadgroup";
+ break;
+ case core::ir::FunctionParam::Builtin::kLocalInvocationIndex:
+ out << "thread_index_in_threadgroup";
+ break;
+ case core::ir::FunctionParam::Builtin::kNumWorkgroups:
+ out << "threadgroups_per_grid";
+ break;
+ case core::ir::FunctionParam::Builtin::kPosition:
+ out << "position";
+ break;
+ case core::ir::FunctionParam::Builtin::kSampleIndex:
+ out << "sample_id";
+ break;
+ case core::ir::FunctionParam::Builtin::kSampleMask:
+ out << "sample_mask";
+ break;
+ case core::ir::FunctionParam::Builtin::kWorkgroupId:
+ out << "threadgroup_position_in_grid";
+ break;
+
+ default:
+ break;
+ }
+ out << "]]";
+ }
+ }
+
+ out << ") {";
}
{
ScopedIndent si(current_buffer_);
@@ -220,11 +315,7 @@
/// Emit a block
/// @param block the block to emit
- void EmitBlock(core::ir::Block* block) {
- MarkInlinable(block);
-
- EmitBlockInstructions(block);
- }
+ void EmitBlock(core::ir::Block* block) { EmitBlockInstructions(block); }
/// Emit the instructions in a block
/// @param block the block with the instructions to emit
@@ -234,27 +325,90 @@
for (auto* inst : *block) {
Switch(
inst, //
- [&](core::ir::Binary* b) { EmitBinary(b); }, //
- [&](core::ir::ExitIf* e) { EmitExitIf(e); }, //
- [&](core::ir::If* if_) { EmitIf(if_); }, //
- [&](core::ir::Let* l) { EmitLet(l); }, //
- [&](core::ir::Load* l) { EmitLoad(l); }, //
- [&](core::ir::Return* r) { EmitReturn(r); }, //
+ [&](core::ir::BreakIf* i) { EmitBreakIf(i); }, //
+ [&](core::ir::Continue*) { EmitContinue(); }, //
+ [&](core::ir::Discard*) { EmitDiscard(); }, //
+ [&](core::ir::ExitIf* i) { EmitExitIf(i); }, //
+ [&](core::ir::ExitLoop*) { EmitExitLoop(); }, //
+ [&](core::ir::ExitSwitch*) { EmitExitSwitch(); }, //
+ [&](core::ir::If* i) { EmitIf(i); }, //
+ [&](core::ir::Let* i) { EmitLet(i); }, //
+ [&](core::ir::Loop* i) { EmitLoop(i); }, //
+ [&](core::ir::NextIteration*) { /* do nothing */ }, //
+ [&](core::ir::Return* i) { EmitReturn(i); }, //
+ [&](core::ir::Store* i) { EmitStore(i); }, //
+ [&](core::ir::Switch* i) { EmitSwitch(i); }, //
[&](core::ir::Unreachable*) { EmitUnreachable(); }, //
- [&](core::ir::Var* v) { EmitVar(v); }, //
+ [&](core::ir::Call* i) { EmitCallStmt(i); }, //
+ [&](core::ir::Var* i) { EmitVar(i); }, //
+ [&](core::ir::StoreVectorElement* e) { EmitStoreVectorElement(e); },
+ [&](core::ir::TerminateInvocation*) { EmitDiscard(); }, //
+
+ [&](core::ir::LoadVectorElement*) { /* inlined */ }, //
+ [&](core::ir::Swizzle*) { /* inlined */ }, //
+ [&](core::ir::Bitcast*) { /* inlined */ }, //
+ [&](core::ir::Unary*) { /* inlined */ }, //
+ [&](core::ir::Binary*) { /* inlined */ }, //
+ [&](core::ir::Load*) { /* inlined */ }, //
+ [&](core::ir::Construct*) { /* inlined */ }, //
+ [&](core::ir::Access*) { /* inlined */ }, //
TINT_ICE_ON_NO_MATCH);
}
}
+ void EmitValue(StringStream& out, const core::ir::Value* v) {
+ Switch(
+ v, //
+ [&](const core::ir::Constant* c) { EmitConstant(out, c); }, //
+ [&](const core::ir::InstructionResult* r) {
+ Switch(
+ r->Instruction(), //
+ [&](const core::ir::Unary* u) { EmitUnary(out, u); }, //
+ [&](const core::ir::Binary* b) { EmitBinary(out, b); }, //
+ [&](const core::ir::Convert* b) { EmitConvert(out, b); }, //
+ [&](const core::ir::Let* l) { out << NameOf(l->Result(0)); }, //
+ [&](const core::ir::Load* l) { EmitValue(out, l->From()); }, //
+ [&](const core::ir::Construct* c) { EmitConstruct(out, c); }, //
+ [&](const core::ir::Var* var) { out << NameOf(var->Result(0)); }, //
+ [&](const core::ir::Bitcast* b) { EmitBitcast(out, b); }, //
+ [&](const core::ir::Access* a) { EmitAccess(out, a); }, //
+ [&](const core::ir::CoreBuiltinCall* c) { EmitCoreBuiltinCall(out, c); }, //
+ [&](const core::ir::UserCall* c) { EmitUserCall(out, c); }, //
+ [&](const core::ir::LoadVectorElement* e) {
+ EmitLoadVectorElement(out, e);
+ }, //
+ [&](const core::ir::Swizzle* s) { EmitSwizzle(out, s); }, //
+ TINT_ICE_ON_NO_MATCH);
+ }, //
+ [&](const core::ir::FunctionParam* p) { out << NameOf(p); }, //
+ TINT_ICE_ON_NO_MATCH);
+ }
+
+ void EmitUnary(StringStream& out, const core::ir::Unary* u) {
+ switch (u->Op()) {
+ case core::ir::UnaryOp::kNegation:
+ out << "-";
+ break;
+ case core::ir::UnaryOp::kComplement:
+ out << "~";
+ break;
+ }
+ out << "(";
+ EmitValue(out, u->Val());
+ out << ")";
+ }
+
/// Emit a binary instruction
/// @param b the binary instruction
- void EmitBinary(core::ir::Binary* b) {
+ void EmitBinary(StringStream& out, const core::ir::Binary* b) {
if (b->Op() == core::ir::BinaryOp::kEqual) {
auto* rhs = b->RHS()->As<core::ir::Constant>();
if (rhs && rhs->Type()->Is<core::type::Bool>() &&
rhs->Value()->ValueAs<bool>() == false) {
// expr == false
- Bind(b->Result(), "!(" + Expr(b->LHS()) + ")");
+ out << "!(";
+ EmitValue(out, b->LHS());
+ out << ")";
return;
}
}
@@ -297,17 +451,20 @@
return "<error>";
};
- StringStream str;
- str << "(" << Expr(b->LHS()) << " " << kind() << " " + Expr(b->RHS()) << ")";
-
- Bind(b->Result(), str.str());
+ out << "(";
+ EmitValue(out, b->LHS());
+ out << " " << kind() << " ";
+ EmitValue(out, b->RHS());
+ out << ")";
}
- /// Emit a load instruction
- /// @param l the load instruction
- void EmitLoad(core::ir::Load* l) {
- // Force loads to be bound as inlines
- bindings_.Add(l->Result(), InlinedValue{Expr(l->From()), PtrKind::kRef});
+ /// Emit a convert instruction
+ /// @param c the convert instruction
+ void EmitConvert(StringStream& out, const core::ir::Convert* c) {
+ EmitType(out, c->Result(0)->Type());
+ out << "(";
+ EmitValue(out, c->Operand(0));
+ out << ")";
}
/// Emit a var instruction
@@ -315,7 +472,7 @@
void EmitVar(core::ir::Var* v) {
auto out = Line();
- auto* ptr = v->Result()->Type()->As<core::type::Pointer>();
+ auto* ptr = v->Result(0)->Type()->As<core::type::Pointer>();
TINT_ASSERT_OR_RETURN(ptr);
auto space = ptr->AddressSpace();
@@ -330,17 +487,16 @@
out << "threadgroup ";
break;
default:
- TINT_ICE() << "unhandled variable address space";
+ TINT_IR_ICE(ir_) << "unhandled variable address space";
return;
}
- auto name = ir_.NameOf(v);
-
EmitType(out, ptr->UnwrapPtr());
- out << " " << name.Name();
+ out << " " << NameOf(v->Result(0));
if (v->Initializer()) {
- out << " = " << Expr(v->Initializer());
+ out << " = ";
+ EmitValue(out, v->Initializer());
} else if (space == core::AddressSpace::kPrivate ||
space == core::AddressSpace::kFunction ||
space == core::AddressSpace::kUndefined) {
@@ -348,36 +504,147 @@
EmitZeroValue(out, ptr->UnwrapPtr());
}
out << ";";
-
- Bind(v->Result(), name, PtrKind::kRef);
}
/// Emit a let instruction
/// @param l the let instruction
void EmitLet(core::ir::Let* l) {
- Bind(l->Result(), Expr(l->Value(), PtrKind::kPtr), PtrKind::kPtr);
+ auto out = Line();
+ EmitType(out, l->Result(0)->Type());
+ out << " const " << NameOf(l->Result(0)) << " = ";
+ EmitValue(out, l->Value());
+ out << ";";
+ }
+
+ void EmitExitLoop() { Line() << "break;"; }
+
+ void EmitBreakIf(core::ir::BreakIf* b) {
+ auto out = Line();
+ out << "if ";
+ EmitValue(out, b->Condition());
+ out << " { break; }";
+ }
+
+ void EmitContinue() {
+ if (emit_continuing_) {
+ emit_continuing_();
+ }
+ Line() << "continue;";
+ }
+
+ void EmitLoop(core::ir::Loop* l) {
+ // Note, we can't just emit the continuing inside a conditional at the top of the loop
+ // because any variable declared in the block must be visible to the continuing.
+ //
+ // loop {
+ // var a = 3;
+ // continue {
+ // let y = a;
+ // }
+ // }
+
+ auto emit_continuing = [&] { EmitBlock(l->Continuing()); };
+ TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
+
+ Line() << "{";
+ {
+ ScopedIndent init(current_buffer_);
+ EmitBlock(l->Initializer());
+
+ Line() << "while(true) {";
+ {
+ ScopedIndent si(current_buffer_);
+ EmitBlock(l->Body());
+ }
+ Line() << "}";
+ }
+ Line() << "}";
+ }
+
+ void EmitExitSwitch() { Line() << "break;"; }
+
+ void EmitSwitch(core::ir::Switch* s) {
+ {
+ auto out = Line();
+ out << "switch(";
+ EmitValue(out, s->Condition());
+ out << ") {";
+ }
+ {
+ ScopedIndent blk(current_buffer_);
+ for (auto& case_ : s->Cases()) {
+ for (auto& sel : case_.selectors) {
+ if (sel.IsDefault()) {
+ Line() << "default:";
+ } else {
+ auto out = Line();
+ out << "case ";
+ EmitValue(out, sel.val);
+ out << ":";
+ }
+ }
+ Line() << "{";
+ {
+ ScopedIndent ci(current_buffer_);
+ EmitBlock(case_.block);
+ }
+ Line() << "}";
+ }
+ }
+ Line() << "}";
+ }
+
+ void EmitSwizzle(StringStream& out, const core::ir::Swizzle* swizzle) {
+ EmitValue(out, swizzle->Object());
+ out << ".";
+ for (const auto i : swizzle->Indices()) {
+ switch (i) {
+ case 0:
+ out << "x";
+ break;
+ case 1:
+ out << "y";
+ break;
+ case 2:
+ out << "z";
+ break;
+ case 3:
+ out << "w";
+ break;
+ default:
+ TINT_UNREACHABLE();
+ }
+ }
+ }
+
+ void EmitStoreVectorElement(const core::ir::StoreVectorElement* l) {
+ auto out = Line();
+
+ EmitValue(out, l->To());
+ out << "[";
+ EmitValue(out, l->Index());
+ out << "] = ";
+ EmitValue(out, l->Value());
+ out << ";";
+ }
+
+ void EmitLoadVectorElement(StringStream& out, const core::ir::LoadVectorElement* l) {
+ EmitValue(out, l->From());
+ out << "[";
+ EmitValue(out, l->Index());
+ out << "]";
}
/// Emit an if instruction
/// @param if_ the if instruction
void EmitIf(core::ir::If* if_) {
- // Emit any nodes that need to be used as PHI nodes
- for (auto* phi : if_->Results()) {
- if (!ir_.NameOf(phi).IsValid()) {
- ir_.SetName(phi, ir_.symbols.New());
- }
-
- auto name = ir_.NameOf(phi);
-
+ {
auto out = Line();
- EmitType(out, phi->Type());
- out << " " << name.Name() << ";";
-
- Bind(phi, name);
+ out << "if (";
+ EmitValue(out, if_->Condition());
+ out << ") {";
}
- Line() << "if (" << Expr(if_->Condition()) << ") {";
-
{
ScopedIndent si(current_buffer_);
EmitBlockInstructions(if_->True());
@@ -402,7 +669,10 @@
auto* phi = results[i];
auto* val = args[i];
- Line() << ir_.NameOf(phi).Name() << " = " << Expr(val) << ";";
+ auto out = Line();
+ out << NameOf(phi) << " = ";
+ EmitValue(out, val);
+ out << ";";
}
}
@@ -418,7 +688,8 @@
auto out = Line();
out << "return";
if (!r->Args().IsEmpty()) {
- out << " " << Expr(r->Args().Front());
+ out << " ";
+ EmitValue(out, r->Args().Front());
}
out << ";";
}
@@ -426,6 +697,257 @@
/// Emit an unreachable instruction
void EmitUnreachable() { Line() << "/* unreachable */"; }
+ /// Emit a discard instruction
+ void EmitDiscard() { Line() << "discard_fragment();"; }
+
+ /// Emit a store
+ void EmitStore(core::ir::Store* s) {
+ auto out = Line();
+
+ EmitValue(out, s->To());
+ out << " = ";
+ EmitValue(out, s->From());
+ out << ";";
+ }
+
+ /// Emit a bitcast instruction
+ void EmitBitcast(StringStream& out, const core::ir::Bitcast* b) {
+ out << "as_type<";
+ EmitType(out, b->Result(0)->Type());
+ out << ">(";
+ EmitValue(out, b->Val());
+ out << ")";
+ }
+
+ /// Emit an accessor
+ void EmitAccess(StringStream& out, const core::ir::Access* a) {
+ EmitValue(out, a->Object());
+
+ auto* current_type = a->Object()->Type();
+ for (auto* index : a->Indices()) {
+ TINT_ASSERT(current_type);
+
+ current_type = current_type->UnwrapPtr();
+ Switch(
+ current_type, //
+ [&](const core::type::Struct* s) {
+ auto* c = index->As<core::ir::Constant>();
+ auto* member = s->Members()[c->Value()->ValueAs<uint32_t>()];
+ out << "." << member->Name().Name();
+ current_type = member->Type();
+ },
+ [&](Default) {
+ out << "[";
+ EmitValue(out, index);
+ out << "]";
+ current_type = current_type->Element(0);
+ });
+ }
+ }
+
+ void EmitCallStmt(const core::ir::Call* c) {
+ if (!c->Result(0)->IsUsed()) {
+ auto out = Line();
+ EmitValue(out, c->Result(0));
+ out << ";";
+ }
+ }
+
+ void EmitCoreBuiltinCall(StringStream& out, const core::ir::CoreBuiltinCall* c) {
+ EmitCoreBuiltinName(out, c->Func());
+ out << "(";
+
+ size_t i = 0;
+ for (const auto* arg : c->Args()) {
+ if (i > 0) {
+ out << ", ";
+ }
+ ++i;
+
+ EmitValue(out, arg);
+ }
+ out << ")";
+ }
+
+ void EmitCoreBuiltinName(StringStream& out, core::BuiltinFn func) {
+ switch (func) {
+ case core::BuiltinFn::kAcos:
+ case core::BuiltinFn::kAcosh:
+ case core::BuiltinFn::kAll:
+ case core::BuiltinFn::kAny:
+ case core::BuiltinFn::kAsin:
+ case core::BuiltinFn::kAsinh:
+ case core::BuiltinFn::kAtan2:
+ case core::BuiltinFn::kAtan:
+ case core::BuiltinFn::kAtanh:
+ case core::BuiltinFn::kCeil:
+ case core::BuiltinFn::kClamp:
+ case core::BuiltinFn::kCos:
+ case core::BuiltinFn::kCosh:
+ case core::BuiltinFn::kCross:
+ case core::BuiltinFn::kDeterminant:
+ case core::BuiltinFn::kExp2:
+ case core::BuiltinFn::kExp:
+ case core::BuiltinFn::kFloor:
+ case core::BuiltinFn::kFma:
+ case core::BuiltinFn::kFract:
+ case core::BuiltinFn::kLdexp:
+ case core::BuiltinFn::kLog2:
+ case core::BuiltinFn::kLog:
+ case core::BuiltinFn::kMix:
+ case core::BuiltinFn::kNormalize:
+ case core::BuiltinFn::kPow:
+ case core::BuiltinFn::kReflect:
+ case core::BuiltinFn::kRefract:
+ case core::BuiltinFn::kSaturate:
+ case core::BuiltinFn::kSelect:
+ case core::BuiltinFn::kSign:
+ case core::BuiltinFn::kSin:
+ case core::BuiltinFn::kSinh:
+ case core::BuiltinFn::kSqrt:
+ case core::BuiltinFn::kStep:
+ case core::BuiltinFn::kTan:
+ case core::BuiltinFn::kTanh:
+ case core::BuiltinFn::kTranspose:
+ case core::BuiltinFn::kTrunc:
+ out << func;
+ break;
+ case core::BuiltinFn::kCountLeadingZeros:
+ out << "clz";
+ break;
+ case core::BuiltinFn::kCountOneBits:
+ out << "popcount";
+ break;
+ case core::BuiltinFn::kCountTrailingZeros:
+ out << "ctz";
+ break;
+ case core::BuiltinFn::kDpdx:
+ case core::BuiltinFn::kDpdxCoarse:
+ case core::BuiltinFn::kDpdxFine:
+ out << "dfdx";
+ break;
+ case core::BuiltinFn::kDpdy:
+ case core::BuiltinFn::kDpdyCoarse:
+ case core::BuiltinFn::kDpdyFine:
+ out << "dfdy";
+ break;
+ case core::BuiltinFn::kExtractBits:
+ out << "extract_bits";
+ break;
+ case core::BuiltinFn::kInsertBits:
+ out << "insert_bits";
+ break;
+ case core::BuiltinFn::kFwidth:
+ case core::BuiltinFn::kFwidthCoarse:
+ case core::BuiltinFn::kFwidthFine:
+ out << "fwidth";
+ break;
+ case core::BuiltinFn::kFaceForward:
+ out << "faceforward";
+ break;
+ case core::BuiltinFn::kPack4X8Snorm:
+ out << "pack_float_to_snorm4x8";
+ break;
+ case core::BuiltinFn::kPack4X8Unorm:
+ out << "pack_float_to_unorm4x8";
+ break;
+ case core::BuiltinFn::kPack2X16Snorm:
+ out << "pack_float_to_snorm2x16";
+ break;
+ case core::BuiltinFn::kPack2X16Unorm:
+ out << "pack_float_to_unorm2x16";
+ break;
+ case core::BuiltinFn::kReverseBits:
+ out << "reverse_bits";
+ break;
+ case core::BuiltinFn::kRound:
+ out << "rint";
+ break;
+ case core::BuiltinFn::kSmoothstep:
+ out << "smoothstep";
+ break;
+ case core::BuiltinFn::kInverseSqrt:
+ out << "rsqrt";
+ break;
+ case core::BuiltinFn::kUnpack4X8Snorm:
+ out << "unpack_snorm4x8_to_float";
+ break;
+ case core::BuiltinFn::kUnpack4X8Unorm:
+ out << "unpack_unorm4x8_to_float";
+ break;
+ case core::BuiltinFn::kUnpack2X16Snorm:
+ out << "unpack_snorm2x16_to_float";
+ break;
+ case core::BuiltinFn::kUnpack2X16Unorm:
+ out << "unpack_unorm2x16_to_float";
+ break;
+ default:
+ TINT_UNREACHABLE() << "unhandled: " << func;
+ }
+ }
+
+ /// Emits a user call instruction
+ void EmitUserCall(StringStream& out, const core::ir::UserCall* c) {
+ out << NameOf(c->Target()) << "(";
+ size_t i = 0;
+ for (const auto* arg : c->Args()) {
+ if (i > 0) {
+ out << ", ";
+ }
+ ++i;
+
+ EmitValue(out, arg);
+ }
+ out << ")";
+ }
+
+ /// Emit a constructor
+ void EmitConstruct(StringStream& out, const core::ir::Construct* c) {
+ Switch(
+ c->Result(0)->Type(),
+ [&](const core::type::Array*) {
+ EmitType(out, c->Result(0)->Type());
+ out << "{";
+ size_t i = 0;
+ for (auto* arg : c->Args()) {
+ if (i > 0) {
+ out << ", ";
+ }
+ EmitValue(out, arg);
+ i++;
+ }
+ out << "}";
+ },
+ [&](const core::type::Struct* struct_ty) {
+ out << "{";
+ size_t i = 0;
+ for (auto* arg : c->Args()) {
+ if (i > 0) {
+ out << ", ";
+ }
+ // Emit field designators for structures to account for padding members.
+ auto name = struct_ty->Members()[i]->Name().Name();
+ out << "." << name << "=";
+ EmitValue(out, arg);
+ i++;
+ }
+ out << "}";
+ },
+ [&](Default) {
+ EmitType(out, c->Result(0)->Type());
+ out << "(";
+ size_t i = 0;
+ for (auto* arg : c->Args()) {
+ if (i > 0) {
+ out << ", ";
+ }
+ EmitValue(out, arg);
+ i++;
+ }
+ out << ")";
+ });
+ }
+
/// Handles generating a address space
/// @param out the output of the type stream
/// @param sc the address space to generate
@@ -446,7 +968,7 @@
out << "constant";
break;
default:
- TINT_ICE() << "unhandled address space: " << sc;
+ TINT_IR_ICE(ir_) << "unhandled address space: " << sc;
break;
}
}
@@ -519,7 +1041,7 @@
} else {
auto count = arr->ConstantCount();
if (!count) {
- TINT_ICE() << core::type::Array::kErrExpectedConstantCount;
+ TINT_IR_ICE(ir_) << core::type::Array::kErrExpectedConstantCount;
return;
}
out << count.value();
@@ -551,7 +1073,7 @@
/// @param tex the texture to emit
void EmitTextureType(StringStream& out, const core::type::Texture* tex) {
if (TINT_UNLIKELY(tex->Is<core::type::ExternalTexture>())) {
- TINT_ICE() << "Multiplanar external texture transform was not run.";
+ TINT_IR_ICE(ir_) << "Multiplanar external texture transform was not run.";
return;
}
@@ -581,7 +1103,7 @@
out << "cube_array";
break;
default:
- TINT_ICE() << "invalid texture dimensions";
+ TINT_IR_ICE(ir_) << "invalid texture dimensions";
return;
}
if (tex->IsAnyOf<core::type::MultisampledTexture, core::type::DepthMultisampledTexture>()) {
@@ -604,7 +1126,7 @@
} else if (storage->access() == core::Access::kWrite) {
out << "access::write";
} else {
- TINT_ICE() << "invalid access control for storage texture";
+ TINT_IR_ICE(ir_) << "invalid access control for storage texture";
return;
}
},
@@ -666,8 +1188,8 @@
if (is_host_shareable) {
if (TINT_UNLIKELY(ir_offset < msl_offset)) {
// Unimplementable layout
- TINT_ICE() << "Structure member offset (" << ir_offset
- << ") is behind MSL offset (" << msl_offset << ")";
+ TINT_IR_ICE(ir_) << "Structure member offset (" << ir_offset
+ << ") is behind MSL offset (" << msl_offset << ")";
return;
}
@@ -691,7 +1213,7 @@
if (auto builtin = attributes.builtin) {
auto name = BuiltinToAttribute(builtin.value());
if (name.empty()) {
- TINT_ICE() << "unknown builtin";
+ TINT_IR_ICE(ir_) << "unknown builtin";
return;
}
out << " [[" << name << "]]";
@@ -700,7 +1222,7 @@
if (auto location = attributes.location) {
auto& pipeline_stage_uses = str->PipelineStageUses();
if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
- TINT_ICE() << "invalid entry point IO struct uses";
+ TINT_IR_ICE(ir_) << "invalid entry point IO struct uses";
return;
}
@@ -716,7 +1238,7 @@
core::type::PipelineStageUsage::kFragmentOutput))) {
out << " [[color(" + std::to_string(location.value()) + ")]]";
} else {
- TINT_ICE() << "invalid use of location decoration";
+ TINT_IR_ICE(ir_) << "invalid use of location decoration";
return;
}
}
@@ -724,7 +1246,7 @@
if (auto interpolation = attributes.interpolation) {
auto name = InterpolationToAttribute(interpolation->type, interpolation->sampling);
if (name.empty()) {
- TINT_ICE() << "unknown interpolation attribute";
+ TINT_IR_ICE(ir_) << "unknown interpolation attribute";
return;
}
out << " [[" << name << "]]";
@@ -741,9 +1263,9 @@
// Calculate new MSL offset
auto size_align = MslPackedTypeSizeAndAlign(ty);
if (TINT_UNLIKELY(msl_offset % size_align.align)) {
- TINT_ICE() << "Misaligned MSL structure member " << mem_name << " : "
- << ty->FriendlyName() << " offset: " << msl_offset
- << " align: " << size_align.align;
+ TINT_IR_ICE(ir_) << "Misaligned MSL structure member " << mem_name << " : "
+ << ty->FriendlyName() << " offset: " << msl_offset
+ << " align: " << size_align.align;
return;
}
msl_offset += size_align.size;
@@ -763,7 +1285,9 @@
/// Handles core::ir::Constant values
/// @param out the stream to write the constant too
/// @param c the constant to emit
- void EmitConstant(StringStream& out, core::ir::Constant* c) { EmitConstant(out, c->Value()); }
+ void EmitConstant(StringStream& out, const core::ir::Constant* c) {
+ EmitConstant(out, c->Value());
+ }
/// Handles core::constant::Value values
/// @param out the stream to write the constant too
@@ -811,7 +1335,7 @@
auto count = a->ConstantCount();
if (!count) {
- TINT_ICE() << core::type::Array::kErrExpectedConstantCount;
+ TINT_IR_ICE(ir_) << core::type::Array::kErrExpectedConstantCount;
return;
}
emit_values(*count);
@@ -872,177 +1396,26 @@
return name;
}
+ /// @param value the value to get the name of
+ /// @returns the name of the given value, creating a new unique name if the value is unnamed in
+ /// the module.
+ std::string NameOf(const core::ir::Value* value) {
+ return names_.GetOrCreate(value, [&] {
+ if (auto sym = ir_.NameOf(value); sym.IsValid()) {
+ return sym.Name();
+ }
+ return UniqueIdentifier("v");
+ });
+ }
+
/// @return a new, unique identifier with the given prefix.
- /// @param prefix optional prefix to apply to the generated identifier. If empty "tint_symbol"
- /// will be used.
+ /// @param prefix optional prefix to apply to the generated identifier. If empty
+ /// "tint_symbol" will be used.
std::string UniqueIdentifier(const std::string& prefix /* = "" */) {
return ir_.symbols.New(prefix).Name();
}
-
- TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
-
- /// Returns the expression for the given value
- /// @param value the value to lookup
- /// @param want_ptr_kind the pointer information for the return
- /// @returns the string expression
- std::string Expr(core::ir::Value* value, PtrKind want_ptr_kind = PtrKind::kRef) {
- using ExprAndPtrKind = std::pair<std::string, PtrKind>;
-
- auto [expr, got_ptr_kind] = tint::Switch(
- value,
- [&](core::ir::Constant* c) -> ExprAndPtrKind {
- StringStream str;
- EmitConstant(str, c);
- return {str.str(), PtrKind::kRef};
- },
- [&](Default) -> ExprAndPtrKind {
- auto lookup = bindings_.Find(value);
- if (TINT_UNLIKELY(!lookup)) {
- TINT_ICE() << "Expr(" << (value ? value->TypeInfo().name : "null")
- << ") value has no expression";
- return {};
- }
-
- return std::visit(
- [&](auto&& got) -> ExprAndPtrKind {
- using T = std::decay_t<decltype(got)>;
-
- if constexpr (std::is_same_v<T, VariableValue>) {
- return {got.name.Name(), got.ptr_kind};
- }
-
- if constexpr (std::is_same_v<T, InlinedValue>) {
- auto result = ExprAndPtrKind{got.expr, got.ptr_kind};
-
- // Single use (inlined) expression.
- // Mark the bindings_ map entry as consumed.
- *lookup = ConsumedValue{};
- return result;
- }
-
- if constexpr (std::is_same_v<T, ConsumedValue>) {
- TINT_ICE() << "Expr(" << value->TypeInfo().name
- << ") called twice on the same value";
- } else {
- TINT_ICE()
- << "Expr(" << value->TypeInfo().name << ") has unhandled value";
- }
- return {};
- },
- *lookup);
- });
- if (expr.empty()) {
- return "<error>";
- }
-
- if (value->Type()->Is<core::type::Pointer>()) {
- return ToPtrKind(expr, got_ptr_kind, want_ptr_kind);
- }
-
- return expr;
- }
-
- TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
-
- /// Returns the given expression converted to the given pointer kind
- /// @param in the input expression
- /// @param got the pointer kind we have
- /// @param want the pointer kind we want
- std::string ToPtrKind(const std::string& in, PtrKind got, PtrKind want) {
- if (want == PtrKind::kRef && got == PtrKind::kPtr) {
- return "*(" + in + ")";
- }
- if (want == PtrKind::kPtr && got == PtrKind::kRef) {
- return "&(" + in + ")";
- }
- return in;
- }
-
- /// Associates an IR value with a result expression
- /// @param value the IR value
- /// @param expr the result expression
- /// @param ptr_kind defines how pointer values are represented by the expression
- void Bind(core::ir::Value* value, const std::string& expr, PtrKind ptr_kind = PtrKind::kRef) {
- TINT_ASSERT(value);
-
- if (can_inline_.Remove(value)) {
- // Value will be inlined at its place of usage.
- if (TINT_LIKELY(bindings_.Add(value, InlinedValue{expr, ptr_kind}))) {
- return;
- }
- } else {
- auto mod_name = ir_.NameOf(value);
- if (value->Usages().IsEmpty() && !mod_name.IsValid()) {
- // Drop phonies.
- } else {
- if (mod_name.Name().empty()) {
- mod_name = ir_.symbols.New("v");
- }
-
- auto out = Line();
- EmitType(out, value->Type());
- out << " const " << mod_name.Name() << " = ";
- if (value->Type()->Is<core::type::Pointer>()) {
- out << ToPtrKind(expr, ptr_kind, PtrKind::kPtr);
- } else {
- out << expr;
- }
- out << ";";
-
- Bind(value, mod_name, PtrKind::kPtr);
- }
- return;
- }
-
- TINT_ICE() << "Bind(" << value->TypeInfo().name << ") called twice for same value";
- }
-
- /// Associates an IR value the 'var', 'let' or parameter of the given name
- /// @param value the IR value
- /// @param name the name for the value
- /// @param ptr_kind defines how pointer values are represented by @p expr.
- void Bind(core::ir::Value* value, Symbol name, PtrKind ptr_kind = PtrKind::kRef) {
- TINT_ASSERT(value);
-
- bool added = bindings_.Add(value, VariableValue{name, ptr_kind});
- if (TINT_UNLIKELY(!added)) {
- TINT_ICE() << "Bind(" << value->TypeInfo().name << ") called twice for same value";
- }
- }
-
- /// Marks instructions in a block for inlineability
- /// @param block the block
- void MarkInlinable(core::ir::Block* block) {
- // An ordered list of possibly-inlinable values returned by sequenced instructions that have
- // not yet been marked-for or ruled-out-for inlining.
- UniqueVector<core::ir::Value*, 32> pending_resolution;
-
- // Walk the instructions of the block starting with the first.
- for (auto* inst : *block) {
- // Is the instruction sequenced?
- bool sequenced = inst->Sequenced();
-
- if (inst->Results().Length() != 1) {
- continue;
- }
-
- // Instruction has a single result value.
- // Check to see if the result of this instruction is a candidate for inlining.
- auto* result = inst->Result();
- // Only values with a single usage can be inlined.
- // Named values are not inlined, as we want to emit the name for a let.
- if (result->Usages().Count() == 1 && !ir_.NameOf(result).IsValid()) {
- if (sequenced) {
- // The value comes from a sequenced instruction. Don't inline.
- } else {
- // The value comes from an unsequenced instruction. Just inline.
- can_inline_.Add(result);
- }
- continue;
- }
- }
- }
};
+
} // namespace
Result<std::string> Print(core::ir::Module& module) {
diff --git a/src/tint/lang/msl/writer/printer/var_test.cc b/src/tint/lang/msl/writer/printer/var_test.cc
index ab15f44..04f9358 100644
--- a/src/tint/lang/msl/writer/printer/var_test.cc
+++ b/src/tint/lang/msl/writer/printer/var_test.cc
@@ -254,9 +254,9 @@
auto* func = b.Function("foo", ty.void_());
b.Append(func->Block(), [&] {
- auto* ld = b.Load(v->Result());
+ auto* ld = b.Load(v->Result(0));
auto* a = b.Var("a", ty.ptr<core::AddressSpace::kFunction, f32>());
- a->SetInitializer(ld->Result());
+ a->SetInitializer(ld->Result(0));
b.Return(func);
});
@@ -281,9 +281,9 @@
auto* func = b.Function("foo", ty.void_());
b.Append(func->Block(), [&] {
- auto* ld = b.Load(v->Result());
+ auto* ld = b.Load(v->Result(0));
auto* a = b.Var("a", ty.ptr<core::AddressSpace::kFunction, f32>());
- a->SetInitializer(ld->Result());
+ a->SetInitializer(ld->Result(0));
b.Return(func);
});
diff --git a/src/tint/lang/msl/writer/raise/BUILD.bazel b/src/tint/lang/msl/writer/raise/BUILD.bazel
index ab458ab..a192956 100644
--- a/src/tint/lang/msl/writer/raise/BUILD.bazel
+++ b/src/tint/lang/msl/writer/raise/BUILD.bazel
@@ -45,18 +45,32 @@
"raise.h",
],
deps = [
+ "//src/tint/api/common",
+ "//src/tint/api/options",
+ "//src/tint/lang/core/ir/transform",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
"//src/tint/utils/ice",
"//src/tint/utils/macros",
"//src/tint/utils/math",
"//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
"//src/tint/utils/result",
"//src/tint/utils/rtti",
"//src/tint/utils/text",
"//src/tint/utils/traits",
- ],
+ ] + select({
+ ":tint_build_msl_writer": [
+ "//src/tint/lang/msl/writer/common",
+ ],
+ "//conditions:default": [],
+ }),
copts = COPTS,
visibility = ["//visibility:public"],
)
+alias(
+ name = "tint_build_msl_writer",
+ actual = "//src/tint:tint_build_msl_writer_true",
+)
+
diff --git a/src/tint/lang/msl/writer/raise/BUILD.cfg b/src/tint/lang/msl/writer/raise/BUILD.cfg
new file mode 100644
index 0000000..70e4a45
--- /dev/null
+++ b/src/tint/lang/msl/writer/raise/BUILD.cfg
@@ -0,0 +1,4 @@
+{
+ "condition": "tint_build_msl_writer"
+}
+
diff --git a/src/tint/lang/msl/writer/raise/BUILD.cmake b/src/tint/lang/msl/writer/raise/BUILD.cmake
index cb64e93..0e41a3c 100644
--- a/src/tint/lang/msl/writer/raise/BUILD.cmake
+++ b/src/tint/lang/msl/writer/raise/BUILD.cmake
@@ -34,9 +34,11 @@
# Do not modify this file directly
################################################################################
+if(TINT_BUILD_MSL_WRITER)
################################################################################
# Target: tint_lang_msl_writer_raise
# Kind: lib
+# Condition: TINT_BUILD_MSL_WRITER
################################################################################
tint_add_target(tint_lang_msl_writer_raise lib
lang/msl/writer/raise/raise.cc
@@ -44,14 +46,26 @@
)
tint_target_add_dependencies(tint_lang_msl_writer_raise lib
+ tint_api_common
+ tint_api_options
+ tint_lang_core_ir_transform
tint_utils_containers
tint_utils_diagnostic
tint_utils_ice
tint_utils_macros
tint_utils_math
tint_utils_memory
+ tint_utils_reflection
tint_utils_result
tint_utils_rtti
tint_utils_text
tint_utils_traits
)
+
+if(TINT_BUILD_MSL_WRITER)
+ tint_target_add_dependencies(tint_lang_msl_writer_raise lib
+ tint_lang_msl_writer_common
+ )
+endif(TINT_BUILD_MSL_WRITER)
+
+endif(TINT_BUILD_MSL_WRITER)
\ No newline at end of file
diff --git a/src/tint/lang/msl/writer/raise/BUILD.gn b/src/tint/lang/msl/writer/raise/BUILD.gn
index bd20a51..74cc477 100644
--- a/src/tint/lang/msl/writer/raise/BUILD.gn
+++ b/src/tint/lang/msl/writer/raise/BUILD.gn
@@ -37,22 +37,31 @@
import("../../../../../../scripts/tint_overrides_with_defaults.gni")
import("${tint_src_dir}/tint.gni")
+if (tint_build_msl_writer) {
+ libtint_source_set("raise") {
+ sources = [
+ "raise.cc",
+ "raise.h",
+ ]
+ deps = [
+ "${tint_src_dir}/api/common",
+ "${tint_src_dir}/api/options",
+ "${tint_src_dir}/lang/core/ir/transform",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
-libtint_source_set("raise") {
- sources = [
- "raise.cc",
- "raise.h",
- ]
- deps = [
- "${tint_src_dir}/utils/containers",
- "${tint_src_dir}/utils/diagnostic",
- "${tint_src_dir}/utils/ice",
- "${tint_src_dir}/utils/macros",
- "${tint_src_dir}/utils/math",
- "${tint_src_dir}/utils/memory",
- "${tint_src_dir}/utils/result",
- "${tint_src_dir}/utils/rtti",
- "${tint_src_dir}/utils/text",
- "${tint_src_dir}/utils/traits",
- ]
+ if (tint_build_msl_writer) {
+ deps += [ "${tint_src_dir}/lang/msl/writer/common" ]
+ }
+ }
}
diff --git a/src/tint/lang/msl/writer/raise/raise.cc b/src/tint/lang/msl/writer/raise/raise.cc
index 6a7cd81..da70216 100644
--- a/src/tint/lang/msl/writer/raise/raise.cc
+++ b/src/tint/lang/msl/writer/raise/raise.cc
@@ -29,18 +29,82 @@
#include <utility>
-namespace tint::msl::raise {
+#include "src/tint/lang/core/ir/transform/binary_polyfill.h"
+#include "src/tint/lang/core/ir/transform/binding_remapper.h"
+#include "src/tint/lang/core/ir/transform/builtin_polyfill.h"
+#include "src/tint/lang/core/ir/transform/conversion_polyfill.h"
+#include "src/tint/lang/core/ir/transform/demote_to_helper.h"
+#include "src/tint/lang/core/ir/transform/multiplanar_external_texture.h"
+#include "src/tint/lang/core/ir/transform/preserve_padding.h"
+#include "src/tint/lang/core/ir/transform/robustness.h"
+#include "src/tint/lang/core/ir/transform/value_to_let.h"
+#include "src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.h"
+#include "src/tint/lang/core/ir/transform/zero_init_workgroup_memory.h"
+#include "src/tint/lang/msl/writer/common/option_helpers.h"
-Result<SuccessType> Raise(core::ir::Module&) {
- // #define RUN_TRANSFORM(name)
- // do {
- // auto result = core::ir::transform::name(module);
- // if (!result) {
- // return result;
- // }
- // } while (false)
+namespace tint::msl::writer::raise {
+
+Result<SuccessType> Raise(core::ir::Module& module, const Options& options) {
+#define RUN_TRANSFORM(name, ...) \
+ do { \
+ auto result = name(module, ##__VA_ARGS__); \
+ if (!result) { \
+ return result; \
+ } \
+ } while (false)
+
+ ExternalTextureOptions external_texture_options{};
+ RemapperData remapper_data{};
+ PopulateRemapperAndMultiplanarOptions(options, remapper_data, external_texture_options);
+ RUN_TRANSFORM(core::ir::transform::BindingRemapper, remapper_data);
+
+ {
+ core::ir::transform::BinaryPolyfillConfig binary_polyfills{};
+ binary_polyfills.int_div_mod = true;
+ binary_polyfills.bitshift_modulo = true; // crbug.com/tint/1543
+ RUN_TRANSFORM(core::ir::transform::BinaryPolyfill, binary_polyfills);
+ }
+
+ {
+ core::ir::transform::BuiltinPolyfillConfig core_polyfills{};
+ core_polyfills.clamp_int = true;
+ core_polyfills.extract_bits = core::ir::transform::BuiltinPolyfillLevel::kClampOrRangeCheck;
+ core_polyfills.first_leading_bit = true;
+ core_polyfills.first_trailing_bit = true;
+ core_polyfills.insert_bits = core::ir::transform::BuiltinPolyfillLevel::kClampOrRangeCheck;
+ core_polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
+ RUN_TRANSFORM(core::ir::transform::BuiltinPolyfill, core_polyfills);
+ }
+ // polyfills.sign_int = true;
+
+ {
+ core::ir::transform::ConversionPolyfillConfig conversion_polyfills;
+ conversion_polyfills.ftoi = true;
+ RUN_TRANSFORM(core::ir::transform::ConversionPolyfill, conversion_polyfills);
+ }
+
+ if (!options.disable_robustness) {
+ core::ir::transform::RobustnessConfig config{};
+ RUN_TRANSFORM(core::ir::transform::Robustness, config);
+ }
+
+ RUN_TRANSFORM(core::ir::transform::MultiplanarExternalTexture, external_texture_options);
+
+ if (!options.disable_workgroup_init) {
+ RUN_TRANSFORM(core::ir::transform::ZeroInitWorkgroupMemory);
+ }
+
+ // PreservePadding must come before DirectVariableAccess.
+ RUN_TRANSFORM(core::ir::transform::PreservePadding);
+
+ RUN_TRANSFORM(core::ir::transform::VectorizeScalarMatrixConstructors);
+
+ // DemoteToHelper must come before any transform that introduces non-core instructions.
+ RUN_TRANSFORM(core::ir::transform::DemoteToHelper);
+
+ RUN_TRANSFORM(core::ir::transform::ValueToLet);
return Success;
}
-} // namespace tint::msl::raise
+} // namespace tint::msl::writer::raise
diff --git a/src/tint/lang/msl/writer/raise/raise.h b/src/tint/lang/msl/writer/raise/raise.h
index 979d713..256925d 100644
--- a/src/tint/lang/msl/writer/raise/raise.h
+++ b/src/tint/lang/msl/writer/raise/raise.h
@@ -30,6 +30,7 @@
#include <string>
+#include "src/tint/lang/msl/writer/common/options.h"
#include "src/tint/utils/diagnostic/diagnostic.h"
#include "src/tint/utils/result/result.h"
@@ -38,13 +39,14 @@
class Module;
} // namespace tint::core::ir
-namespace tint::msl::raise {
+namespace tint::msl::writer::raise {
/// Raise a core IR module to the MSL dialect of the IR.
-/// @param mod the core IR module to raise to MSL dialect
+/// @param module the core IR module to raise to MSL dialect
+/// @param options the printer options
/// @returns success or failure
-Result<SuccessType> Raise(core::ir::Module& mod);
+Result<SuccessType> Raise(core::ir::Module& module, const Options& options);
-} // namespace tint::msl::raise
+} // namespace tint::msl::writer::raise
#endif // SRC_TINT_LANG_MSL_WRITER_RAISE_RAISE_H_
diff --git a/src/tint/lang/msl/writer/writer.cc b/src/tint/lang/msl/writer/writer.cc
index cb5281d..bc1a5e0 100644
--- a/src/tint/lang/msl/writer/writer.cc
+++ b/src/tint/lang/msl/writer/writer.cc
@@ -42,68 +42,61 @@
namespace tint::msl::writer {
+Result<Output> Generate(core::ir::Module& ir, const Options& options) {
+ {
+ auto res = ValidateBindingOptions(options);
+ if (!res) {
+ return res.Failure();
+ }
+ }
+
+ Output output;
+
+ // Raise from core-dialect to MSL-dialect.
+ if (auto res = raise::Raise(ir, options); !res) {
+ return res.Failure();
+ }
+
+ // Generate the MSL code.
+ auto result = Print(ir);
+ if (!result) {
+ return result.Failure();
+ }
+ output.msl = result.Get();
+ return output;
+}
+
Result<Output> Generate(const Program& program, const Options& options) {
if (!program.IsValid()) {
return Failure{program.Diagnostics()};
}
{
- diag::List validation_diagnostics;
- if (!ValidateBindingOptions(options, validation_diagnostics)) {
- return Failure{validation_diagnostics};
+ auto res = ValidateBindingOptions(options);
+ if (!res) {
+ return res.Failure();
}
}
Output output;
- if (options.use_tint_ir) {
-#if TINT_BUILD_WGSL_READER
- // Convert the AST program to an IR module.
- auto converted = wgsl::reader::ProgramToIR(program);
- if (!converted) {
- return converted.Failure();
- }
-
- auto ir = converted.Move();
-
- // Lower from WGSL-dialect to core-dialect
- if (auto res = wgsl::reader::Lower(ir); !res) {
- return res.Failure();
- }
-
- // Raise from core-dialect to MSL-dialect.
- if (auto res = raise::Raise(ir); !res) {
- return res.Failure();
- }
-
- // Generate the MSL code.
- auto result = Print(ir);
- if (!result) {
- return result.Failure();
- }
- output.msl = result.Get();
-#else
- return Failure{"use_tint_ir requires building with TINT_BUILD_WGSL_READER"};
-#endif
- } else {
- // Sanitize the program.
- auto sanitized_result = Sanitize(program, options);
- if (!sanitized_result.program.IsValid()) {
- return Failure{sanitized_result.program.Diagnostics()};
- }
- output.needs_storage_buffer_sizes = sanitized_result.needs_storage_buffer_sizes;
- output.used_array_length_from_uniform_indices =
- std::move(sanitized_result.used_array_length_from_uniform_indices);
-
- // Generate the MSL code.
- auto impl = std::make_unique<ASTPrinter>(sanitized_result.program);
- if (!impl->Generate()) {
- return Failure{impl->Diagnostics()};
- }
- output.msl = impl->Result();
- output.has_invariant_attribute = impl->HasInvariant();
- output.workgroup_allocations = impl->DynamicWorkgroupAllocations();
+ // Sanitize the program.
+ auto sanitized_result = Sanitize(program, options);
+ if (!sanitized_result.program.IsValid()) {
+ return Failure{sanitized_result.program.Diagnostics()};
}
+ output.needs_storage_buffer_sizes = sanitized_result.needs_storage_buffer_sizes;
+ output.used_array_length_from_uniform_indices =
+ std::move(sanitized_result.used_array_length_from_uniform_indices);
+
+ // Generate the MSL code.
+ auto impl = std::make_unique<ASTPrinter>(sanitized_result.program);
+ if (!impl->Generate()) {
+ return Failure{impl->Diagnostics()};
+ }
+ output.msl = impl->Result();
+ output.has_invariant_attribute = impl->HasInvariant();
+ output.workgroup_allocations = impl->DynamicWorkgroupAllocations();
return output;
}
diff --git a/src/tint/lang/msl/writer/writer.h b/src/tint/lang/msl/writer/writer.h
index 7d34ddd..e27c318 100644
--- a/src/tint/lang/msl/writer/writer.h
+++ b/src/tint/lang/msl/writer/writer.h
@@ -39,11 +39,21 @@
namespace tint {
class Program;
} // namespace tint
+namespace tint::core::ir {
+class Module;
+} // namespace tint::core::ir
namespace tint::msl::writer {
/// Generate MSL for a program, according to a set of configuration options.
/// The result will contain the MSL and supplementary information, or failure.
+/// @param ir the IR module to translate to MSL
+/// @param options the configuration options to use when generating MSL
+/// @returns the resulting MSL and supplementary information, or failure
+Result<Output> Generate(core::ir::Module& ir, const Options& options);
+
+/// Generate MSL for a program, according to a set of configuration options.
+/// The result will contain the MSL and supplementary information, or failure.
/// @param program the program to translate to MSL
/// @param options the configuration options to use when generating MSL
/// @returns the resulting MSL and supplementary information, or failure
diff --git a/src/tint/lang/spirv/BUILD.cmake b/src/tint/lang/spirv/BUILD.cmake
index 30c3163..06f7cfd 100644
--- a/src/tint/lang/spirv/BUILD.cmake
+++ b/src/tint/lang/spirv/BUILD.cmake
@@ -38,6 +38,7 @@
include(lang/spirv/ir/BUILD.cmake)
include(lang/spirv/reader/BUILD.cmake)
include(lang/spirv/type/BUILD.cmake)
+include(lang/spirv/validate/BUILD.cmake)
include(lang/spirv/writer/BUILD.cmake)
################################################################################
diff --git a/src/tint/lang/spirv/ir/builtin_call.cc b/src/tint/lang/spirv/ir/builtin_call.cc
index dd01293..5503e55 100644
--- a/src/tint/lang/spirv/ir/builtin_call.cc
+++ b/src/tint/lang/spirv/ir/builtin_call.cc
@@ -48,7 +48,7 @@
BuiltinCall::~BuiltinCall() = default;
BuiltinCall* BuiltinCall::Clone(core::ir::CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto new_args = ctx.Clone<BuiltinCall::kDefaultNumOperands>(Args());
return ctx.ir.instructions.Create<BuiltinCall>(new_result, func_, new_args);
}
diff --git a/src/tint/lang/spirv/ir/builtin_call.h b/src/tint/lang/spirv/ir/builtin_call.h
index fbc958b..54e357f 100644
--- a/src/tint/lang/spirv/ir/builtin_call.h
+++ b/src/tint/lang/spirv/ir/builtin_call.h
@@ -54,16 +54,16 @@
BuiltinCall* Clone(core::ir::CloneContext& ctx) override;
/// @returns the builtin function
- BuiltinFn Func() { return func_; }
+ BuiltinFn Func() const { return func_; }
/// @returns the identifier for the function
- size_t FuncId() override { return static_cast<size_t>(func_); }
+ size_t FuncId() const override { return static_cast<size_t>(func_); }
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return std::string("spirv.") + str(func_); }
+ std::string FriendlyName() const override { return std::string("spirv.") + str(func_); }
/// @returns the table data to validate this builtin
- const core::intrinsic::TableData& TableData() override {
+ const core::intrinsic::TableData& TableData() const override {
return spirv::intrinsic::Dialect::kData;
}
diff --git a/src/tint/lang/spirv/ir/builtin_call_test.cc b/src/tint/lang/spirv/ir/builtin_call_test.cc
index a48c8fb..4256f26 100644
--- a/src/tint/lang/spirv/ir/builtin_call_test.cc
+++ b/src/tint/lang/spirv/ir/builtin_call_test.cc
@@ -43,8 +43,8 @@
auto* new_b = clone_ctx.Clone(builtin);
EXPECT_NE(builtin, new_b);
- EXPECT_NE(builtin->Result(), new_b->Result());
- EXPECT_EQ(mod.Types().f32(), new_b->Result()->Type());
+ EXPECT_NE(builtin->Result(0), new_b->Result(0));
+ EXPECT_EQ(mod.Types().f32(), new_b->Result(0)->Type());
EXPECT_EQ(BuiltinFn::kArrayLength, new_b->Func());
@@ -62,8 +62,8 @@
auto* builtin = b.Call<BuiltinCall>(mod.Types().f32(), BuiltinFn::kArrayLength);
auto* new_b = clone_ctx.Clone(builtin);
- EXPECT_NE(builtin->Result(), new_b->Result());
- EXPECT_EQ(mod.Types().f32(), new_b->Result()->Type());
+ EXPECT_NE(builtin->Result(0), new_b->Result(0));
+ EXPECT_EQ(mod.Types().f32(), new_b->Result(0)->Type());
EXPECT_EQ(BuiltinFn::kArrayLength, new_b->Func());
diff --git a/src/tint/lang/spirv/reader/BUILD.bazel b/src/tint/lang/spirv/reader/BUILD.bazel
index 7d88550..599d625 100644
--- a/src/tint/lang/spirv/reader/BUILD.bazel
+++ b/src/tint/lang/spirv/reader/BUILD.bazel
@@ -52,6 +52,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/spirv/reader/BUILD.cmake b/src/tint/lang/spirv/reader/BUILD.cmake
index 540b7b4..46c4639 100644
--- a/src/tint/lang/spirv/reader/BUILD.cmake
+++ b/src/tint/lang/spirv/reader/BUILD.cmake
@@ -57,6 +57,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/spirv/reader/BUILD.gn b/src/tint/lang/spirv/reader/BUILD.gn
index 2b415fb..e6eb783 100644
--- a/src/tint/lang/spirv/reader/BUILD.gn
+++ b/src/tint/lang/spirv/reader/BUILD.gn
@@ -51,6 +51,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/spirv/reader/ast_lower/BUILD.bazel b/src/tint/lang/spirv/reader/ast_lower/BUILD.bazel
index 5f667a1..4bb7e6a 100644
--- a/src/tint/lang/spirv/reader/ast_lower/BUILD.bazel
+++ b/src/tint/lang/spirv/reader/ast_lower/BUILD.bazel
@@ -59,6 +59,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
@@ -98,6 +99,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/spirv/reader/ast_lower/BUILD.cmake b/src/tint/lang/spirv/reader/ast_lower/BUILD.cmake
index f73503c..6d3870b 100644
--- a/src/tint/lang/spirv/reader/ast_lower/BUILD.cmake
+++ b/src/tint/lang/spirv/reader/ast_lower/BUILD.cmake
@@ -60,6 +60,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
@@ -102,6 +103,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
diff --git a/src/tint/lang/spirv/reader/ast_lower/BUILD.gn b/src/tint/lang/spirv/reader/ast_lower/BUILD.gn
index d904f52..c2ded34 100644
--- a/src/tint/lang/spirv/reader/ast_lower/BUILD.gn
+++ b/src/tint/lang/spirv/reader/ast_lower/BUILD.gn
@@ -62,6 +62,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
@@ -102,6 +103,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/spirv/reader/ast_parser/BUILD.bazel b/src/tint/lang/spirv/reader/ast_parser/BUILD.bazel
index 3afb571..421ec97 100644
--- a/src/tint/lang/spirv/reader/ast_parser/BUILD.bazel
+++ b/src/tint/lang/spirv/reader/ast_parser/BUILD.bazel
@@ -72,6 +72,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
@@ -151,6 +152,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/spirv/reader/ast_parser/BUILD.cmake b/src/tint/lang/spirv/reader/ast_parser/BUILD.cmake
index 6316fb3..cf9191f 100644
--- a/src/tint/lang/spirv/reader/ast_parser/BUILD.cmake
+++ b/src/tint/lang/spirv/reader/ast_parser/BUILD.cmake
@@ -73,6 +73,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
@@ -157,6 +158,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/spirv/reader/ast_parser/BUILD.gn b/src/tint/lang/spirv/reader/ast_parser/BUILD.gn
index 85be154..f82d2fb 100644
--- a/src/tint/lang/spirv/reader/ast_parser/BUILD.gn
+++ b/src/tint/lang/spirv/reader/ast_parser/BUILD.gn
@@ -75,6 +75,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
@@ -157,6 +158,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/spirv/reader/common/BUILD.bazel b/src/tint/lang/spirv/reader/common/BUILD.bazel
index 0700a25..b74c742 100644
--- a/src/tint/lang/spirv/reader/common/BUILD.bazel
+++ b/src/tint/lang/spirv/reader/common/BUILD.bazel
@@ -47,6 +47,7 @@
deps = [
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/utils/containers",
"//src/tint/utils/ice",
"//src/tint/utils/macros",
diff --git a/src/tint/lang/spirv/reader/common/BUILD.cmake b/src/tint/lang/spirv/reader/common/BUILD.cmake
index 871983e..23c0ff1 100644
--- a/src/tint/lang/spirv/reader/common/BUILD.cmake
+++ b/src/tint/lang/spirv/reader/common/BUILD.cmake
@@ -46,6 +46,7 @@
tint_target_add_dependencies(tint_lang_spirv_reader_common lib
tint_lang_wgsl
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_utils_containers
tint_utils_ice
tint_utils_macros
diff --git a/src/tint/lang/spirv/reader/common/BUILD.gn b/src/tint/lang/spirv/reader/common/BUILD.gn
index 391f597..9e75c83 100644
--- a/src/tint/lang/spirv/reader/common/BUILD.gn
+++ b/src/tint/lang/spirv/reader/common/BUILD.gn
@@ -46,6 +46,7 @@
deps = [
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/ice",
"${tint_src_dir}/utils/macros",
diff --git a/src/tint/lang/spirv/validate/BUILD.bazel b/src/tint/lang/spirv/validate/BUILD.bazel
new file mode 100644
index 0000000..bc1d952
--- /dev/null
+++ b/src/tint/lang/spirv/validate/BUILD.bazel
@@ -0,0 +1,112 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+cc_library(
+ name = "validate",
+ srcs = [
+ "validate.cc",
+ ],
+ hdrs = [
+ "validate.h",
+ ],
+ deps = [
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ ] + select({
+ ":tint_build_spv_reader_or_tint_build_spv_writer": [
+ "@spirv_tools",
+ ],
+ "//conditions:default": [],
+ }),
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+cc_library(
+ name = "test",
+ alwayslink = True,
+ srcs = [
+ "validate_test.cc",
+ ],
+ deps = [
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ "@gtest",
+ ] + select({
+ ":tint_build_spv_reader_or_tint_build_spv_writer": [
+ "//src/tint/lang/spirv/validate",
+ ],
+ "//conditions:default": [],
+ }),
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+
+alias(
+ name = "tint_build_spv_reader",
+ actual = "//src/tint:tint_build_spv_reader_true",
+)
+
+alias(
+ name = "tint_build_spv_writer",
+ actual = "//src/tint:tint_build_spv_writer_true",
+)
+
+selects.config_setting_group(
+ name = "tint_build_spv_reader_or_tint_build_spv_writer",
+ match_any = [
+ "tint_build_spv_reader",
+ "tint_build_spv_writer",
+ ],
+)
+
diff --git a/src/tint/lang/spirv/validate/BUILD.cfg b/src/tint/lang/spirv/validate/BUILD.cfg
new file mode 100644
index 0000000..3b3caf4
--- /dev/null
+++ b/src/tint/lang/spirv/validate/BUILD.cfg
@@ -0,0 +1,3 @@
+{
+ "condition": "tint_build_spv_reader || tint_build_spv_writer"
+}
diff --git a/src/tint/lang/spirv/validate/BUILD.cmake b/src/tint/lang/spirv/validate/BUILD.cmake
new file mode 100644
index 0000000..e50d0e9
--- /dev/null
+++ b/src/tint/lang/spirv/validate/BUILD.cmake
@@ -0,0 +1,101 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+################################################################################
+# Target: tint_lang_spirv_validate
+# Kind: lib
+# Condition: TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER
+################################################################################
+tint_add_target(tint_lang_spirv_validate lib
+ lang/spirv/validate/validate.cc
+ lang/spirv/validate/validate.h
+)
+
+tint_target_add_dependencies(tint_lang_spirv_validate lib
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_text
+ tint_utils_traits
+)
+
+if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+ tint_target_add_external_dependencies(tint_lang_spirv_validate lib
+ "spirv-tools"
+ )
+endif(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+
+endif(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+################################################################################
+# Target: tint_lang_spirv_validate_test
+# Kind: test
+# Condition: TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER
+################################################################################
+tint_add_target(tint_lang_spirv_validate_test test
+ lang/spirv/validate/validate_test.cc
+)
+
+tint_target_add_dependencies(tint_lang_spirv_validate_test test
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_text
+ tint_utils_traits
+)
+
+tint_target_add_external_dependencies(tint_lang_spirv_validate_test test
+ "gtest"
+)
+
+if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+ tint_target_add_dependencies(tint_lang_spirv_validate_test test
+ tint_lang_spirv_validate
+ )
+endif(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+
+endif(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
\ No newline at end of file
diff --git a/src/tint/lang/spirv/validate/BUILD.gn b/src/tint/lang/spirv/validate/BUILD.gn
new file mode 100644
index 0000000..99890f7
--- /dev/null
+++ b/src/tint/lang/spirv/validate/BUILD.gn
@@ -0,0 +1,94 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+import("../../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+
+if (tint_build_unittests || tint_build_benchmarks) {
+ import("//testing/test.gni")
+}
+if (tint_build_spv_reader || tint_build_spv_writer) {
+ libtint_source_set("validate") {
+ sources = [
+ "validate.cc",
+ "validate.h",
+ ]
+ deps = [
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+
+ if (tint_build_spv_reader || tint_build_spv_writer) {
+ deps += [
+ "${tint_spirv_tools_dir}:spvtools_headers",
+ "${tint_spirv_tools_dir}:spvtools_val",
+ ]
+ }
+ }
+}
+if (tint_build_unittests) {
+ if (tint_build_spv_reader || tint_build_spv_writer) {
+ tint_unittests_source_set("unittests") {
+ sources = [ "validate_test.cc" ]
+ deps = [
+ "${tint_src_dir}:gmock_and_gtest",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+
+ if (tint_build_spv_reader || tint_build_spv_writer) {
+ deps += [ "${tint_src_dir}/lang/spirv/validate" ]
+ }
+ }
+ }
+}
diff --git a/src/tint/lang/spirv/validate/validate.cc b/src/tint/lang/spirv/validate/validate.cc
new file mode 100644
index 0000000..13344b7
--- /dev/null
+++ b/src/tint/lang/spirv/validate/validate.cc
@@ -0,0 +1,91 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/spirv/validate/validate.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "spirv-tools/libspirv.hpp"
+
+namespace tint::spirv::validate {
+
+Result<SuccessType> Validate(Slice<const uint32_t> spirv) {
+ Vector<diag::Diagnostic, 4> diags;
+ diags.Push(diag::Diagnostic{}); // Filled in on error
+
+ spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_3);
+ tools.SetMessageConsumer(
+ [&](spv_message_level_t level, const char*, const spv_position_t& pos, const char* msg) {
+ diag::Diagnostic diag;
+ diag.message = msg;
+ diag.source.range.begin.line = pos.line + 1;
+ diag.source.range.begin.column = pos.column + 1;
+ diag.source.range.end = diag.source.range.begin;
+ switch (level) {
+ case SPV_MSG_FATAL:
+ case SPV_MSG_INTERNAL_ERROR:
+ case SPV_MSG_ERROR:
+ diag.severity = diag::Severity::Error;
+ break;
+ case SPV_MSG_WARNING:
+ diag.severity = diag::Severity::Warning;
+ break;
+ case SPV_MSG_INFO:
+ case SPV_MSG_DEBUG:
+ diag.severity = diag::Severity::Note;
+ break;
+ }
+ diags.Push(std::move(diag));
+ });
+
+ if (tools.Validate(spirv.data, spirv.len)) {
+ return Success;
+ }
+
+ std::string disassembly;
+ if (tools.Disassemble(
+ spirv.data, spirv.len, &disassembly,
+ SPV_BINARY_TO_TEXT_OPTION_INDENT | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES)) {
+ diag::Diagnostic& err = diags.Front();
+ err.message = "SPIR-V failed validation.\n\nDisassembly:\n" + std::move(disassembly);
+ err.severity = diag::Severity::Error;
+ } else {
+ diag::Diagnostic& err = diags.Front();
+ err.message = "SPIR-V failed validation and disassembly\n";
+ err.severity = diag::Severity::Error;
+ }
+ auto file = std::make_shared<Source::File>("spirv", disassembly);
+ for (auto& diag : diags) {
+ diag.source.file = file.get();
+ diag.owned_file = file;
+ }
+ return Failure{diag::List{std::move(diags)}};
+}
+
+} // namespace tint::spirv::validate
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/lang/spirv/validate/validate.h
similarity index 67%
copy from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
copy to src/tint/lang/spirv/validate/validate.h
index 6f0f657..840d90f 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/lang/spirv/validate/validate.h
@@ -25,28 +25,22 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
-#define SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#ifndef SRC_TINT_LANG_SPIRV_VALIDATE_VALIDATE_H_
+#define SRC_TINT_LANG_SPIRV_VALIDATE_VALIDATE_H_
-#include <string>
-
-#include "src/tint/utils/diagnostic/diagnostic.h"
#include "src/tint/utils/result/result.h"
-// Forward declarations.
-namespace tint::core::ir {
-class Module;
-}
+// Forward declarations
+namespace tint {
+class Program;
+} // namespace tint
-namespace tint::wgsl::writer {
+namespace tint::spirv::validate {
-/// RenameConflicts is a transform that renames declarations which prevent identifiers from
-/// resolving to the correct declaration, and those with identical identifiers declared in the same
-/// scope.
-/// @param module the module to transform
-/// @returns success or failure
-Result<SuccessType> RenameConflicts(core::ir::Module* module);
+/// Validate checks that the provided SPIR-V passes validation.
+/// @return success or failure(s)
+Result<SuccessType> Validate(Slice<const uint32_t> spirv);
-} // namespace tint::wgsl::writer
+} // namespace tint::spirv::validate
-#endif // SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#endif // SRC_TINT_LANG_SPIRV_VALIDATE_VALIDATE_H_
diff --git a/src/tint/lang/spirv/validate/validate_test.cc b/src/tint/lang/spirv/validate/validate_test.cc
new file mode 100644
index 0000000..96ba63e
--- /dev/null
+++ b/src/tint/lang/spirv/validate/validate_test.cc
@@ -0,0 +1,113 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "gtest/gtest.h"
+
+#include "src/tint/lang/spirv/validate/validate.h"
+
+namespace tint::spirv::validate {
+namespace {
+
+TEST(SpirvValidateTest, Valid) {
+ uint32_t spirv[] = {
+ 0x07230203, 0x00010600, 0x00070000, 0x00000011, 0x00000000, 0x00020011, 0x00000001,
+ 0x0003000e, 0x00000000, 0x00000001, 0x0005000f, 0x00000005, 0x00000001, 0x6e69616d,
+ 0x00000000, 0x00060010, 0x00000001, 0x00000011, 0x00000001, 0x00000001, 0x00000001,
+ 0x00040005, 0x00000001, 0x6e69616d, 0x00000000, 0x00030005, 0x00000002, 0x0000006d,
+ 0x00020013, 0x00000003, 0x00030021, 0x00000004, 0x00000003, 0x00030016, 0x00000005,
+ 0x00000020, 0x00040017, 0x00000006, 0x00000005, 0x00000003, 0x00040018, 0x00000007,
+ 0x00000006, 0x00000003, 0x00040020, 0x00000008, 0x00000007, 0x00000007, 0x0003002e,
+ 0x00000007, 0x00000009, 0x00040015, 0x0000000a, 0x00000020, 0x00000001, 0x0004002b,
+ 0x0000000a, 0x0000000b, 0x00000001, 0x00040020, 0x0000000c, 0x00000007, 0x00000006,
+ 0x00050036, 0x00000003, 0x00000001, 0x00000000, 0x00000004, 0x000200f8, 0x0000000d,
+ 0x0005003b, 0x00000008, 0x00000002, 0x00000007, 0x00000009, 0x00050041, 0x0000000c,
+ 0x0000000e, 0x00000002, 0x0000000b, 0x0004003d, 0x00000006, 0x0000000f, 0x0000000e,
+ 0x00050051, 0x00000005, 0x00000010, 0x0000000f, 0x00000001, 0x000100fd, 0x00010038,
+ };
+ auto res = Validate(spirv);
+ EXPECT_TRUE(res) << res;
+}
+
+TEST(SpirvValidateTest, Invalid) {
+ uint32_t spirv[] = {
+ 0x07230203, 0x00010600, 0x00070000, 0x00000011, 0x00000000, 0x00020011, 0x00000001,
+ 0x0003000e, 0x00000000, 0x00000001, 0x0005000f, 0x00000005, 0x00000001, 0x6e69616d,
+ 0x00000000, 0x00060010, 0x00000001, 0x00000011, 0x00000001, 0x00000001, 0x00000001,
+ 0x00040005, 0x00000001, 0x6e69616d, 0x00000000, 0x00030005, 0x00000002, 0x0000006d,
+ 0x00020013, 0x00000003, 0x00030021, 0x00000004, 0x00000003, 0x00030016, 0x00000005,
+ 0x00000020, 0x00040017, 0x00000006, 0x00000005, 0x00000003, 0x00040018, 0x00000007,
+ 0x00000006, 0x00000003, 0x00040020, 0x00000008, 0x00000007, 0x00000007, 0x0003002e,
+ 0x00000006, 0x00000009, 0x00040015, 0x0000000a, 0x00000020, 0x00000001, 0x0004002b,
+ 0x0000000a, 0x0000000b, 0x00000001, 0x00040020, 0x0000000c, 0x00000007, 0x00000006,
+ 0x00050036, 0x00000003, 0x00000001, 0x00000000, 0x00000004, 0x000200f8, 0x0000000d,
+ 0x0005003b, 0x00000008, 0x00000002, 0x00000007, 0x00000009, 0x00050041, 0x0000000c,
+ 0x0000000e, 0x00000002, 0x0000000b, 0x0004003d, 0x00000006, 0x0000000f, 0x0000000e,
+ 0x00050051, 0x00000005, 0x00000010, 0x0000000f, 0x00000001, 0x000100fd, 0x00010038,
+ };
+ auto res = Validate(spirv);
+ ASSERT_FALSE(res);
+ EXPECT_EQ(res.Failure().reason.str(), R"(spirv error: SPIR-V failed validation.
+
+Disassembly:
+; SPIR-V
+; Version: 1.6
+; Generator: Khronos SPIR-V Tools Assembler; 0
+; Bound: 17
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %m "m"
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%_ptr_Function_mat3v3float = OpTypePointer Function %mat3v3float
+ %9 = OpConstantNull %v3float
+ %int = OpTypeInt 32 1
+ %int_1 = OpConstant %int 1
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+ %main = OpFunction %void None %4
+ %13 = OpLabel
+ %m = OpVariable %_ptr_Function_mat3v3float Function %9
+ %14 = OpAccessChain %_ptr_Function_v3float %m %int_1
+ %15 = OpLoad %v3float %14
+ %16 = OpCompositeExtract %float %15 1
+ OpReturn
+ OpFunctionEnd
+
+spirv:1:1 error: Initializer type must match the type pointed to by the Result Type
+ %m = OpVariable %_ptr_Function_mat3v3float Function %9
+
+)");
+}
+
+} // namespace
+} // namespace tint::spirv::validate
diff --git a/src/tint/lang/spirv/writer/BUILD.bazel b/src/tint/lang/spirv/writer/BUILD.bazel
index 1525211..9cfb1ed 100644
--- a/src/tint/lang/spirv/writer/BUILD.bazel
+++ b/src/tint/lang/spirv/writer/BUILD.bazel
@@ -39,6 +39,7 @@
cc_library(
name = "writer",
srcs = [
+ "output.cc",
"writer.cc",
],
hdrs = [
@@ -54,8 +55,8 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
- "//src/tint/lang/wgsl/reader/lower",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
@@ -83,11 +84,6 @@
"//src/tint/lang/spirv/writer/raise",
],
"//conditions:default": [],
- }) + select({
- ":tint_build_wgsl_reader": [
- "//src/tint/lang/wgsl/reader/program_to_ir",
- ],
- "//conditions:default": [],
}),
copts = COPTS,
visibility = ["//visibility:public"],
@@ -167,9 +163,12 @@
"//src/tint/cmd/bench:bench",
"//src/tint/lang/core",
"//src/tint/lang/core/constant",
+ "//src/tint/lang/core/ir",
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
@@ -192,6 +191,11 @@
"//src/tint/lang/spirv/writer/common",
],
"//conditions:default": [],
+ }) + select({
+ ":tint_build_wgsl_reader": [
+ "//src/tint/lang/wgsl/reader",
+ ],
+ "//conditions:default": [],
}),
copts = COPTS,
visibility = ["//visibility:public"],
diff --git a/src/tint/lang/spirv/writer/BUILD.cmake b/src/tint/lang/spirv/writer/BUILD.cmake
index 767a497..0720114 100644
--- a/src/tint/lang/spirv/writer/BUILD.cmake
+++ b/src/tint/lang/spirv/writer/BUILD.cmake
@@ -48,6 +48,7 @@
# Condition: TINT_BUILD_SPV_WRITER
################################################################################
tint_add_target(tint_lang_spirv_writer lib
+ lang/spirv/writer/output.cc
lang/spirv/writer/output.h
lang/spirv/writer/writer.cc
lang/spirv/writer/writer.h
@@ -62,8 +63,8 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
- tint_lang_wgsl_reader_lower
tint_lang_wgsl_sem
tint_utils_containers
tint_utils_diagnostic
@@ -95,12 +96,6 @@
)
endif(TINT_BUILD_SPV_WRITER)
-if(TINT_BUILD_WGSL_READER)
- tint_target_add_dependencies(tint_lang_spirv_writer lib
- tint_lang_wgsl_reader_program_to_ir
- )
-endif(TINT_BUILD_WGSL_READER)
-
endif(TINT_BUILD_SPV_WRITER)
if(TINT_BUILD_SPV_WRITER)
################################################################################
@@ -189,9 +184,12 @@
tint_cmd_bench_bench
tint_lang_core
tint_lang_core_constant
+ tint_lang_core_ir
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
@@ -220,4 +218,72 @@
)
endif(TINT_BUILD_SPV_WRITER)
+if(TINT_BUILD_WGSL_READER)
+ tint_target_add_dependencies(tint_lang_spirv_writer_bench bench
+ tint_lang_wgsl_reader
+ )
+endif(TINT_BUILD_WGSL_READER)
+
+endif(TINT_BUILD_SPV_WRITER)
+if(TINT_BUILD_SPV_WRITER)
+################################################################################
+# Target: tint_lang_spirv_writer_fuzz
+# Kind: fuzz
+# Condition: TINT_BUILD_SPV_WRITER
+################################################################################
+tint_add_target(tint_lang_spirv_writer_fuzz fuzz
+ lang/spirv/writer/writer_fuzz.cc
+)
+
+tint_target_add_dependencies(tint_lang_spirv_writer_fuzz fuzz
+ tint_api_common
+ tint_cmd_fuzz_ir_fuzz
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_ir
+ tint_lang_core_type
+ tint_lang_wgsl
+ tint_lang_wgsl_ast
+ tint_lang_wgsl_helpers
+ tint_lang_wgsl_program
+ tint_lang_wgsl_sem
+ tint_utils_bytes
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_symbol
+ tint_utils_text
+ tint_utils_traits
+)
+
+if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+ tint_target_add_dependencies(tint_lang_spirv_writer_fuzz fuzz
+ tint_lang_spirv_validate
+ )
+endif(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+
+if(TINT_BUILD_SPV_WRITER)
+ tint_target_add_dependencies(tint_lang_spirv_writer_fuzz fuzz
+ tint_lang_spirv_writer
+ tint_lang_spirv_writer_common
+ tint_lang_spirv_writer_helpers
+ )
+endif(TINT_BUILD_SPV_WRITER)
+
+if(TINT_BUILD_WGSL_READER)
+ tint_target_add_sources(tint_lang_spirv_writer_fuzz fuzz
+ "lang/spirv/writer/ast_writer_fuzz.cc"
+ )
+ tint_target_add_dependencies(tint_lang_spirv_writer_fuzz fuzz
+ tint_cmd_fuzz_wgsl_fuzz
+ )
+endif(TINT_BUILD_WGSL_READER)
+
endif(TINT_BUILD_SPV_WRITER)
\ No newline at end of file
diff --git a/src/tint/lang/spirv/writer/BUILD.gn b/src/tint/lang/spirv/writer/BUILD.gn
index d9cefee..8045c04 100644
--- a/src/tint/lang/spirv/writer/BUILD.gn
+++ b/src/tint/lang/spirv/writer/BUILD.gn
@@ -44,6 +44,7 @@
if (tint_build_spv_writer) {
libtint_source_set("writer") {
sources = [
+ "output.cc",
"output.h",
"writer.cc",
"writer.h",
@@ -57,8 +58,8 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
- "${tint_src_dir}/lang/wgsl/reader/lower",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
@@ -87,10 +88,6 @@
"${tint_src_dir}/lang/spirv/writer/raise",
]
}
-
- if (tint_build_wgsl_reader) {
- deps += [ "${tint_src_dir}/lang/wgsl/reader/program_to_ir" ]
- }
}
}
if (tint_build_unittests) {
@@ -170,9 +167,12 @@
"${tint_src_dir}/cmd/bench:bench",
"${tint_src_dir}/lang/core",
"${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
@@ -196,6 +196,59 @@
"${tint_src_dir}/lang/spirv/writer/common",
]
}
+
+ if (tint_build_wgsl_reader) {
+ deps += [ "${tint_src_dir}/lang/wgsl/reader" ]
+ }
+ }
+ }
+}
+if (tint_build_spv_writer) {
+ tint_fuzz_source_set("fuzz") {
+ sources = [ "writer_fuzz.cc" ]
+ deps = [
+ "${tint_src_dir}/api/common",
+ "${tint_src_dir}/cmd/fuzz/ir:fuzz",
+ "${tint_src_dir}/lang/core",
+ "${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/lang/wgsl",
+ "${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/helpers",
+ "${tint_src_dir}/lang/wgsl/program",
+ "${tint_src_dir}/lang/wgsl/sem",
+ "${tint_src_dir}/utils/bytes",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+
+ if (tint_build_spv_reader || tint_build_spv_writer) {
+ deps += [ "${tint_src_dir}/lang/spirv/validate" ]
+ }
+
+ if (tint_build_spv_writer) {
+ deps += [
+ "${tint_src_dir}/lang/spirv/writer",
+ "${tint_src_dir}/lang/spirv/writer/common",
+ "${tint_src_dir}/lang/spirv/writer/helpers",
+ ]
+ }
+
+ if (tint_build_wgsl_reader) {
+ sources += [ "ast_writer_fuzz.cc" ]
+ deps += [ "${tint_src_dir}/cmd/fuzz/wgsl:fuzz" ]
}
}
}
diff --git a/src/tint/lang/spirv/writer/ast_printer/BUILD.bazel b/src/tint/lang/spirv/writer/ast_printer/BUILD.bazel
index 40919cf..1b8df51 100644
--- a/src/tint/lang/spirv/writer/ast_printer/BUILD.bazel
+++ b/src/tint/lang/spirv/writer/ast_printer/BUILD.bazel
@@ -56,6 +56,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/helpers",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
@@ -124,11 +125,13 @@
"//src/tint/api/common",
"//src/tint/lang/core",
"//src/tint/lang/core/constant",
+ "//src/tint/lang/core/ir",
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast:test",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/spirv/writer/ast_printer/BUILD.cmake b/src/tint/lang/spirv/writer/ast_printer/BUILD.cmake
index e1f6e05..1acdba0 100644
--- a/src/tint/lang/spirv/writer/ast_printer/BUILD.cmake
+++ b/src/tint/lang/spirv/writer/ast_printer/BUILD.cmake
@@ -57,6 +57,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
+ tint_lang_wgsl_features
tint_lang_wgsl_helpers
tint_lang_wgsl_program
tint_lang_wgsl_sem
@@ -130,11 +131,13 @@
tint_api_common
tint_lang_core
tint_lang_core_constant
+ tint_lang_core_ir
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_ast_test
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
diff --git a/src/tint/lang/spirv/writer/ast_printer/BUILD.gn b/src/tint/lang/spirv/writer/ast_printer/BUILD.gn
index 12b2c96..1ee1bb6 100644
--- a/src/tint/lang/spirv/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/spirv/writer/ast_printer/BUILD.gn
@@ -59,6 +59,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/helpers",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
@@ -127,11 +128,13 @@
"${tint_src_dir}/api/common",
"${tint_src_dir}/lang/core",
"${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast:unittests",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/spirv/writer/ast_printer/builder.cc b/src/tint/lang/spirv/writer/ast_printer/builder.cc
index a75d703..2e1271e 100644
--- a/src/tint/lang/spirv/writer/ast_printer/builder.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/builder.cc
@@ -280,7 +280,6 @@
wgsl::Extension::kChromiumExperimentalDp4A,
wgsl::Extension::kChromiumExperimentalFullPtrParameters,
wgsl::Extension::kChromiumExperimentalPushConstant,
- wgsl::Extension::kChromiumExperimentalReadWriteStorageTexture,
wgsl::Extension::kChromiumExperimentalSubgroups,
wgsl::Extension::kF16,
wgsl::Extension::kChromiumInternalDualSourceBlending,
diff --git a/src/tint/lang/spirv/writer/ast_raise/BUILD.bazel b/src/tint/lang/spirv/writer/ast_raise/BUILD.bazel
index 4dd9ee8..ac25dcc 100644
--- a/src/tint/lang/spirv/writer/ast_raise/BUILD.bazel
+++ b/src/tint/lang/spirv/writer/ast_raise/BUILD.bazel
@@ -63,6 +63,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
@@ -104,6 +105,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/spirv/writer/ast_raise/BUILD.cmake b/src/tint/lang/spirv/writer/ast_raise/BUILD.cmake
index a3ac9dd..b79c8bb 100644
--- a/src/tint/lang/spirv/writer/ast_raise/BUILD.cmake
+++ b/src/tint/lang/spirv/writer/ast_raise/BUILD.cmake
@@ -64,6 +64,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
@@ -108,6 +109,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/spirv/writer/ast_raise/BUILD.gn b/src/tint/lang/spirv/writer/ast_raise/BUILD.gn
index b54c6fc..ba17c58 100644
--- a/src/tint/lang/spirv/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/spirv/writer/ast_raise/BUILD.gn
@@ -66,6 +66,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
@@ -108,6 +109,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/spirv/writer/ast_writer_fuzz.cc b/src/tint/lang/spirv/writer/ast_writer_fuzz.cc
new file mode 100644
index 0000000..7ce83db
--- /dev/null
+++ b/src/tint/lang/spirv/writer/ast_writer_fuzz.cc
@@ -0,0 +1,59 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// GEN_BUILD:CONDITION(tint_build_wgsl_reader)
+
+#include "src/tint/lang/spirv/writer/writer.h"
+
+#include "src/tint/cmd/fuzz/wgsl/fuzz.h"
+#include "src/tint/lang/spirv/validate/validate.h"
+#include "src/tint/lang/wgsl/helpers/apply_substitute_overrides.h"
+
+namespace tint::spirv::writer {
+namespace {
+
+void ASTPrinterFuzzer(const tint::Program& program, const Options& options) {
+ auto transformed = tint::wgsl::ApplySubstituteOverrides(program);
+ auto& no_overrides = transformed ? transformed.value() : program;
+ if (!no_overrides.IsValid()) {
+ return;
+ }
+ auto output = Generate(no_overrides, options);
+ if (!output) {
+ return;
+ }
+ auto& spirv = output->spirv;
+ if (auto res = validate::Validate(Slice(spirv.data(), spirv.size())); !res) {
+ TINT_ICE() << "Output of SPIR-V writer failed to validate with SPIR-V Tools\n"
+ << res.Failure();
+ }
+}
+
+} // namespace
+} // namespace tint::spirv::writer
+
+TINT_WGSL_PROGRAM_FUZZER(tint::spirv::writer::ASTPrinterFuzzer);
diff --git a/src/tint/lang/spirv/writer/common/BUILD.bazel b/src/tint/lang/spirv/writer/common/BUILD.bazel
index 7c07fad..87e23c6 100644
--- a/src/tint/lang/spirv/writer/common/BUILD.bazel
+++ b/src/tint/lang/spirv/writer/common/BUILD.bazel
@@ -65,6 +65,7 @@
"//src/tint/utils/math",
"//src/tint/utils/memory",
"//src/tint/utils/reflection",
+ "//src/tint/utils/result",
"//src/tint/utils/rtti",
"//src/tint/utils/text",
"//src/tint/utils/traits",
diff --git a/src/tint/lang/spirv/writer/common/BUILD.cmake b/src/tint/lang/spirv/writer/common/BUILD.cmake
index 969c5e7..4d4db56 100644
--- a/src/tint/lang/spirv/writer/common/BUILD.cmake
+++ b/src/tint/lang/spirv/writer/common/BUILD.cmake
@@ -66,6 +66,7 @@
tint_utils_math
tint_utils_memory
tint_utils_reflection
+ tint_utils_result
tint_utils_rtti
tint_utils_text
tint_utils_traits
diff --git a/src/tint/lang/spirv/writer/common/BUILD.gn b/src/tint/lang/spirv/writer/common/BUILD.gn
index 0c9830d..c0aa3c5 100644
--- a/src/tint/lang/spirv/writer/common/BUILD.gn
+++ b/src/tint/lang/spirv/writer/common/BUILD.gn
@@ -68,6 +68,7 @@
"${tint_src_dir}/utils/math",
"${tint_src_dir}/utils/memory",
"${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
"${tint_src_dir}/utils/rtti",
"${tint_src_dir}/utils/text",
"${tint_src_dir}/utils/traits",
diff --git a/src/tint/lang/spirv/writer/common/option_helper.cc b/src/tint/lang/spirv/writer/common/option_helper.cc
index dc3670b..aec904a 100644
--- a/src/tint/lang/spirv/writer/common/option_helper.cc
+++ b/src/tint/lang/spirv/writer/common/option_helper.cc
@@ -27,11 +27,15 @@
#include "src/tint/lang/spirv/writer/common/option_helpers.h"
+#include <utility>
+
#include "src/tint/utils/containers/hashset.h"
namespace tint::spirv::writer {
-bool ValidateBindingOptions(const Options& options, diag::List& diagnostics) {
+Result<SuccessType> ValidateBindingOptions(const Options& options) {
+ diag::List diagnostics;
+
tint::Hashmap<tint::BindingPoint, binding::BindingInfo, 8> seen_wgsl_bindings{};
tint::Hashmap<binding::BindingInfo, tint::BindingPoint, 8> seen_spirv_bindings{};
@@ -88,23 +92,23 @@
if (!valid(options.bindings.uniform)) {
diagnostics.add_note(diag::System::Writer, "when processing uniform", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
if (!valid(options.bindings.storage)) {
diagnostics.add_note(diag::System::Writer, "when processing storage", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
if (!valid(options.bindings.texture)) {
diagnostics.add_note(diag::System::Writer, "when processing texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
if (!valid(options.bindings.storage_texture)) {
diagnostics.add_note(diag::System::Writer, "when processing storage_texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
if (!valid(options.bindings.sampler)) {
diagnostics.add_note(diag::System::Writer, "when processing sampler", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
for (const auto& it : options.bindings.external_texture) {
@@ -116,24 +120,24 @@
// Validate with the actual source regardless of what the remapper will do
if (wgsl_seen(src_binding, plane0)) {
diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
if (spirv_seen(plane0, src_binding)) {
diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
if (spirv_seen(plane1, src_binding)) {
diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
if (spirv_seen(metadata, src_binding)) {
diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
- return false;
+ return Failure{std::move(diagnostics)};
}
}
- return true;
+ return Success;
}
// The remapped binding data and external texture data need to coordinate in order to put things in
diff --git a/src/tint/lang/spirv/writer/common/option_helpers.h b/src/tint/lang/spirv/writer/common/option_helpers.h
index 0be6d35..3f51355 100644
--- a/src/tint/lang/spirv/writer/common/option_helpers.h
+++ b/src/tint/lang/spirv/writer/common/option_helpers.h
@@ -34,14 +34,15 @@
#include "src/tint/api/options/external_texture.h"
#include "src/tint/lang/spirv/writer/common/options.h"
#include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/result/result.h"
namespace tint::spirv::writer {
using RemapperData = std::unordered_map<BindingPoint, BindingPoint>;
/// @param options the options
-/// @returns true if the binding points are valid
-bool ValidateBindingOptions(const Options& options, diag::List& diagnostics);
+/// @return success or failure
+Result<SuccessType> ValidateBindingOptions(const Options& options);
/// Populates data from the writer options for the remapper and external texture.
/// @param options the writer options
diff --git a/src/tint/lang/spirv/writer/common/options.h b/src/tint/lang/spirv/writer/common/options.h
index 46718d2..f5c7897 100644
--- a/src/tint/lang/spirv/writer/common/options.h
+++ b/src/tint/lang/spirv/writer/common/options.h
@@ -138,9 +138,6 @@
/// Set to `true` to always pass matrices to user functions by pointer instead of by value.
bool pass_matrix_by_pointer = false;
- /// Set to `true` to generate SPIR-V via the Tint IR instead of from the AST.
- bool use_tint_ir = false;
-
/// Set to `true` to require `SPV_KHR_subgroup_uniform_control_flow` extension and
/// `SubgroupUniformControlFlowKHR` execution mode for compute stage entry points in generated
/// SPIRV module. Issue: dawn:464
@@ -157,7 +154,6 @@
use_zero_initialize_workgroup_memory_extension,
emit_vertex_point_size,
clamp_frag_depth,
- use_tint_ir,
experimental_require_subgroup_uniform_control_flow,
bindings);
};
diff --git a/src/tint/lang/spirv/writer/discard_test.cc b/src/tint/lang/spirv/writer/discard_test.cc
index 5398726..5e9ccf9 100644
--- a/src/tint/lang/spirv/writer/discard_test.cc
+++ b/src/tint/lang/spirv/writer/discard_test.cc
@@ -85,5 +85,61 @@
)");
}
+TEST_F(SpirvWriterTest, DiscardBeforeAtomic) {
+ auto* buffer = b.Var("buffer", ty.ptr(storage, ty.atomic<i32>()));
+ buffer->SetBindingPoint(0, 0);
+ mod.root_block->Append(buffer);
+
+ auto* front_facing = b.FunctionParam("front_facing", ty.bool_());
+ front_facing->SetBuiltin(core::ir::FunctionParam::Builtin::kFrontFacing);
+ auto* ep = b.Function("ep", ty.f32(), core::ir::Function::PipelineStage::kFragment);
+ ep->SetParams({front_facing});
+ ep->SetReturnLocation(0_u, {});
+
+ b.Append(ep->Block(), [&] {
+ auto* ifelse = b.If(front_facing);
+ b.Append(ifelse->True(), [&] { //
+ b.Discard();
+ b.ExitIf(ifelse);
+ });
+ b.Call(ty.i32(), core::BuiltinFn::kAtomicAdd, buffer, 1_i);
+ b.Return(ep, 0.5_f);
+ });
+
+ ASSERT_TRUE(Generate()) << Error() << output_;
+ EXPECT_INST(R"(
+ ; Function ep_inner
+ %ep_inner = OpFunction %float None %16
+%front_facing = OpFunctionParameter %bool
+ %17 = OpLabel
+ OpSelectionMerge %18 None
+ OpBranchConditional %front_facing %19 %18
+ %19 = OpLabel
+ OpStore %continue_execution %false
+ OpBranch %18
+ %18 = OpLabel
+ %21 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
+ %25 = OpLoad %bool %continue_execution
+ OpSelectionMerge %26 None
+ OpBranchConditional %25 %27 %28
+ %27 = OpLabel
+ %29 = OpAtomicIAdd %int %21 %uint_1 %uint_0 %int_1
+ OpBranch %26
+ %28 = OpLabel
+ OpBranch %26
+ %26 = OpLabel
+ %32 = OpPhi %int %29 %27 %33 %28
+ %34 = OpLoad %bool %continue_execution
+ %35 = OpLogicalEqual %bool %34 %false
+ OpSelectionMerge %36 None
+ OpBranchConditional %35 %37 %36
+ %37 = OpLabel
+ OpKill
+ %36 = OpLabel
+ OpReturnValue %float_0_5
+ OpFunctionEnd
+)");
+}
+
} // namespace
} // namespace tint::spirv::writer
diff --git a/src/tint/lang/spirv/writer/helpers/BUILD.bazel b/src/tint/lang/spirv/writer/helpers/BUILD.bazel
index 50b7a44..e8b7913 100644
--- a/src/tint/lang/spirv/writer/helpers/BUILD.bazel
+++ b/src/tint/lang/spirv/writer/helpers/BUILD.bazel
@@ -39,18 +39,22 @@
cc_library(
name = "helpers",
srcs = [
+ "ast_generate_bindings.cc",
"generate_bindings.cc",
],
hdrs = [
+ "ast_generate_bindings.h",
"generate_bindings.h",
],
deps = [
"//src/tint/api/common",
"//src/tint/lang/core",
"//src/tint/lang/core/constant",
+ "//src/tint/lang/core/ir",
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/spirv/writer/helpers/BUILD.cmake b/src/tint/lang/spirv/writer/helpers/BUILD.cmake
index d6b94dd..08da907 100644
--- a/src/tint/lang/spirv/writer/helpers/BUILD.cmake
+++ b/src/tint/lang/spirv/writer/helpers/BUILD.cmake
@@ -41,6 +41,8 @@
# Condition: TINT_BUILD_SPV_WRITER
################################################################################
tint_add_target(tint_lang_spirv_writer_helpers lib
+ lang/spirv/writer/helpers/ast_generate_bindings.cc
+ lang/spirv/writer/helpers/ast_generate_bindings.h
lang/spirv/writer/helpers/generate_bindings.cc
lang/spirv/writer/helpers/generate_bindings.h
)
@@ -49,9 +51,11 @@
tint_api_common
tint_lang_core
tint_lang_core_constant
+ tint_lang_core_ir
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/spirv/writer/helpers/BUILD.gn b/src/tint/lang/spirv/writer/helpers/BUILD.gn
index a1f5bb3..d0fc799 100644
--- a/src/tint/lang/spirv/writer/helpers/BUILD.gn
+++ b/src/tint/lang/spirv/writer/helpers/BUILD.gn
@@ -40,6 +40,8 @@
if (tint_build_spv_writer) {
libtint_source_set("helpers") {
sources = [
+ "ast_generate_bindings.cc",
+ "ast_generate_bindings.h",
"generate_bindings.cc",
"generate_bindings.h",
]
@@ -47,9 +49,11 @@
"${tint_src_dir}/api/common",
"${tint_src_dir}/lang/core",
"${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/spirv/writer/helpers/ast_generate_bindings.cc b/src/tint/lang/spirv/writer/helpers/ast_generate_bindings.cc
new file mode 100644
index 0000000..cd40f27
--- /dev/null
+++ b/src/tint/lang/spirv/writer/helpers/ast_generate_bindings.cc
@@ -0,0 +1,123 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/spirv/writer/helpers/ast_generate_bindings.h"
+
+#include <algorithm>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "src/tint/api/common/binding_point.h"
+#include "src/tint/lang/core/type/external_texture.h"
+#include "src/tint/lang/core/type/storage_texture.h"
+#include "src/tint/lang/wgsl/ast/module.h"
+#include "src/tint/lang/wgsl/program/program.h"
+#include "src/tint/lang/wgsl/sem/variable.h"
+#include "src/tint/utils/containers/hashmap.h"
+#include "src/tint/utils/containers/vector.h"
+#include "src/tint/utils/rtti/switch.h"
+
+namespace tint::spirv::writer {
+
+Bindings GenerateBindings(const Program& program) {
+ // TODO(tint:1491): Use Inspector once we can get binding info for all
+ // variables, not just those referenced by entry points.
+
+ Bindings bindings{};
+
+ // Collect next valid binding number per group
+ Hashmap<uint32_t, uint32_t, 4> group_to_next_binding_number;
+ Vector<tint::BindingPoint, 4> ext_tex_bps;
+ for (auto* var : program.AST().GlobalVariables()) {
+ if (auto* sem_var = program.Sem().Get(var)->As<sem::GlobalVariable>()) {
+ if (auto bp = sem_var->Attributes().binding_point) {
+ if (auto val = group_to_next_binding_number.Find(bp->group)) {
+ *val = std::max(*val, bp->binding + 1);
+ } else {
+ group_to_next_binding_number.Add(bp->group, bp->binding + 1);
+ }
+
+ // Store up the external textures, we'll add them in the next step
+ if (sem_var->Type()->UnwrapRef()->Is<core::type::ExternalTexture>()) {
+ ext_tex_bps.Push(*bp);
+ continue;
+ }
+
+ binding::BindingInfo info{bp->group, bp->binding};
+ switch (sem_var->AddressSpace()) {
+ case core::AddressSpace::kHandle:
+ Switch(
+ sem_var->Type()->UnwrapRef(), //
+ [&](const core::type::Sampler*) {
+ bindings.sampler.emplace(*bp, info);
+ },
+ [&](const core::type::StorageTexture*) {
+ bindings.storage_texture.emplace(*bp, info);
+ },
+ [&](const core::type::Texture*) {
+ bindings.texture.emplace(*bp, info);
+ });
+ break;
+ case core::AddressSpace::kStorage:
+ bindings.storage.emplace(*bp, info);
+ break;
+ case core::AddressSpace::kUniform:
+ bindings.uniform.emplace(*bp, info);
+ break;
+
+ case core::AddressSpace::kUndefined:
+ case core::AddressSpace::kPixelLocal:
+ case core::AddressSpace::kPrivate:
+ case core::AddressSpace::kPushConstant:
+ case core::AddressSpace::kIn:
+ case core::AddressSpace::kOut:
+ case core::AddressSpace::kFunction:
+ case core::AddressSpace::kWorkgroup:
+ break;
+ }
+ }
+ }
+ }
+
+ for (auto bp : ext_tex_bps) {
+ uint32_t g = bp.group;
+ uint32_t next_num = *(group_to_next_binding_number.GetOrZero(g));
+
+ binding::BindingInfo plane0{bp.group, bp.binding};
+ binding::BindingInfo plane1{g, next_num++};
+ binding::BindingInfo metadata{g, next_num++};
+
+ group_to_next_binding_number.Replace(g, next_num);
+
+ bindings.external_texture.emplace(bp, binding::ExternalTexture{metadata, plane0, plane1});
+ }
+
+ return bindings;
+}
+
+} // namespace tint::spirv::writer
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/lang/spirv/writer/helpers/ast_generate_bindings.h
similarity index 66%
copy from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
copy to src/tint/lang/spirv/writer/helpers/ast_generate_bindings.h
index 6f0f657..ae4c1b6 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/lang/spirv/writer/helpers/ast_generate_bindings.h
@@ -25,28 +25,20 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
-#define SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#ifndef SRC_TINT_LANG_SPIRV_WRITER_HELPERS_AST_GENERATE_BINDINGS_H_
+#define SRC_TINT_LANG_SPIRV_WRITER_HELPERS_AST_GENERATE_BINDINGS_H_
-#include <string>
+#include "src/tint/lang/spirv/writer/common/options.h"
-#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/result/result.h"
-
-// Forward declarations.
-namespace tint::core::ir {
-class Module;
+// Forward declarations
+namespace tint {
+class Program;
}
-namespace tint::wgsl::writer {
+namespace tint::spirv::writer {
-/// RenameConflicts is a transform that renames declarations which prevent identifiers from
-/// resolving to the correct declaration, and those with identical identifiers declared in the same
-/// scope.
-/// @param module the module to transform
-/// @returns success or failure
-Result<SuccessType> RenameConflicts(core::ir::Module* module);
+Bindings GenerateBindings(const Program& program);
-} // namespace tint::wgsl::writer
+} // namespace tint::spirv::writer
-#endif // SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#endif // SRC_TINT_LANG_SPIRV_WRITER_HELPERS_AST_GENERATE_BINDINGS_H_
diff --git a/src/tint/lang/spirv/writer/helpers/generate_bindings.cc b/src/tint/lang/spirv/writer/helpers/generate_bindings.cc
index 076a594..1cf3b6a 100644
--- a/src/tint/lang/spirv/writer/helpers/generate_bindings.cc
+++ b/src/tint/lang/spirv/writer/helpers/generate_bindings.cc
@@ -28,78 +28,76 @@
#include "src/tint/lang/spirv/writer/helpers/generate_bindings.h"
#include <algorithm>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
#include "src/tint/api/common/binding_point.h"
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/core/ir/var.h"
#include "src/tint/lang/core/type/external_texture.h"
+#include "src/tint/lang/core/type/pointer.h"
#include "src/tint/lang/core/type/storage_texture.h"
-#include "src/tint/lang/wgsl/ast/module.h"
-#include "src/tint/lang/wgsl/program/program.h"
-#include "src/tint/lang/wgsl/sem/variable.h"
#include "src/tint/utils/containers/hashmap.h"
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/rtti/switch.h"
namespace tint::spirv::writer {
-Bindings GenerateBindings(const Program& program) {
- // TODO(tint:1491): Use Inspector once we can get binding info for all
- // variables, not just those referenced by entry points.
-
+Bindings GenerateBindings(const core::ir::Module& module) {
Bindings bindings{};
+ if (!module.root_block) {
+ return bindings;
+ }
// Collect next valid binding number per group
Hashmap<uint32_t, uint32_t, 4> group_to_next_binding_number;
Vector<tint::BindingPoint, 4> ext_tex_bps;
- for (auto* var : program.AST().GlobalVariables()) {
- if (auto* sem_var = program.Sem().Get(var)->As<sem::GlobalVariable>()) {
- if (auto bp = sem_var->Attributes().binding_point) {
- if (auto val = group_to_next_binding_number.Find(bp->group)) {
- *val = std::max(*val, bp->binding + 1);
- } else {
- group_to_next_binding_number.Add(bp->group, bp->binding + 1);
- }
+ for (auto* inst : *module.root_block) {
+ if (!inst->Alive()) {
+ continue;
+ }
+ auto* var = inst->As<core::ir::Var>();
+ if (auto bp = var->BindingPoint()) {
+ if (auto val = group_to_next_binding_number.Find(bp->group)) {
+ *val = std::max(*val, bp->binding + 1);
+ } else {
+ group_to_next_binding_number.Add(bp->group, bp->binding + 1);
+ }
- // Store up the external textures, we'll add them in the next step
- if (sem_var->Type()->UnwrapRef()->Is<core::type::ExternalTexture>()) {
- ext_tex_bps.Push(*bp);
- continue;
- }
+ auto* ptr = var->Result(0)->Type()->As<core::type::Pointer>();
+ auto* ty = ptr->UnwrapPtr();
- binding::BindingInfo info{bp->group, bp->binding};
- switch (sem_var->AddressSpace()) {
- case core::AddressSpace::kHandle:
- Switch(
- sem_var->Type()->UnwrapRef(), //
- [&](const core::type::Sampler*) {
- bindings.sampler.emplace(*bp, info);
- },
- [&](const core::type::StorageTexture*) {
- bindings.storage_texture.emplace(*bp, info);
- },
- [&](const core::type::Texture*) {
- bindings.texture.emplace(*bp, info);
- });
- break;
- case core::AddressSpace::kStorage:
- bindings.storage.emplace(*bp, info);
- break;
- case core::AddressSpace::kUniform:
- bindings.uniform.emplace(*bp, info);
- break;
+ // Store up the external textures, we'll add them in the next step
+ if (ty->Is<core::type::ExternalTexture>()) {
+ ext_tex_bps.Push(*bp);
+ continue;
+ }
- case core::AddressSpace::kUndefined:
- case core::AddressSpace::kPixelLocal:
- case core::AddressSpace::kPrivate:
- case core::AddressSpace::kPushConstant:
- case core::AddressSpace::kIn:
- case core::AddressSpace::kOut:
- case core::AddressSpace::kFunction:
- case core::AddressSpace::kWorkgroup:
- break;
- }
+ binding::BindingInfo info{bp->group, bp->binding};
+ switch (ptr->AddressSpace()) {
+ case core::AddressSpace::kHandle:
+ Switch(
+ ptr->UnwrapPtr(), //
+ [&](const core::type::Sampler*) { bindings.sampler.emplace(*bp, info); },
+ [&](const core::type::StorageTexture*) {
+ bindings.storage_texture.emplace(*bp, info);
+ },
+ [&](const core::type::Texture*) { bindings.texture.emplace(*bp, info); });
+ break;
+ case core::AddressSpace::kStorage:
+ bindings.storage.emplace(*bp, info);
+ break;
+ case core::AddressSpace::kUniform:
+ bindings.uniform.emplace(*bp, info);
+ break;
+
+ case core::AddressSpace::kUndefined:
+ case core::AddressSpace::kPixelLocal:
+ case core::AddressSpace::kPrivate:
+ case core::AddressSpace::kPushConstant:
+ case core::AddressSpace::kIn:
+ case core::AddressSpace::kOut:
+ case core::AddressSpace::kFunction:
+ case core::AddressSpace::kWorkgroup:
+ break;
}
}
}
diff --git a/src/tint/lang/spirv/writer/helpers/generate_bindings.h b/src/tint/lang/spirv/writer/helpers/generate_bindings.h
index 8b3c3c7..b79d3af 100644
--- a/src/tint/lang/spirv/writer/helpers/generate_bindings.h
+++ b/src/tint/lang/spirv/writer/helpers/generate_bindings.h
@@ -31,13 +31,13 @@
#include "src/tint/lang/spirv/writer/common/options.h"
// Forward declarations
-namespace tint {
-class Program;
+namespace tint::core::ir {
+class Module;
}
namespace tint::spirv::writer {
-Bindings GenerateBindings(const Program& program);
+Bindings GenerateBindings(const core::ir::Module& module);
} // namespace tint::spirv::writer
diff --git a/src/tint/lang/spirv/writer/if_test.cc b/src/tint/lang/spirv/writer/if_test.cc
index a91ab22..321ed89 100644
--- a/src/tint/lang/spirv/writer/if_test.cc
+++ b/src/tint/lang/spirv/writer/if_test.cc
@@ -241,6 +241,34 @@
)");
}
+TEST_F(SpirvWriterTest, If_Phi_SingleValue_ImplicitFalse) {
+ auto* func = b.Function("foo", ty.i32());
+ b.Append(func->Block(), [&] {
+ auto* i = b.If(true);
+ i->SetResults(b.InstructionResult(ty.i32()));
+ b.Append(i->True(), [&] { //
+ b.ExitIf(i, 10_i);
+ });
+ b.Return(func, i);
+ });
+
+ ASSERT_TRUE(Generate()) << Error() << output_;
+ EXPECT_INST("%12 = OpUndef %int");
+ EXPECT_INST(R"(
+ %4 = OpLabel
+ OpSelectionMerge %5 None
+ OpBranchConditional %true %6 %7
+ %6 = OpLabel
+ OpBranch %5
+ %7 = OpLabel
+ OpBranch %5
+ %5 = OpLabel
+ %10 = OpPhi %int %int_10 %6 %12 %7
+ OpReturnValue %10
+ OpFunctionEnd
+)");
+}
+
TEST_F(SpirvWriterTest, If_Phi_MultipleValue_0) {
auto* func = b.Function("foo", ty.i32());
b.Append(func->Block(), [&] {
@@ -315,7 +343,7 @@
b.Append(inner->False(), [&] { //
b.ExitIf(inner, 20_i);
});
- b.ExitIf(outer, inner->Result());
+ b.ExitIf(outer, inner->Result(0));
});
b.Append(outer->False(), [&] { //
b.ExitIf(outer, 30_i);
diff --git a/src/tint/lang/spirv/writer/loop_test.cc b/src/tint/lang/spirv/writer/loop_test.cc
index 332c52a..633eb9b 100644
--- a/src/tint/lang/spirv/writer/loop_test.cc
+++ b/src/tint/lang/spirv/writer/loop_test.cc
@@ -460,7 +460,7 @@
b.Append(inner->False(), [&] { //
b.ExitIf(inner, 20_i);
});
- b.Continue(loop, inner->Result());
+ b.Continue(loop, inner->Result(0));
});
auto* cont_param = b.BlockParam(ty.i32());
@@ -572,5 +572,54 @@
)");
}
+TEST_F(SpirvWriterTest, Loop_Phi_NestedIfWithResultAndImplicitFalse_InContinuing) {
+ auto* func = b.Function("foo", ty.void_());
+
+ b.Append(func->Block(), [&] {
+ auto* loop = b.Loop();
+
+ b.Append(loop->Body(), [&] { //
+ b.Continue(loop);
+ });
+
+ b.Append(loop->Continuing(), [&] {
+ auto* if_ = b.If(true);
+ auto* cond = b.InstructionResult(ty.bool_());
+ if_->SetResults(Vector{cond});
+ b.Append(if_->True(), [&] { //
+ b.ExitIf(if_, true);
+ });
+ b.BreakIf(loop, cond);
+ });
+
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << Error() << output_;
+ EXPECT_INST("%15 = OpUndef %bool");
+ EXPECT_INST(R"(
+ %4 = OpLabel
+ OpBranch %7
+ %7 = OpLabel
+ OpLoopMerge %8 %6 None
+ OpBranch %5
+ %5 = OpLabel
+ OpBranch %6
+ %6 = OpLabel
+ OpSelectionMerge %9 None
+ OpBranchConditional %true %10 %11
+ %10 = OpLabel
+ OpBranch %9
+ %11 = OpLabel
+ OpBranch %9
+ %9 = OpLabel
+ %14 = OpPhi %bool %true %10 %15 %11
+ OpBranchConditional %14 %8 %7
+ %8 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)");
+}
+
} // namespace
} // namespace tint::spirv::writer
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/lang/spirv/writer/output.cc
similarity index 65%
copy from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
copy to src/tint/lang/spirv/writer/output.cc
index 6f0f657..ec197e5 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/lang/spirv/writer/output.cc
@@ -25,28 +25,16 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
-#define SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#include "src/tint/lang/spirv/writer/output.h"
-#include <string>
+namespace tint::spirv::writer {
-#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/result/result.h"
+Output::Output() = default;
-// Forward declarations.
-namespace tint::core::ir {
-class Module;
-}
+Output::~Output() = default;
-namespace tint::wgsl::writer {
+Output::Output(const Output&) = default;
-/// RenameConflicts is a transform that renames declarations which prevent identifiers from
-/// resolving to the correct declaration, and those with identical identifiers declared in the same
-/// scope.
-/// @param module the module to transform
-/// @returns success or failure
-Result<SuccessType> RenameConflicts(core::ir::Module* module);
+Output& Output::operator=(const Output&) = default;
-} // namespace tint::wgsl::writer
-
-#endif // SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+} // namespace tint::spirv::writer
diff --git a/src/tint/lang/spirv/writer/output.h b/src/tint/lang/spirv/writer/output.h
index e14f7b1..c6b6e3c 100644
--- a/src/tint/lang/spirv/writer/output.h
+++ b/src/tint/lang/spirv/writer/output.h
@@ -28,6 +28,7 @@
#ifndef SRC_TINT_LANG_SPIRV_WRITER_OUTPUT_H_
#define SRC_TINT_LANG_SPIRV_WRITER_OUTPUT_H_
+#include <cstdint>
#include <string>
#include <vector>
@@ -44,6 +45,10 @@
/// Copy constructor
Output(const Output&);
+ /// Copy assignment
+ /// @returns this
+ Output& operator=(const Output&);
+
/// The generated SPIR-V.
std::vector<uint32_t> spirv;
};
diff --git a/src/tint/lang/spirv/writer/printer/BUILD.bazel b/src/tint/lang/spirv/writer/printer/BUILD.bazel
index 1488b1e..1c64224 100644
--- a/src/tint/lang/spirv/writer/printer/BUILD.bazel
+++ b/src/tint/lang/spirv/writer/printer/BUILD.bazel
@@ -57,6 +57,7 @@
"//src/tint/lang/spirv/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/spirv/writer/printer/BUILD.cmake b/src/tint/lang/spirv/writer/printer/BUILD.cmake
index 1118e66..6002e0c 100644
--- a/src/tint/lang/spirv/writer/printer/BUILD.cmake
+++ b/src/tint/lang/spirv/writer/printer/BUILD.cmake
@@ -58,6 +58,7 @@
tint_lang_spirv_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/spirv/writer/printer/BUILD.gn b/src/tint/lang/spirv/writer/printer/BUILD.gn
index ab8d4f1..58b49ef 100644
--- a/src/tint/lang/spirv/writer/printer/BUILD.gn
+++ b/src/tint/lang/spirv/writer/printer/BUILD.gn
@@ -56,6 +56,7 @@
"${tint_src_dir}/lang/spirv/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index a7c86b8..add607e 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -261,13 +261,13 @@
Hashmap<const core::type::Type*, uint32_t, 4> undef_values_;
/// The map of non-constant values to their result IDs.
- Hashmap<core::ir::Value*, uint32_t, 8> values_;
+ Hashmap<const core::ir::Value*, uint32_t, 8> values_;
/// The map of blocks to the IDs of their label instructions.
- Hashmap<core::ir::Block*, uint32_t, 8> block_labels_;
+ Hashmap<const core::ir::Block*, uint32_t, 8> block_labels_;
/// The map of control instructions to the IDs of the label of their SPIR-V merge blocks.
- Hashmap<core::ir::ControlInstruction*, uint32_t, 8> merge_block_labels_;
+ Hashmap<const core::ir::ControlInstruction*, uint32_t, 8> merge_block_labels_;
/// The map of extended instruction set names to their result IDs.
Hashmap<std::string_view, uint32_t, 2> imports_;
@@ -304,7 +304,7 @@
EmitRootBlock(ir_.root_block);
// Emit functions.
- for (auto* func : ir_.functions) {
+ for (core::ir::Function* func : ir_.functions) {
EmitFunction(func);
}
@@ -538,7 +538,7 @@
/// Get the result ID of the instruction result `value`, emitting its instruction if necessary.
/// @param inst the instruction to get the ID for
/// @returns the result ID of the instruction
- uint32_t Value(core::ir::Instruction* inst) { return Value(inst->Result()); }
+ uint32_t Value(core::ir::Instruction* inst) { return Value(inst->Result(0)); }
/// Get the result ID of the value `value`, emitting its instruction if necessary.
/// @param value the value to get the ID for
@@ -555,7 +555,7 @@
/// Get the ID of the label for `block`.
/// @param block the block to get the label ID for
/// @returns the ID of the block's label
- uint32_t Label(core::ir::Block* block) {
+ uint32_t Label(const core::ir::Block* block) {
return block_labels_.GetOrCreate(block, [&] { return module_.NextId(); });
}
@@ -781,7 +781,7 @@
continue;
}
- auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+ auto* ptr = var->Result(0)->Type()->As<core::type::Pointer>();
if (!(ptr->AddressSpace() == core::AddressSpace::kIn ||
ptr->AddressSpace() == core::AddressSpace::kOut)) {
continue;
@@ -789,7 +789,7 @@
// Determine if this IO variable is used by the entry point.
bool used = false;
- for (const auto& use : var->Result()->Usages()) {
+ for (const auto& use : var->Result(0)->Usages()) {
auto* block = use.instruction->Block();
while (block->Parent()) {
block = block->Parent()->Block();
@@ -837,7 +837,11 @@
// If there are no instructions in the block, it's a dead end, so we shouldn't be able to
// get here to begin with.
if (block->IsEmpty()) {
- current_function_.push_inst(spv::Op::OpUnreachable, {});
+ if (!block->Parent()->Results().IsEmpty()) {
+ current_function_.push_inst(spv::Op::OpBranch, {GetMergeLabel(block->Parent())});
+ } else {
+ current_function_.push_inst(spv::Op::OpUnreachable, {});
+ }
return;
}
@@ -897,7 +901,7 @@
TINT_ICE_ON_NO_MATCH);
// Set the name for the SPIR-V result ID if provided in the module.
- if (inst->Result() && !inst->Is<core::ir::Var>()) {
+ if (inst->Result(0) && !inst->Is<core::ir::Var>()) {
if (auto name = ir_.NameOf(inst)) {
module_.PushDebug(spv::Op::OpName, {Value(inst), Operand(name.Name())});
}
@@ -974,12 +978,12 @@
uint32_t true_label = merge_label;
uint32_t false_label = merge_label;
- if (true_block->Length() > 1 || i->HasResults() ||
- (true_block->HasTerminator() && !true_block->Terminator()->Is<core::ir::ExitIf>())) {
+ if (true_block->Length() > 1 || !i->Results().IsEmpty() ||
+ (true_block->Terminator() && !true_block->Terminator()->Is<core::ir::ExitIf>())) {
true_label = Label(true_block);
}
- if (false_block->Length() > 1 || i->HasResults() ||
- (false_block->HasTerminator() && !false_block->Terminator()->Is<core::ir::ExitIf>())) {
+ if (false_block->Length() > 1 || !i->Results().IsEmpty() ||
+ (false_block->Terminator() && !false_block->Terminator()->Is<core::ir::ExitIf>())) {
false_label = Label(false_block);
}
@@ -1006,7 +1010,7 @@
/// Emit an access instruction
/// @param access the access instruction to emit
void EmitAccess(core::ir::Access* access) {
- auto* ty = access->Result()->Type();
+ auto* ty = access->Result(0)->Type();
auto id = Value(access);
OperandList operands = {Type(ty), id, Value(access->Object())};
@@ -1060,7 +1064,7 @@
auto id = Value(binary);
auto lhs = Value(binary->LHS());
auto rhs = Value(binary->RHS());
- auto* ty = binary->Result()->Type();
+ auto* ty = binary->Result(0)->Type();
auto* lhs_ty = binary->LHS()->Type();
// Determine the opcode.
@@ -1206,9 +1210,9 @@
/// Emit a bitcast instruction.
/// @param bitcast the bitcast instruction to emit
void EmitBitcast(core::ir::Bitcast* bitcast) {
- auto* ty = bitcast->Result()->Type();
+ auto* ty = bitcast->Result(0)->Type();
if (ty == bitcast->Val()->Type()) {
- values_.Add(bitcast->Result(), Value(bitcast->Val()));
+ values_.Add(bitcast->Result(0), Value(bitcast->Val()));
return;
}
current_function_.push_inst(spv::Op::OpBitcast,
@@ -1341,8 +1345,8 @@
}
OperandList operands;
- if (!builtin->Result()->Type()->Is<core::type::Void>()) {
- operands = {Type(builtin->Result()->Type()), id};
+ if (!builtin->Result(0)->Type()->Is<core::type::Void>()) {
+ operands = {Type(builtin->Result(0)->Type()), id};
}
for (auto* arg : builtin->Args()) {
operands.push_back(Value(arg));
@@ -1353,19 +1357,19 @@
/// Emit a builtin function call instruction.
/// @param builtin the builtin call instruction to emit
void EmitCoreBuiltinCall(core::ir::CoreBuiltinCall* builtin) {
- auto* result_ty = builtin->Result()->Type();
+ auto* result_ty = builtin->Result(0)->Type();
if (builtin->Func() == core::BuiltinFn::kAbs &&
result_ty->is_unsigned_integer_scalar_or_vector()) {
// abs() is a no-op for unsigned integers.
- values_.Add(builtin->Result(), Value(builtin->Args()[0]));
+ values_.Add(builtin->Result(0), Value(builtin->Args()[0]));
return;
}
if ((builtin->Func() == core::BuiltinFn::kAll ||
builtin->Func() == core::BuiltinFn::kAny) &&
builtin->Args()[0]->Type()->Is<core::type::Bool>()) {
// all() and any() are passthroughs for scalar arguments.
- values_.Add(builtin->Result(), Value(builtin->Args()[0]));
+ values_.Add(builtin->Result(0), Value(builtin->Args()[0]));
return;
}
@@ -1710,12 +1714,12 @@
// If there is just a single argument with the same type as the result, this is an identity
// constructor and we can just pass through the ID of the argument.
if (construct->Args().Length() == 1 &&
- construct->Result()->Type() == construct->Args()[0]->Type()) {
- values_.Add(construct->Result(), Value(construct->Args()[0]));
+ construct->Result(0)->Type() == construct->Args()[0]->Type()) {
+ values_.Add(construct->Result(0), Value(construct->Args()[0]));
return;
}
- OperandList operands = {Type(construct->Result()->Type()), Value(construct)};
+ OperandList operands = {Type(construct->Result(0)->Type()), Value(construct)};
for (auto* arg : construct->Args()) {
operands.push_back(Value(arg));
}
@@ -1725,10 +1729,10 @@
/// Emit a convert instruction.
/// @param convert the convert instruction to emit
void EmitConvert(core::ir::Convert* convert) {
- auto* res_ty = convert->Result()->Type();
+ auto* res_ty = convert->Result(0)->Type();
auto* arg_ty = convert->Args()[0]->Type();
- OperandList operands = {Type(convert->Result()->Type()), Value(convert)};
+ OperandList operands = {Type(convert->Result(0)->Type()), Value(convert)};
for (auto* arg : convert->Args()) {
operands.push_back(Value(arg));
}
@@ -1810,21 +1814,21 @@
/// @param load the load instruction to emit
void EmitLoad(core::ir::Load* load) {
current_function_.push_inst(
- spv::Op::OpLoad, {Type(load->Result()->Type()), Value(load), Value(load->From())});
+ spv::Op::OpLoad, {Type(load->Result(0)->Type()), Value(load), Value(load->From())});
}
/// Emit a load vector element instruction.
/// @param load the load vector element instruction to emit
void EmitLoadVectorElement(core::ir::LoadVectorElement* load) {
auto* vec_ptr_ty = load->From()->Type()->As<core::type::Pointer>();
- auto* el_ty = load->Result()->Type();
+ auto* el_ty = load->Result(0)->Type();
auto* el_ptr_ty = ir_.Types().ptr(vec_ptr_ty->AddressSpace(), el_ty, vec_ptr_ty->Access());
auto el_ptr_id = module_.NextId();
current_function_.push_inst(
spv::Op::OpAccessChain,
{Type(el_ptr_ty), el_ptr_id, Value(load->From()), Value(load->Index())});
current_function_.push_inst(spv::Op::OpLoad,
- {Type(load->Result()->Type()), Value(load), el_ptr_id});
+ {Type(load->Result(0)->Type()), Value(load), el_ptr_id});
}
/// Emit a loop instruction.
@@ -1862,7 +1866,7 @@
EmitBlockInstructions(loop->Body());
// Emit the loop continuing block.
- if (loop->Continuing()->HasTerminator()) {
+ if (loop->Continuing()->Terminator()) {
EmitBlock(loop->Continuing());
} else {
// We still need to emit a continuing block with a back-edge, even if it is unreachable.
@@ -1885,7 +1889,7 @@
for (auto& c : swtch->Cases()) {
for (auto& sel : c.selectors) {
if (sel.IsDefault()) {
- default_label = Label(c.Block());
+ default_label = Label(c.block);
}
}
}
@@ -1894,7 +1898,7 @@
// Build the operands to the OpSwitch instruction.
OperandList switch_operands = {Value(swtch->Condition()), default_label};
for (auto& c : swtch->Cases()) {
- auto label = Label(c.Block());
+ auto label = Label(c.block);
for (auto& sel : c.selectors) {
if (sel.IsDefault()) {
continue;
@@ -1914,7 +1918,7 @@
// Emit the cases.
for (auto& c : swtch->Cases()) {
- EmitBlock(c.Block());
+ EmitBlock(c.block);
}
// Emit the switch merge block.
@@ -1929,7 +1933,7 @@
void EmitSwizzle(core::ir::Swizzle* swizzle) {
auto id = Value(swizzle);
auto obj = Value(swizzle->Object());
- OperandList operands = {Type(swizzle->Result()->Type()), id, obj, obj};
+ OperandList operands = {Type(swizzle->Result(0)->Type()), id, obj, obj};
for (auto idx : swizzle->Indices()) {
operands.push_back(idx);
}
@@ -1959,7 +1963,7 @@
/// @param unary the unary instruction to emit
void EmitUnary(core::ir::Unary* unary) {
auto id = Value(unary);
- auto* ty = unary->Result()->Type();
+ auto* ty = unary->Result(0)->Type();
spv::Op op = spv::Op::Max;
switch (unary->Op()) {
case core::ir::UnaryOp::kComplement:
@@ -1980,7 +1984,7 @@
/// @param call the user call instruction to emit
void EmitUserCall(core::ir::UserCall* call) {
auto id = Value(call);
- OperandList operands = {Type(call->Result()->Type()), id, Value(call->Target())};
+ OperandList operands = {Type(call->Result(0)->Type()), id, Value(call->Target())};
for (auto* arg : call->Args()) {
operands.push_back(Value(arg));
}
@@ -2041,7 +2045,7 @@
/// @param var the var instruction to emit
void EmitVar(core::ir::Var* var) {
auto id = Value(var);
- auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+ auto* ptr = var->Result(0)->Type()->As<core::type::Pointer>();
auto* store_ty = ptr->StoreType();
auto ty = Type(ptr);
@@ -2139,7 +2143,7 @@
/// @param let the let instruction to emit
void EmitLet(core::ir::Let* let) {
auto id = Value(let->Value());
- values_.Add(let->Result(), id);
+ values_.Add(let->Result(0), id);
}
/// Emit the OpPhis for the given flow control instruction.
@@ -2163,6 +2167,13 @@
}
branches.Sort(); // Sort the branches by label to ensure deterministic output
+ // Also add phi nodes from implicit exit blocks.
+ inst->ForeachBlock([&](core::ir::Block* block) {
+ if (block->IsEmpty()) {
+ branches.Push(Branch{Label(block), nullptr});
+ }
+ });
+
OperandList ops{Type(ty), Value(result)};
for (auto& branch : branches) {
if (branch.value == nullptr) {
@@ -2188,9 +2199,9 @@
/// @returns the label ID
uint32_t GetTerminatorBlockLabel(core::ir::Terminator* t) {
// Walk backwards from `t` until we find a control instruction.
- auto* inst = t->prev;
+ auto* inst = t->prev.Get();
while (inst) {
- auto* prev = inst->prev;
+ auto* prev = inst->prev.Get();
if (auto* ci = inst->As<core::ir::ControlInstruction>()) {
// This is the last control instruction before `t`, so use its merge block label.
return GetMergeLabel(ci);
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
index ddce778..923a526 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
@@ -105,7 +105,7 @@
worklist.Push(builtin);
break;
case core::BuiltinFn::kQuantizeToF16:
- if (builtin->Result()->Type()->Is<core::type::Vector>()) {
+ if (builtin->Result(0)->Type()->Is<core::type::Vector>()) {
worklist.Push(builtin);
}
break;
@@ -178,10 +178,10 @@
TINT_ASSERT_OR_RETURN(replacement);
// Replace the old builtin result with the new value.
- if (auto name = ir.NameOf(builtin->Result())) {
+ if (auto name = ir.NameOf(builtin->Result(0))) {
ir.SetName(replacement, name);
}
- builtin->Result()->ReplaceAllUsesWith(replacement);
+ builtin->Result(0)->ReplaceAllUsesWith(replacement);
builtin->Destroy();
}
}
@@ -199,12 +199,12 @@
core::ir::Value* ArrayLength(core::ir::CoreBuiltinCall* builtin) {
// Strip away any let instructions to get to the original struct member access instruction.
auto* ptr = builtin->Args()[0]->As<core::ir::InstructionResult>();
- while (auto* let = tint::As<core::ir::Let>(ptr->Source())) {
+ while (auto* let = tint::As<core::ir::Let>(ptr->Instruction())) {
ptr = let->Value()->As<core::ir::InstructionResult>();
}
TINT_ASSERT_OR_RETURN_VALUE(ptr, nullptr);
- auto* access = ptr->Source()->As<core::ir::Access>();
+ auto* access = ptr->Instruction()->As<core::ir::Access>();
TINT_ASSERT_OR_RETURN_VALUE(access, nullptr);
TINT_ASSERT_OR_RETURN_VALUE(access->Indices().Length() == 1u, nullptr);
TINT_ASSERT_OR_RETURN_VALUE(access->Object()->Type()->UnwrapPtr()->Is<core::type::Struct>(),
@@ -213,17 +213,17 @@
// Replace the builtin call with a call to the spirv.array_length intrinsic.
auto* call = b.Call<spirv::ir::BuiltinCall>(
- builtin->Result()->Type(), spirv::BuiltinFn::kArrayLength,
+ builtin->Result(0)->Type(), spirv::BuiltinFn::kArrayLength,
Vector{access->Object(), Literal(u32(const_idx->Value()->ValueAs<uint32_t>()))});
call->InsertBefore(builtin);
- return call->Result();
+ return call->Result(0);
}
/// Handle an atomic*() builtin.
/// @param builtin the builtin call instruction
/// @returns the replacement value
core::ir::Value* Atomic(core::ir::CoreBuiltinCall* builtin) {
- auto* result_ty = builtin->Result()->Type();
+ auto* result_ty = builtin->Result(0)->Type();
auto* pointer = builtin->Args()[0];
auto* memory = [&]() -> core::ir::Value* {
@@ -267,14 +267,14 @@
call->InsertBefore(builtin);
// Compare the original value to the comparator to see if an exchange happened.
- auto* original = call->Result();
+ auto* original = call->Result(0);
auto* compare = b.Equal(ty.bool_(), original, cmp);
compare->InsertBefore(builtin);
// Construct the atomicCompareExchange result structure.
call = b.Construct(
core::type::CreateAtomicCompareExchangeResult(ty, ir.symbols, int_ty),
- Vector{original, compare->Result()});
+ Vector{original, compare->Result(0)});
break;
}
case core::BuiltinFn::kAtomicExchange:
@@ -321,7 +321,7 @@
}
call->InsertBefore(builtin);
- return call->Result();
+ return call->Result(0);
}
/// Handle a `dot()` builtin.
@@ -330,7 +330,7 @@
core::ir::Value* Dot(core::ir::CoreBuiltinCall* builtin) {
// OpDot only supports floating point operands, so we need to polyfill the integer case.
// TODO(crbug.com/tint/1267): If SPV_KHR_integer_dot_product is supported, use that instead.
- if (builtin->Result()->Type()->is_integer_scalar()) {
+ if (builtin->Result(0)->Type()->is_integer_scalar()) {
core::ir::Instruction* sum = nullptr;
auto* v1 = builtin->Args()[0];
@@ -349,15 +349,15 @@
}
});
}
- return sum->Result();
+ return sum->Result(0);
}
// Replace the builtin call with a call to the spirv.dot intrinsic.
auto args = Vector<core::ir::Value*, 4>(builtin->Args());
- auto* call = b.Call<spirv::ir::BuiltinCall>(builtin->Result()->Type(),
+ auto* call = b.Call<spirv::ir::BuiltinCall>(builtin->Result(0)->Type(),
spirv::BuiltinFn::kDot, std::move(args));
call->InsertBefore(builtin);
- return call->Result();
+ return call->Result(0);
}
/// Handle a `dot4{I,U}8Packed()` builtin.
@@ -365,7 +365,7 @@
/// @returns the replacement value
core::ir::Value* DotPacked4x8(core::ir::CoreBuiltinCall* builtin) {
// Replace the builtin call with a call to the spirv.{s,u}dot intrinsic.
- auto* type = builtin->Result()->Type();
+ auto* type = builtin->Result(0)->Type();
auto is_signed = builtin->Func() == core::BuiltinFn::kDot4I8Packed;
auto inst = is_signed ? spirv::BuiltinFn::kSdot : spirv::BuiltinFn::kUdot;
@@ -374,7 +374,7 @@
auto* call = b.Call<spirv::ir::BuiltinCall>(type, inst, std::move(args));
call->InsertBefore(builtin);
- return call->Result();
+ return call->Result(0);
}
/// Handle a `select()` builtin.
@@ -391,21 +391,21 @@
// If the condition is scalar and the objects are vectors, we need to splat the condition
// into a vector of the same size.
// TODO(jrprice): We don't need to do this if we're targeting SPIR-V 1.4 or newer.
- auto* vec = builtin->Result()->Type()->As<core::type::Vector>();
+ auto* vec = builtin->Result(0)->Type()->As<core::type::Vector>();
if (vec && args[0]->Type()->Is<core::type::Scalar>()) {
Vector<core::ir::Value*, 4> elements;
elements.Resize(vec->Width(), args[0]);
auto* construct = b.Construct(ty.vec(ty.bool_(), vec->Width()), std::move(elements));
construct->InsertBefore(builtin);
- args[0] = construct->Result();
+ args[0] = construct->Result(0);
}
// Replace the builtin call with a call to the spirv.select intrinsic.
- auto* call = b.Call<spirv::ir::BuiltinCall>(builtin->Result()->Type(),
+ auto* call = b.Call<spirv::ir::BuiltinCall>(builtin->Result(0)->Type(),
spirv::BuiltinFn::kSelect, std::move(args));
call->InsertBefore(builtin);
- return call->Result();
+ return call->Result(0);
}
/// ImageOperands represents the optional image operands for an image instruction.
@@ -449,7 +449,7 @@
if (requires_float_lod && operands.lod->Type()->is_integer_scalar()) {
auto* convert = b.Convert(ty.f32(), operands.lod);
convert->InsertBefore(insertion_point);
- operands.lod = convert->Result();
+ operands.lod = convert->Result(0);
}
args.Push(operands.lod);
}
@@ -486,7 +486,7 @@
if (array_idx->Type() != element_ty) {
auto* array_idx_converted = b.Convert(element_ty, array_idx);
array_idx_converted->InsertBefore(insertion_point);
- array_idx = array_idx_converted->Result();
+ array_idx = array_idx_converted->Result(0);
}
// Construct a new coordinate vector.
@@ -494,7 +494,7 @@
auto* coord_ty = ty.vec(element_ty, num_coords + 1);
auto* construct = b.Construct(coord_ty, Vector{coords, array_idx});
construct->InsertBefore(insertion_point);
- return construct->Result();
+ return construct->Result(0);
}
/// Handle a textureSample*() builtin.
@@ -568,7 +568,7 @@
// The first two operands are always the sampled image and then the coordinates, followed by
// the depth reference if used.
Vector<core::ir::Value*, 8> function_args;
- function_args.Push(sampled_image->Result());
+ function_args.Push(sampled_image->Result(0));
function_args.Push(coords);
if (depth) {
function_args.Push(depth);
@@ -584,7 +584,7 @@
b.Call<spirv::ir::BuiltinCall>(result_ty, function, std::move(function_args));
texture_call->InsertBefore(builtin);
- auto* result = texture_call->Result();
+ auto* result = texture_call->Result(0);
// If this is not a depth comparison but we are sampling a depth texture, extract the first
// component to get the scalar f32 that SPIR-V expects.
@@ -592,7 +592,7 @@
texture_ty->IsAnyOf<core::type::DepthTexture, core::type::DepthMultisampledTexture>()) {
auto* extract = b.Access(ty.f32(), result, 0_u);
extract->InsertBefore(builtin);
- result = extract->Result();
+ result = extract->Result(0);
}
return result;
@@ -654,7 +654,7 @@
// The first two operands are always the sampled image and then the coordinates, followed by
// either the depth reference or the component.
Vector<core::ir::Value*, 8> function_args;
- function_args.Push(sampled_image->Result());
+ function_args.Push(sampled_image->Result(0));
function_args.Push(coords);
if (depth) {
function_args.Push(depth);
@@ -666,11 +666,11 @@
AppendImageOperands(operands, function_args, builtin, /* requires_float_lod */ true);
// Call the function.
- auto* result_ty = builtin->Result()->Type();
+ auto* result_ty = builtin->Result(0)->Type();
auto* texture_call =
b.Call<spirv::ir::BuiltinCall>(result_ty, function, std::move(function_args));
texture_call->InsertBefore(builtin);
- return texture_call->Result();
+ return texture_call->Result(0);
}
/// Handle a textureLoad() builtin.
@@ -711,7 +711,7 @@
// Call the builtin.
// The result is always a vec4 in SPIR-V.
- auto* result_ty = builtin->Result()->Type();
+ auto* result_ty = builtin->Result(0)->Type();
bool expects_scalar_result = result_ty->Is<core::type::Scalar>();
if (expects_scalar_result) {
result_ty = ty.vec4(result_ty);
@@ -721,13 +721,13 @@
auto* texture_call =
b.Call<spirv::ir::BuiltinCall>(result_ty, kind, std::move(builtin_args));
texture_call->InsertBefore(builtin);
- auto* result = texture_call->Result();
+ auto* result = texture_call->Result(0);
// If we are expecting a scalar result, extract the first component.
if (expects_scalar_result) {
auto* extract = b.Access(ty.f32(), result, 0_u);
extract->InsertBefore(builtin);
- result = extract->Result();
+ result = extract->Result(0);
}
return result;
@@ -769,7 +769,7 @@
auto* texture_call = b.Call<spirv::ir::BuiltinCall>(
ty.void_(), spirv::BuiltinFn::kImageWrite, std::move(function_args));
texture_call->InsertBefore(builtin);
- return texture_call->Result();
+ return texture_call->Result(0);
}
/// Handle a textureDimensions() builtin.
@@ -805,7 +805,7 @@
}
// Add an extra component to the result vector for arrayed textures.
- auto* result_ty = builtin->Result()->Type();
+ auto* result_ty = builtin->Result(0)->Type();
if (core::type::IsTextureArray(texture_ty->dim())) {
auto* vec = result_ty->As<core::type::Vector>();
result_ty = ty.vec(vec->type(), vec->Width() + 1);
@@ -816,13 +816,13 @@
b.Call<spirv::ir::BuiltinCall>(result_ty, function, std::move(function_args));
texture_call->InsertBefore(builtin);
- auto* result = texture_call->Result();
+ auto* result = texture_call->Result(0);
// Swizzle the first two components from the result for arrayed textures.
if (core::type::IsTextureArray(texture_ty->dim())) {
- auto* swizzle = b.Swizzle(builtin->Result()->Type(), result, {0, 1});
+ auto* swizzle = b.Swizzle(builtin->Result(0)->Type(), result, {0, 1});
swizzle->InsertBefore(builtin);
- result = swizzle->Result();
+ result = swizzle->Result(0);
}
return result;
@@ -855,9 +855,9 @@
texture_call->InsertBefore(builtin);
// Extract the third component to get the number of array layers.
- auto* extract = b.Access(ty.u32(), texture_call->Result(), 2_u);
+ auto* extract = b.Access(ty.u32(), texture_call->Result(0), 2_u);
extract->InsertBefore(builtin);
- return extract->Result();
+ return extract->Result(0);
}
/// Scalarize the vector form of a `quantizeToF16()` builtin.
@@ -874,13 +874,13 @@
for (uint32_t i = 0; i < vec->Width(); i++) {
auto* el = b.Access(ty.f32(), arg, u32(i));
auto* scalar_call = b.Call(ty.f32(), core::BuiltinFn::kQuantizeToF16, el);
- args.Push(scalar_call->Result());
+ args.Push(scalar_call->Result(0));
el->InsertBefore(builtin);
scalar_call->InsertBefore(builtin);
}
auto* construct = b.Construct(vec, std::move(args));
construct->InsertBefore(builtin);
- return construct->Result();
+ return construct->Result(0);
}
};
diff --git a/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc b/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc
index 7df2b91..033cb2a 100644
--- a/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc
+++ b/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc
@@ -55,7 +55,7 @@
if (auto* construct = inst->As<core::ir::Construct>()) {
// A vector constructor with a single scalar argument needs to be modified to replicate
// the argument N times.
- auto* vec = construct->Result()->Type()->As<core::type::Vector>();
+ auto* vec = construct->Result(0)->Type()->As<core::type::Vector>();
if (vec && //
construct->Args().Length() == 1 &&
construct->Args()[0]->Type()->Is<core::type::Scalar>()) {
@@ -66,7 +66,7 @@
} else if (auto* binary = inst->As<core::ir::Binary>()) {
// A binary instruction that mixes vector and scalar operands needs to have the scalar
// operand replaced with an explicit vector constructor.
- if (binary->Result()->Type()->Is<core::type::Vector>()) {
+ if (binary->Result(0)->Type()->Is<core::type::Vector>()) {
if (binary->LHS()->Type()->Is<core::type::Scalar>() ||
binary->RHS()->Type()->Is<core::type::Scalar>()) {
binary_worklist.Push(binary);
@@ -76,7 +76,7 @@
// A mix builtin call that mixes vector and scalar operands needs to have the scalar
// operand replaced with an explicit vector constructor.
if (builtin->Func() == core::BuiltinFn::kMix) {
- if (builtin->Result()->Type()->Is<core::type::Vector>()) {
+ if (builtin->Result(0)->Type()->Is<core::type::Vector>()) {
if (builtin->Args()[2]->Type()->Is<core::type::Scalar>()) {
builtin_worklist.Push(builtin);
}
@@ -88,19 +88,19 @@
// Helper to expand a scalar operand of an instruction by replacing it with an explicitly
// constructed vector that matches the result type.
auto expand_operand = [&](core::ir::Instruction* inst, size_t operand_idx) {
- auto* vec = inst->Result()->Type()->As<core::type::Vector>();
+ auto* vec = inst->Result(0)->Type()->As<core::type::Vector>();
Vector<core::ir::Value*, 4> args;
args.Resize(vec->Width(), inst->Operands()[operand_idx]);
auto* construct = b.Construct(vec, std::move(args));
construct->InsertBefore(inst);
- inst->SetOperand(operand_idx, construct->Result());
+ inst->SetOperand(operand_idx, construct->Result(0));
};
// Replace scalar operands to binary instructions that produce vectors.
for (auto* binary : binary_worklist) {
- auto* result_ty = binary->Result()->Type();
+ auto* result_ty = binary->Result(0)->Type();
if (result_ty->is_float_vector() && binary->Op() == core::ir::BinaryOp::kMultiply) {
// Use OpVectorTimesScalar for floating point multiply.
auto* vts =
@@ -113,9 +113,9 @@
vts->AppendArg(binary->RHS());
}
if (auto name = ir.NameOf(binary)) {
- ir.SetName(vts->Result(), name);
+ ir.SetName(vts->Result(0), name);
}
- binary->Result()->ReplaceAllUsesWith(vts->Result());
+ binary->Result(0)->ReplaceAllUsesWith(vts->Result(0));
binary->ReplaceWith(vts);
binary->Destroy();
} else {
diff --git a/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc b/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc
index bfd212f..43ede7c 100644
--- a/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc
+++ b/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc
@@ -61,7 +61,7 @@
binary_worklist.Push(binary);
}
} else if (auto* convert = inst->As<core::ir::Convert>()) {
- if (convert->Result()->Type()->Is<core::type::Matrix>()) {
+ if (convert->Result(0)->Type()->Is<core::type::Matrix>()) {
convert_worklist.Push(convert);
}
}
@@ -73,14 +73,14 @@
auto* rhs = binary->RHS();
auto* lhs_ty = lhs->Type();
auto* rhs_ty = rhs->Type();
- auto* ty = binary->Result()->Type();
+ auto* ty = binary->Result(0)->Type();
// Helper to replace the instruction with a new one.
auto replace = [&](core::ir::Instruction* inst) {
if (auto name = ir.NameOf(binary)) {
- ir.SetName(inst->Result(), name);
+ ir.SetName(inst->Result(0), name);
}
- binary->Result()->ReplaceAllUsesWith(inst->Result());
+ binary->Result(0)->ReplaceAllUsesWith(inst->Result(0));
binary->ReplaceWith(inst);
binary->Destroy();
};
@@ -94,7 +94,7 @@
auto* lhs_col = b.Access(mat->ColumnType(), lhs, u32(col));
auto* rhs_col = b.Access(mat->ColumnType(), rhs, u32(col));
auto* add = b.Binary(op, mat->ColumnType(), lhs_col, rhs_col);
- args.Push(add->Result());
+ args.Push(add->Result(0));
});
}
replace(b.Construct(ty, std::move(args)));
@@ -141,7 +141,7 @@
for (auto* convert : convert_worklist) {
auto* arg = convert->Args()[core::ir::Convert::kValueOperandOffset];
auto* in_mat = arg->Type()->As<core::type::Matrix>();
- auto* out_mat = convert->Result()->Type()->As<core::type::Matrix>();
+ auto* out_mat = convert->Result(0)->Type()->As<core::type::Matrix>();
// Extract and convert each column separately.
Vector<core::ir::Value*, 4> args;
@@ -149,16 +149,16 @@
b.InsertBefore(convert, [&] {
auto* col = b.Access(in_mat->ColumnType(), arg, u32(c));
auto* new_col = b.Convert(out_mat->ColumnType(), col);
- args.Push(new_col->Result());
+ args.Push(new_col->Result(0));
});
}
// Reconstruct the result matrix from the converted columns.
auto* construct = b.Construct(out_mat, std::move(args));
if (auto name = ir.NameOf(convert)) {
- ir.SetName(construct->Result(), name);
+ ir.SetName(construct->Result(0), name);
}
- convert->Result()->ReplaceAllUsesWith(construct->Result());
+ convert->Result(0)->ReplaceAllUsesWith(construct->Result(0));
convert->ReplaceWith(construct);
convert->Destroy();
}
diff --git a/src/tint/lang/spirv/writer/raise/merge_return.cc b/src/tint/lang/spirv/writer/raise/merge_return.cc
index dbd06d7..cab47ce 100644
--- a/src/tint/lang/spirv/writer/raise/merge_return.cc
+++ b/src/tint/lang/spirv/writer/raise/merge_return.cc
@@ -132,7 +132,7 @@
for (auto* inst = *block->begin(); inst;) { // For each instruction in 'block'
// As we're modifying the block that we're iterating over, grab the pointer to the next
// instruction before (potentially) moving 'inst' to another block.
- auto* next = inst->next;
+ auto* next = inst->next.Get();
TINT_DEFER(inst = next);
if (auto* ret = inst->As<core::ir::Return>()) {
@@ -178,8 +178,8 @@
return b.InstructionResult(v->Type());
};
- if (inner_if->True()->HasTerminator()) {
- if (auto* exit_if = inner_if->True()->Terminator()->As<core::ir::ExitIf>()) {
+ if (auto* terminator = inner_if->True()->Terminator()) {
+ if (auto* exit_if = terminator->As<core::ir::ExitIf>()) {
// Ensure the associated 'if' is updated.
exit_if->SetIf(inner_if);
@@ -198,10 +198,10 @@
// Loop over the 'if' instructions, starting with the inner-most, and add any missing
// terminating instructions to the blocks holding the 'if'.
for (auto* i = inner_if; i; i = tint::As<core::ir::If>(i->Block()->Parent())) {
- if (!i->Block()->HasTerminator() && i->Block()->Parent()) {
+ if (!i->Block()->Terminator() && i->Block()->Parent()) {
// Append the exit instruction to the block holding the 'if'.
Vector<core::ir::InstructionResult*, 8> exit_args = i->Results();
- if (!i->HasResults()) {
+ if (i->Results().IsEmpty()) {
i->SetResults(tint::Transform(exit_args, new_value_with_type));
}
auto* exit = b.Exit(i->Block()->Parent(), std::move(exit_args));
@@ -244,7 +244,7 @@
// Change the function return to unconditionally load 'return_val' and return it
auto* load = b.Load(return_val);
load->InsertBefore(ret);
- ret->SetValue(load->Result());
+ ret->SetValue(load->Result(0));
}
/// Transforms the return instruction that is found in a control instruction.
@@ -306,7 +306,7 @@
}
// Process each function.
- for (auto* fn : ir.functions) {
+ for (auto& fn : ir.functions) {
State{ir}.Process(fn);
}
diff --git a/src/tint/lang/spirv/writer/raise/merge_return_test.cc b/src/tint/lang/spirv/writer/raise/merge_return_test.cc
index 29a5b3f..425f1c0 100644
--- a/src/tint/lang/spirv/writer/raise/merge_return_test.cc
+++ b/src/tint/lang/spirv/writer/raise/merge_return_test.cc
@@ -111,7 +111,7 @@
b.Append(func->Block(), [&] {
auto* swtch = b.Switch(in);
- b.Append(b.Case(swtch, {core::ir::Switch::CaseSelector{}}), [&] { b.ExitSwitch(swtch); });
+ b.Append(b.DefaultCase(swtch), [&] { b.ExitSwitch(swtch); });
auto* l = b.Loop();
b.Append(l->Body(), [&] { b.ExitLoop(l); });
@@ -1649,9 +1649,8 @@
b.Append(func->Block(), [&] {
auto* sw = b.Switch(cond);
- b.Append(b.Case(sw, {core::ir::Switch::CaseSelector{b.Constant(1_i)}}),
- [&] { b.Return(func, 42_i); });
- b.Append(b.Case(sw, {core::ir::Switch::CaseSelector{}}), [&] { b.ExitSwitch(sw); });
+ b.Append(b.Case(sw, {b.Constant(1_i)}), [&] { b.Return(func, 42_i); });
+ b.Append(b.DefaultCase(sw), [&] { b.ExitSwitch(sw); });
b.Return(func, 0_i);
});
@@ -1716,7 +1715,7 @@
b.Append(func->Block(), [&] {
auto* sw = b.Switch(cond);
- b.Append(b.Case(sw, {core::ir::Switch::CaseSelector{b.Constant(1_i)}}), [&] {
+ b.Append(b.Case(sw, {b.Constant(1_i)}), [&] {
auto* ifcond = b.Equal(ty.bool_(), cond, 1_i);
auto* ifelse = b.If(ifcond);
b.Append(ifelse->True(), [&] { b.Return(func, 42_i); });
@@ -1726,7 +1725,7 @@
b.ExitSwitch(sw);
});
- b.Append(b.Case(sw, {core::ir::Switch::CaseSelector{}}), [&] { b.ExitSwitch(sw); });
+ b.Append(b.DefaultCase(sw), [&] { b.ExitSwitch(sw); });
b.Return(func, 0_i);
});
@@ -1823,13 +1822,10 @@
b.Append(func->Block(), [&] {
auto* sw = b.Switch(cond);
sw->SetResults(b.InstructionResult(ty.i32())); // NOLINT: false detection of std::tuple
- b.Append(b.Case(sw, {core::ir::Switch::CaseSelector{b.Constant(1_i)}}),
- [&] { b.Return(func, 42_i); });
- b.Append(b.Case(sw, {core::ir::Switch::CaseSelector{b.Constant(2_i)}}),
- [&] { b.Return(func, 99_i); });
- b.Append(b.Case(sw, {core::ir::Switch::CaseSelector{b.Constant(3_i)}}),
- [&] { b.ExitSwitch(sw, 1_i); });
- b.Append(b.Case(sw, {core::ir::Switch::CaseSelector{}}), [&] { b.ExitSwitch(sw, 0_i); });
+ b.Append(b.Case(sw, {b.Constant(1_i)}), [&] { b.Return(func, 42_i); });
+ b.Append(b.Case(sw, {b.Constant(2_i)}), [&] { b.Return(func, 99_i); });
+ b.Append(b.Case(sw, {b.Constant(3_i)}), [&] { b.ExitSwitch(sw, 1_i); });
+ b.Append(b.DefaultCase(sw), [&] { b.ExitSwitch(sw, 0_i); });
b.Return(func, sw->Result(0));
});
diff --git a/src/tint/lang/spirv/writer/raise/pass_matrix_by_pointer.cc b/src/tint/lang/spirv/writer/raise/pass_matrix_by_pointer.cc
index 62bfb78..2fe2e74 100644
--- a/src/tint/lang/spirv/writer/raise/pass_matrix_by_pointer.cc
+++ b/src/tint/lang/spirv/writer/raise/pass_matrix_by_pointer.cc
@@ -54,7 +54,7 @@
/// Process the module.
void Process() {
// Find user-declared functions that have value arguments containing matrices.
- for (auto* func : ir.functions) {
+ for (auto& func : ir.functions) {
for (auto* param : func->Params()) {
if (ContainsMatrix(param->Type())) {
TransformFunction(func);
@@ -95,7 +95,7 @@
// Load from the pointer to get the value.
auto* load = b.Load(new_param);
func->Block()->Prepend(load);
- param->ReplaceAllUsesWith(load->Result());
+ param->ReplaceAllUsesWith(load->Result(0));
// Modify all of the callsites.
func->ForEachUse([&](core::ir::Usage use) {
@@ -121,7 +121,7 @@
local_var->SetInitializer(arg);
local_var->InsertBefore(call);
- call->SetOperand(core::ir::UserCall::kArgsOperandOffset + arg_index, local_var->Result());
+ call->SetOperand(core::ir::UserCall::kArgsOperandOffset + arg_index, local_var->Result(0));
}
};
diff --git a/src/tint/lang/spirv/writer/raise/raise.cc b/src/tint/lang/spirv/writer/raise/raise.cc
index 8160fe6..fad09b4 100644
--- a/src/tint/lang/spirv/writer/raise/raise.cc
+++ b/src/tint/lang/spirv/writer/raise/raise.cc
@@ -133,8 +133,10 @@
// produce pointers to matrices.
RUN_TRANSFORM(core::ir::transform::CombineAccessInstructions, module);
- RUN_TRANSFORM(BuiltinPolyfill, module);
+ // DemoteToHelper must come before any transform that introduces non-core instructions.
RUN_TRANSFORM(core::ir::transform::DemoteToHelper, module);
+
+ RUN_TRANSFORM(BuiltinPolyfill, module);
RUN_TRANSFORM(ExpandImplicitSplats, module);
RUN_TRANSFORM(HandleMatrixArithmetic, module);
RUN_TRANSFORM(MergeReturn, module);
diff --git a/src/tint/lang/spirv/writer/raise/shader_io.cc b/src/tint/lang/spirv/writer/raise/shader_io.cc
index c44fdee..5ec25d1 100644
--- a/src/tint/lang/spirv/writer/raise/shader_io.cc
+++ b/src/tint/lang/spirv/writer/raise/shader_io.cc
@@ -143,25 +143,25 @@
core::ir::Value* GetInput(core::ir::Builder& builder, uint32_t idx) override {
// Load the input from the global variable declared earlier.
auto* ptr = ty.ptr(core::AddressSpace::kIn, inputs[idx].type, core::Access::kRead);
- auto* from = input_vars[idx]->Result();
+ auto* from = input_vars[idx]->Result(0);
if (inputs[idx].attributes.builtin) {
if (inputs[idx].attributes.builtin.value() == core::BuiltinValue::kSampleMask) {
// SampleMask becomes an array for SPIR-V, so load from the first element.
- from = builder.Access(ptr, input_vars[idx], 0_u)->Result();
+ from = builder.Access(ptr, input_vars[idx], 0_u)->Result(0);
}
}
- return builder.Load(from)->Result();
+ return builder.Load(from)->Result(0);
}
/// @copydoc ShaderIO::BackendState::SetOutput
void SetOutput(core::ir::Builder& builder, uint32_t idx, core::ir::Value* value) override {
// Store the output to the global variable declared earlier.
auto* ptr = ty.ptr(core::AddressSpace::kOut, outputs[idx].type, core::Access::kWrite);
- auto* to = output_vars[idx]->Result();
+ auto* to = output_vars[idx]->Result(0);
if (outputs[idx].attributes.builtin) {
if (outputs[idx].attributes.builtin.value() == core::BuiltinValue::kSampleMask) {
// SampleMask becomes an array for SPIR-V, so store to the first element.
- to = builder.Access(ptr, to, 0_u)->Result();
+ to = builder.Access(ptr, to, 0_u)->Result(0);
}
// Clamp frag_depth values if necessary.
@@ -186,7 +186,7 @@
// Check that there are no push constants in the module already.
for (auto* inst : *ir.root_block) {
if (auto* var = inst->As<core::ir::Var>()) {
- auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+ auto* ptr = var->Result(0)->Type()->As<core::type::Pointer>();
if (ptr->AddressSpace() == core::AddressSpace::kPushConstant) {
TINT_ICE() << "cannot clamp frag_depth with pre-existing push constants";
}
@@ -204,7 +204,7 @@
// Declare the variable.
auto* var = b.Var("tint_frag_depth_clamp_args", ty.ptr(push_constant, str));
ir.root_block->Append(var);
- module_state.frag_depth_clamp_args = var->Result();
+ module_state.frag_depth_clamp_args = var->Result(0);
}
// Clamp the value.
@@ -213,7 +213,7 @@
auto* frag_depth_max = builder.Access(ty.f32(), args, 1_u);
return builder
.Call(ty.f32(), core::BuiltinFn::kClamp, frag_depth, frag_depth_min, frag_depth_max)
- ->Result();
+ ->Result(0);
}
/// @copydoc ShaderIO::BackendState::NeedsVertexPointSize
diff --git a/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.cc b/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.cc
index e58d05d..855ba42 100644
--- a/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.cc
+++ b/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.cc
@@ -94,7 +94,7 @@
}
std::optional<AccessToReplace> ShouldReplace(core::ir::Access* access) {
- if (access->Result()->Type()->Is<core::type::Pointer>()) {
+ if (access->Result(0)->Type()->Is<core::type::Pointer>()) {
// No need to modify accesses into pointer types.
return {};
}
@@ -153,7 +153,7 @@
auto* intermediate_source = builder.Access(to_replace.dynamic_index_source_type,
source_object, partial_access.indices);
intermediate_source->InsertBefore(access);
- return intermediate_source->Result();
+ return intermediate_source->Result(0);
});
}
@@ -163,13 +163,13 @@
core::AddressSpace::kFunction, source_object->Type(), core::Access::kReadWrite));
decl->SetInitializer(source_object);
decl->InsertBefore(access);
- return decl->Result();
+ return decl->Result(0);
});
// Create a new access instruction using the local variable as the source.
Vector<core::ir::Value*, 4> indices{
access->Indices().Offset(to_replace.first_dynamic_index)};
- const core::type::Type* access_type = access->Result()->Type();
+ const core::type::Type* access_type = access->Result(0)->Type();
core::ir::Value* vector_index = nullptr;
if (to_replace.vector_access_type) {
// The old access indexed the element of a vector.
@@ -189,13 +189,13 @@
core::ir::Instruction* load = nullptr;
if (to_replace.vector_access_type) {
- load = builder.LoadVectorElement(new_access->Result(), vector_index);
+ load = builder.LoadVectorElement(new_access->Result(0), vector_index);
} else {
load = builder.Load(new_access);
}
// Replace all uses of the old access instruction with the loaded result.
- access->Result()->ReplaceAllUsesWith(load->Result());
+ access->Result(0)->ReplaceAllUsesWith(load->Result(0));
access->ReplaceWith(load);
access->Destroy();
}
diff --git a/src/tint/lang/spirv/writer/switch_test.cc b/src/tint/lang/spirv/writer/switch_test.cc
index d00d32e..957d552 100644
--- a/src/tint/lang/spirv/writer/switch_test.cc
+++ b/src/tint/lang/spirv/writer/switch_test.cc
@@ -37,7 +37,7 @@
b.Append(func->Block(), [&] {
auto* swtch = b.Switch(42_i);
- auto* def_case = b.Case(swtch, Vector{core::ir::Switch::CaseSelector()});
+ auto* def_case = b.DefaultCase(swtch);
b.Append(def_case, [&] { //
b.ExitSwitch(swtch);
});
@@ -63,17 +63,17 @@
b.Append(func->Block(), [&] {
auto* swtch = b.Switch(42_i);
- auto* case_a = b.Case(swtch, Vector{core::ir::Switch::CaseSelector{b.Constant(1_i)}});
+ auto* case_a = b.Case(swtch, Vector{b.Constant(1_i)});
b.Append(case_a, [&] { //
b.ExitSwitch(swtch);
});
- auto* case_b = b.Case(swtch, Vector{core::ir::Switch::CaseSelector{b.Constant(2_i)}});
+ auto* case_b = b.Case(swtch, Vector{b.Constant(2_i)});
b.Append(case_b, [&] { //
b.ExitSwitch(swtch);
});
- auto* def_case = b.Case(swtch, Vector{core::ir::Switch::CaseSelector()});
+ auto* def_case = b.DefaultCase(swtch);
b.Append(def_case, [&] { //
b.ExitSwitch(swtch);
});
@@ -103,20 +103,17 @@
b.Append(func->Block(), [&] {
auto* swtch = b.Switch(42_i);
- auto* case_a = b.Case(swtch, Vector{core::ir::Switch::CaseSelector{b.Constant(1_i)},
- core::ir::Switch::CaseSelector{b.Constant(3_i)}});
+ auto* case_a = b.Case(swtch, Vector{b.Constant(1_i), b.Constant(3_i)});
b.Append(case_a, [&] { //
b.ExitSwitch(swtch);
});
- auto* case_b = b.Case(swtch, Vector{core::ir::Switch::CaseSelector{b.Constant(2_i)},
- core::ir::Switch::CaseSelector{b.Constant(4_i)}});
+ auto* case_b = b.Case(swtch, Vector{b.Constant(2_i), b.Constant(4_i)});
b.Append(case_b, [&] { //
b.ExitSwitch(swtch);
});
- auto* def_case = b.Case(swtch, Vector{core::ir::Switch::CaseSelector{b.Constant(5_i)},
- core::ir::Switch::CaseSelector()});
+ auto* def_case = b.Case(swtch, Vector{b.Constant(5_i), nullptr});
b.Append(def_case, [&] { //
b.ExitSwitch(swtch);
});
@@ -146,17 +143,17 @@
b.Append(func->Block(), [&] {
auto* swtch = b.Switch(42_i);
- auto* case_a = b.Case(swtch, Vector{core::ir::Switch::CaseSelector{b.Constant(1_i)}});
+ auto* case_a = b.Case(swtch, Vector{b.Constant(1_i)});
b.Append(case_a, [&] { //
b.Return(func);
});
- auto* case_b = b.Case(swtch, Vector{core::ir::Switch::CaseSelector{b.Constant(2_i)}});
+ auto* case_b = b.Case(swtch, Vector{b.Constant(2_i)});
b.Append(case_b, [&] { //
b.Return(func);
});
- auto* def_case = b.Case(swtch, Vector{core::ir::Switch::CaseSelector()});
+ auto* def_case = b.DefaultCase(swtch);
b.Append(def_case, [&] { //
b.Return(func);
});
@@ -186,7 +183,7 @@
b.Append(func->Block(), [&] {
auto* swtch = b.Switch(42_i);
- auto* case_a = b.Case(swtch, Vector{core::ir::Switch::CaseSelector{b.Constant(1_i)}});
+ auto* case_a = b.Case(swtch, Vector{b.Constant(1_i)});
b.Append(case_a, [&] {
auto* cond_break = b.If(true);
b.Append(cond_break->True(), [&] { //
@@ -199,7 +196,7 @@
b.Return(func);
});
- auto* def_case = b.Case(swtch, Vector{core::ir::Switch::CaseSelector()});
+ auto* def_case = b.DefaultCase(swtch);
b.Append(def_case, [&] { //
b.ExitSwitch(swtch);
});
@@ -232,13 +229,12 @@
b.Append(func->Block(), [&] {
auto* s = b.Switch(42_i);
s->SetResults(b.InstructionResult(ty.i32()));
- auto* case_a = b.Case(s, Vector{core::ir::Switch::CaseSelector{b.Constant(1_i)},
- core::ir::Switch::CaseSelector{nullptr}});
+ auto* case_a = b.Case(s, Vector{b.Constant(1_i), nullptr});
b.Append(case_a, [&] { //
b.ExitSwitch(s, 10_i);
});
- auto* case_b = b.Case(s, Vector{core::ir::Switch::CaseSelector{b.Constant(2_i)}});
+ auto* case_b = b.Case(s, Vector{b.Constant(2_i)});
b.Append(case_b, [&] { //
b.ExitSwitch(s, 20_i);
});
@@ -267,13 +263,12 @@
b.Append(func->Block(), [&] {
auto* s = b.Switch(42_i);
s->SetResults(b.InstructionResult(ty.i32()));
- auto* case_a = b.Case(s, Vector{core::ir::Switch::CaseSelector{b.Constant(1_i)},
- core::ir::Switch::CaseSelector{nullptr}});
+ auto* case_a = b.Case(s, Vector{b.Constant(1_i), nullptr});
b.Append(case_a, [&] { //
b.Return(func, 10_i);
});
- auto* case_b = b.Case(s, Vector{core::ir::Switch::CaseSelector{b.Constant(2_i)}});
+ auto* case_b = b.Case(s, Vector{b.Constant(2_i)});
b.Append(case_b, [&] { //
b.ExitSwitch(s, 20_i);
});
@@ -315,13 +310,12 @@
b.Append(func->Block(), [&] {
auto* s = b.Switch(42_i);
s->SetResults(b.InstructionResult(ty.i32()), b.InstructionResult(ty.bool_()));
- auto* case_a = b.Case(s, Vector{core::ir::Switch::CaseSelector{b.Constant(1_i)},
- core::ir::Switch::CaseSelector{nullptr}});
+ auto* case_a = b.Case(s, Vector{b.Constant(1_i), nullptr});
b.Append(case_a, [&] { //
b.ExitSwitch(s, 10_i, true);
});
- auto* case_b = b.Case(s, Vector{core::ir::Switch::CaseSelector{b.Constant(2_i)}});
+ auto* case_b = b.Case(s, Vector{b.Constant(2_i)});
b.Append(case_b, [&] { //
b.ExitSwitch(s, 20_i, false);
});
@@ -351,13 +345,12 @@
b.Append(func->Block(), [&] {
auto* s = b.Switch(b.Constant(42_i));
s->SetResults(b.InstructionResult(ty.i32()), b.InstructionResult(ty.bool_()));
- auto* case_a = b.Case(s, Vector{core::ir::Switch::CaseSelector{b.Constant(1_i)},
- core::ir::Switch::CaseSelector{nullptr}});
+ auto* case_a = b.Case(s, Vector{b.Constant(1_i), nullptr});
b.Append(case_a, [&] { //
b.ExitSwitch(s, 10_i, true);
});
- auto* case_b = b.Case(s, Vector{core::ir::Switch::CaseSelector{b.Constant(2_i)}});
+ auto* case_b = b.Case(s, Vector{b.Constant(2_i)});
b.Append(case_b, [&] { //
b.ExitSwitch(s, 20_i, false);
});
@@ -387,8 +380,7 @@
b.Append(func->Block(), [&] {
auto* s = b.Switch(42_i);
s->SetResults(b.InstructionResult(ty.i32()));
- auto* case_a = b.Case(s, Vector{core::ir::Switch::CaseSelector{b.Constant(1_i)},
- core::ir::Switch::CaseSelector{nullptr}});
+ auto* case_a = b.Case(s, Vector{b.Constant(1_i), nullptr});
b.Append(case_a, [&] { //
auto* inner = b.If(true);
inner->SetResults(b.InstructionResult(ty.i32()));
@@ -399,10 +391,10 @@
b.ExitIf(inner, 20_i);
});
- b.ExitSwitch(s, inner->Result());
+ b.ExitSwitch(s, inner->Result(0));
});
- auto* case_b = b.Case(s, Vector{core::ir::Switch::CaseSelector{b.Constant(2_i)}});
+ auto* case_b = b.Case(s, Vector{b.Constant(2_i)});
b.Append(case_b, [&] { //
b.ExitSwitch(s, 20_i);
});
@@ -439,12 +431,10 @@
b.Append(func->Block(), [&] {
auto* outer = b.Switch(42_i);
outer->SetResults(b.InstructionResult(ty.i32()));
- auto* case_a = b.Case(outer, Vector{core::ir::Switch::CaseSelector{b.Constant(1_i)},
- core::ir::Switch::CaseSelector{nullptr}});
+ auto* case_a = b.Case(outer, Vector{b.Constant(1_i), nullptr});
b.Append(case_a, [&] { //
auto* inner = b.Switch(42_i);
- auto* case_inner = b.Case(inner, Vector{core::ir::Switch::CaseSelector{b.Constant(2_i)},
- core::ir::Switch::CaseSelector{nullptr}});
+ auto* case_inner = b.Case(inner, Vector{b.Constant(2_i), nullptr});
b.Append(case_inner, [&] { //
b.ExitSwitch(inner);
});
@@ -452,7 +442,7 @@
b.ExitSwitch(outer, 10_i);
});
- auto* case_b = b.Case(outer, Vector{core::ir::Switch::CaseSelector{b.Constant(2_i)}});
+ auto* case_b = b.Case(outer, Vector{b.Constant(2_i)});
b.Append(case_b, [&] { //
b.ExitSwitch(outer, 20_i);
});
diff --git a/src/tint/lang/spirv/writer/writer.cc b/src/tint/lang/spirv/writer/writer.cc
index e6f3098..1ee7d51 100644
--- a/src/tint/lang/spirv/writer/writer.cc
+++ b/src/tint/lang/spirv/writer/writer.cc
@@ -34,20 +34,39 @@
#include "src/tint/lang/spirv/writer/common/option_helpers.h"
#include "src/tint/lang/spirv/writer/printer/printer.h"
#include "src/tint/lang/spirv/writer/raise/raise.h"
-#include "src/tint/lang/wgsl/reader/lower/lower.h"
-
-#if TINT_BUILD_WGSL_READER
-#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
-#endif
// Included by 'ast_printer.h', included again here for './tools/run gen' track the dependency.
#include "spirv/unified1/spirv.h"
namespace tint::spirv::writer {
-Output::Output() = default;
-Output::~Output() = default;
-Output::Output(const Output&) = default;
+Result<Output> Generate(core::ir::Module& ir, const Options& options) {
+ bool zero_initialize_workgroup_memory =
+ !options.disable_workgroup_init && options.use_zero_initialize_workgroup_memory_extension;
+
+ {
+ auto res = ValidateBindingOptions(options);
+ if (!res) {
+ return res.Failure();
+ }
+ }
+
+ Output output;
+
+ // Raise from core-dialect to SPIR-V-dialect.
+ if (auto res = raise::Raise(ir, options); !res) {
+ return std::move(res.Failure());
+ }
+
+ // Generate the SPIR-V code.
+ auto spirv = Print(ir, zero_initialize_workgroup_memory);
+ if (!spirv) {
+ return std::move(spirv.Failure());
+ }
+ output.spirv = std::move(spirv.Get());
+
+ return output;
+}
Result<Output> Generate(const Program& program, const Options& options) {
if (!program.IsValid()) {
@@ -58,60 +77,29 @@
!options.disable_workgroup_init && options.use_zero_initialize_workgroup_memory_extension;
{
- diag::List validation_diagnostics;
- if (!ValidateBindingOptions(options, validation_diagnostics)) {
- return Failure{validation_diagnostics};
+ auto res = ValidateBindingOptions(options);
+ if (!res) {
+ return res.Failure();
}
}
Output output;
- if (options.use_tint_ir) {
-#if TINT_BUILD_WGSL_READER
- // Convert the AST program to an IR module.
- auto converted = wgsl::reader::ProgramToIR(program);
- if (!converted) {
- return converted.Failure();
- }
-
- auto ir = converted.Move();
-
- // Lower from WGSL-dialect to core-dialect
- if (auto res = wgsl::reader::Lower(ir); !res) {
- return res.Failure();
- }
-
- // Raise from core-dialect to SPIR-V-dialect.
- if (auto res = raise::Raise(ir, options); !res) {
- return std::move(res.Failure());
- }
-
- // Generate the SPIR-V code.
- auto spirv = Print(ir, zero_initialize_workgroup_memory);
- if (!spirv) {
- return std::move(spirv.Failure());
- }
- output.spirv = std::move(spirv.Get());
-#else
- return Failure{"use_tint_ir requires building with TINT_BUILD_WGSL_READER"};
-#endif
- } else {
- // Sanitize the program.
- auto sanitized_result = Sanitize(program, options);
- if (!sanitized_result.program.IsValid()) {
- return Failure{sanitized_result.program.Diagnostics()};
- }
-
- // Generate the SPIR-V code.
- auto impl = std::make_unique<ASTPrinter>(
- sanitized_result.program, zero_initialize_workgroup_memory,
- options.experimental_require_subgroup_uniform_control_flow);
- if (!impl->Generate()) {
- return Failure{impl->Diagnostics()};
- }
- output.spirv = std::move(impl->Result());
+ // Sanitize the program.
+ auto sanitized_result = Sanitize(program, options);
+ if (!sanitized_result.program.IsValid()) {
+ return Failure{sanitized_result.program.Diagnostics()};
}
+ // Generate the SPIR-V code.
+ auto impl =
+ std::make_unique<ASTPrinter>(sanitized_result.program, zero_initialize_workgroup_memory,
+ options.experimental_require_subgroup_uniform_control_flow);
+ if (!impl->Generate()) {
+ return Failure{impl->Diagnostics()};
+ }
+ output.spirv = std::move(impl->Result());
+
return output;
}
diff --git a/src/tint/lang/spirv/writer/writer.h b/src/tint/lang/spirv/writer/writer.h
index b050065..807aa9f 100644
--- a/src/tint/lang/spirv/writer/writer.h
+++ b/src/tint/lang/spirv/writer/writer.h
@@ -30,6 +30,7 @@
#include <string>
+#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/spirv/writer/common/options.h"
#include "src/tint/lang/spirv/writer/output.h"
#include "src/tint/utils/diagnostic/diagnostic.h"
@@ -44,6 +45,13 @@
/// Generate SPIR-V for a program, according to a set of configuration options.
/// The result will contain the SPIR-V or failure.
+/// @param ir the IR module to translate to SPIR-V
+/// @param options the configuration options to use when generating SPIR-V
+/// @returns the resulting SPIR-V and supplementary information, or failure.
+Result<Output> Generate(core::ir::Module& ir, const Options& options);
+
+/// Generate SPIR-V for a program, according to a set of configuration options.
+/// The result will contain the SPIR-V or failure.
/// @param program the program to translate to SPIR-V
/// @param options the configuration options to use when generating SPIR-V
/// @returns the resulting SPIR-V and supplementary information, or failure.
diff --git a/src/tint/lang/spirv/writer/writer_bench.cc b/src/tint/lang/spirv/writer/writer_bench.cc
index 5d8766d..2112631 100644
--- a/src/tint/lang/spirv/writer/writer_bench.cc
+++ b/src/tint/lang/spirv/writer/writer_bench.cc
@@ -30,31 +30,50 @@
#include "src/tint/cmd/bench/bench.h"
#include "src/tint/lang/spirv/writer/writer.h"
+#if TINT_BUILD_WGSL_READER
+#include "src/tint/lang/wgsl/reader/reader.h"
+#endif // TINT_BUILD_WGSL_READER
+
namespace tint::spirv::writer {
namespace {
-void RunBenchmark(benchmark::State& state, std::string input_name, Options options) {
+void GenerateSPIRV(benchmark::State& state, std::string input_name) {
auto res = bench::LoadProgram(input_name);
if (!res) {
state.SkipWithError(res.Failure().reason.str());
return;
}
for (auto _ : state) {
- auto gen_res = Generate(res->program, options);
+ auto gen_res = Generate(res->program, {});
if (!gen_res) {
state.SkipWithError(gen_res.Failure().reason.str());
}
}
}
-void GenerateSPIRV(benchmark::State& state, std::string input_name) {
- RunBenchmark(state, input_name, {});
-}
-
void GenerateSPIRV_UseIR(benchmark::State& state, std::string input_name) {
- Options options;
- options.use_tint_ir = true;
- RunBenchmark(state, input_name, std::move(options));
+#if TINT_BUILD_WGSL_READER
+ auto res = bench::LoadProgram(input_name);
+ if (!res) {
+ state.SkipWithError(res.Failure().reason.str());
+ return;
+ }
+ for (auto _ : state) {
+ // Convert the AST program to an IR module.
+ auto ir = tint::wgsl::reader::ProgramToLoweredIR(res->program);
+ if (!ir) {
+ state.SkipWithError(ir.Failure().reason.str());
+ return;
+ }
+
+ auto gen_res = Generate(ir.Get(), {});
+ if (!gen_res) {
+ state.SkipWithError(gen_res.Failure().reason.str());
+ }
+ }
+#else
+#error "WGSL Reader is required to build IR generator"
+#endif // TINT_BUILD_WGSL_READER
}
TINT_BENCHMARK_PROGRAMS(GenerateSPIRV);
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/lang/spirv/writer/writer_fuzz.cc
similarity index 65%
copy from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
copy to src/tint/lang/spirv/writer/writer_fuzz.cc
index 6f0f657..ff37ab7 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/lang/spirv/writer/writer_fuzz.cc
@@ -25,28 +25,29 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
-#define SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#include "src/tint/lang/spirv/writer/writer.h"
-#include <string>
+#include "src/tint/cmd/fuzz/ir/fuzz.h"
+#include "src/tint/lang/spirv/validate/validate.h"
+#include "src/tint/lang/spirv/writer/helpers/generate_bindings.h"
-#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/result/result.h"
+namespace tint::spirv::writer {
+namespace {
-// Forward declarations.
-namespace tint::core::ir {
-class Module;
+void IRPrinterFuzzer(core::ir::Module& module, Options options) {
+ options.bindings = GenerateBindings(module);
+ auto output = Generate(module, options);
+ if (!output) {
+ return;
+ }
+ auto& spirv = output->spirv;
+ if (auto res = validate::Validate(Slice(spirv.data(), spirv.size())); !res) {
+ TINT_ICE() << "Output of SPIR-V writer failed to validate with SPIR-V Tools\n"
+ << res.Failure();
+ }
}
-namespace tint::wgsl::writer {
+} // namespace
+} // namespace tint::spirv::writer
-/// RenameConflicts is a transform that renames declarations which prevent identifiers from
-/// resolving to the correct declaration, and those with identical identifiers declared in the same
-/// scope.
-/// @param module the module to transform
-/// @returns success or failure
-Result<SuccessType> RenameConflicts(core::ir::Module* module);
-
-} // namespace tint::wgsl::writer
-
-#endif // SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+TINT_IR_MODULE_FUZZER(tint::spirv::writer::IRPrinterFuzzer);
diff --git a/src/tint/lang/wgsl/BUILD.bazel b/src/tint/lang/wgsl/BUILD.bazel
index 72a4cc6..6541b22 100644
--- a/src/tint/lang/wgsl/BUILD.bazel
+++ b/src/tint/lang/wgsl/BUILD.bazel
@@ -43,14 +43,12 @@
"diagnostic_rule.cc",
"diagnostic_severity.cc",
"extension.cc",
- "language_feature.cc",
],
hdrs = [
"builtin_fn.h",
"diagnostic_rule.h",
"diagnostic_severity.h",
"extension.h",
- "language_feature.h",
],
deps = [
"//src/tint/utils/containers",
@@ -73,7 +71,6 @@
"diagnostic_rule_test.cc",
"diagnostic_severity_test.cc",
"extension_test.cc",
- "language_feature_test.cc",
"wgsl_test.cc",
] + select({
"//conditions:default": [],
@@ -94,6 +91,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/helpers:test",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/reader/lower",
diff --git a/src/tint/lang/wgsl/BUILD.cmake b/src/tint/lang/wgsl/BUILD.cmake
index 7e09df7..4e0a08b 100644
--- a/src/tint/lang/wgsl/BUILD.cmake
+++ b/src/tint/lang/wgsl/BUILD.cmake
@@ -36,6 +36,7 @@
include(lang/wgsl/ast/BUILD.cmake)
include(lang/wgsl/common/BUILD.cmake)
+include(lang/wgsl/features/BUILD.cmake)
include(lang/wgsl/helpers/BUILD.cmake)
include(lang/wgsl/inspector/BUILD.cmake)
include(lang/wgsl/intrinsic/BUILD.cmake)
@@ -59,8 +60,6 @@
lang/wgsl/diagnostic_severity.h
lang/wgsl/extension.cc
lang/wgsl/extension.h
- lang/wgsl/language_feature.cc
- lang/wgsl/language_feature.h
)
tint_target_add_dependencies(tint_lang_wgsl lib
@@ -83,7 +82,6 @@
lang/wgsl/diagnostic_rule_test.cc
lang/wgsl/diagnostic_severity_test.cc
lang/wgsl/extension_test.cc
- lang/wgsl/language_feature_test.cc
lang/wgsl/wgsl_test.cc
)
@@ -96,6 +94,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_helpers_test
tint_lang_wgsl_program
tint_lang_wgsl_reader_lower
@@ -176,6 +175,7 @@
tint_target_add_dependencies(tint_lang_wgsl_fuzz fuzz
tint_api_common
+ tint_cmd_fuzz_ir_fuzz
tint_lang_core
tint_lang_core_constant
tint_lang_core_ir
@@ -183,13 +183,14 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
- tint_lang_wgsl_helpers
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_reader_lower
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
tint_lang_wgsl_writer_ir_to_program
tint_lang_wgsl_writer_raise
+ tint_utils_bytes
tint_utils_containers
tint_utils_diagnostic
tint_utils_ice
@@ -207,7 +208,6 @@
if(TINT_BUILD_WGSL_READER)
tint_target_add_dependencies(tint_lang_wgsl_fuzz fuzz
- tint_cmd_fuzz_wgsl_fuzz
tint_lang_wgsl_reader_parser
tint_lang_wgsl_reader_program_to_ir
)
diff --git a/src/tint/lang/wgsl/BUILD.gn b/src/tint/lang/wgsl/BUILD.gn
index e27e459..0b9801f 100644
--- a/src/tint/lang/wgsl/BUILD.gn
+++ b/src/tint/lang/wgsl/BUILD.gn
@@ -52,8 +52,6 @@
"diagnostic_severity.h",
"extension.cc",
"extension.h",
- "language_feature.cc",
- "language_feature.h",
]
deps = [
"${tint_src_dir}/utils/containers",
@@ -73,7 +71,6 @@
"diagnostic_rule_test.cc",
"diagnostic_severity_test.cc",
"extension_test.cc",
- "language_feature_test.cc",
"wgsl_test.cc",
]
deps = [
@@ -86,6 +83,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/helpers:unittests",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/reader/lower",
@@ -150,6 +148,7 @@
sources = []
deps = [
"${tint_src_dir}/api/common",
+ "${tint_src_dir}/cmd/fuzz/ir:fuzz",
"${tint_src_dir}/lang/core",
"${tint_src_dir}/lang/core/constant",
"${tint_src_dir}/lang/core/ir",
@@ -157,13 +156,14 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
- "${tint_src_dir}/lang/wgsl/helpers",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/reader/lower",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/lang/wgsl/writer/ir_to_program",
"${tint_src_dir}/lang/wgsl/writer/raise",
+ "${tint_src_dir}/utils/bytes",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
"${tint_src_dir}/utils/ice",
@@ -181,7 +181,6 @@
if (tint_build_wgsl_reader) {
deps += [
- "${tint_src_dir}/cmd/fuzz/wgsl:fuzz",
"${tint_src_dir}/lang/wgsl/reader/parser",
"${tint_src_dir}/lang/wgsl/reader/program_to_ir",
]
diff --git a/src/tint/lang/wgsl/ast/BUILD.bazel b/src/tint/lang/wgsl/ast/BUILD.bazel
index f7514c9..c44c746 100644
--- a/src/tint/lang/wgsl/ast/BUILD.bazel
+++ b/src/tint/lang/wgsl/ast/BUILD.bazel
@@ -208,6 +208,7 @@
"//src/tint/lang/core/constant",
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
+ "//src/tint/lang/wgsl/features",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
"//src/tint/utils/ice",
@@ -313,6 +314,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/ast/BUILD.cmake b/src/tint/lang/wgsl/ast/BUILD.cmake
index fe4eef9..3664cd7 100644
--- a/src/tint/lang/wgsl/ast/BUILD.cmake
+++ b/src/tint/lang/wgsl/ast/BUILD.cmake
@@ -209,6 +209,7 @@
tint_lang_core_constant
tint_lang_core_type
tint_lang_wgsl
+ tint_lang_wgsl_features
tint_utils_containers
tint_utils_diagnostic
tint_utils_ice
@@ -305,6 +306,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
diff --git a/src/tint/lang/wgsl/ast/BUILD.gn b/src/tint/lang/wgsl/ast/BUILD.gn
index 6cc263d..fe2138f 100644
--- a/src/tint/lang/wgsl/ast/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/BUILD.gn
@@ -211,6 +211,7 @@
"${tint_src_dir}/lang/core/constant",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
"${tint_src_dir}/utils/ice",
@@ -305,6 +306,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/ast/builder.h b/src/tint/lang/wgsl/ast/builder.h
index 1b80ec9..7bdaf1e 100644
--- a/src/tint/lang/wgsl/ast/builder.h
+++ b/src/tint/lang/wgsl/ast/builder.h
@@ -1623,7 +1623,7 @@
/// @param feature the feature to require
/// @return a `ast::Requires` requiring the given language feature.
const ast::Requires* Require(wgsl::LanguageFeature feature) {
- auto* req = create<ast::Requires>(wgsl::LanguageFeatures({feature}));
+ auto* req = create<ast::Requires>(Requires::LanguageFeatures({feature}));
AST().AddRequires(req);
return req;
}
@@ -1633,7 +1633,7 @@
/// @param feature the feature to require
/// @return a `ast::Requires` requiring the given language feature.
const ast::Requires* Require(const Source& source, wgsl::LanguageFeature feature) {
- auto* req = create<ast::Requires>(source, wgsl::LanguageFeatures({feature}));
+ auto* req = create<ast::Requires>(source, Requires::LanguageFeatures({feature}));
AST().AddRequires(req);
return req;
}
diff --git a/src/tint/lang/wgsl/ast/requires.cc b/src/tint/lang/wgsl/ast/requires.cc
index 059c35f..0ea77e0 100644
--- a/src/tint/lang/wgsl/ast/requires.cc
+++ b/src/tint/lang/wgsl/ast/requires.cc
@@ -34,7 +34,7 @@
namespace tint::ast {
-Requires::Requires(GenerationID pid, NodeID nid, const Source& src, wgsl::LanguageFeatures feats)
+Requires::Requires(GenerationID pid, NodeID nid, const Source& src, LanguageFeatures feats)
: Base(pid, nid, src), features(std::move(feats)) {}
Requires::~Requires() = default;
diff --git a/src/tint/lang/wgsl/ast/requires.h b/src/tint/lang/wgsl/ast/requires.h
index c94d6b0..eb1f5b8 100644
--- a/src/tint/lang/wgsl/ast/requires.h
+++ b/src/tint/lang/wgsl/ast/requires.h
@@ -33,7 +33,8 @@
#include <vector>
#include "src/tint/lang/wgsl/ast/node.h"
-#include "src/tint/lang/wgsl/language_feature.h"
+#include "src/tint/lang/wgsl/features/language_feature.h"
+#include "src/tint/utils/containers/unique_vector.h"
namespace tint::ast {
@@ -44,12 +45,15 @@
/// ```
class Requires final : public Castable<Requires, Node> {
public:
+ /// A unique list of WGSL language features
+ using LanguageFeatures = UniqueVector<wgsl::LanguageFeature, 4>;
+
/// Create a requires directive
/// @param pid the identifier of the program that owns this node
/// @param nid the unique node identifier
/// @param src the source of this node
/// @param feats the language features being required by this directive
- Requires(GenerationID pid, NodeID nid, const Source& src, wgsl::LanguageFeatures feats);
+ Requires(GenerationID pid, NodeID nid, const Source& src, LanguageFeatures feats);
/// Destructor
~Requires() override;
@@ -60,7 +64,7 @@
const Requires* Clone(CloneContext& ctx) const override;
/// The features being required by this directive.
- const wgsl::LanguageFeatures features;
+ const LanguageFeatures features;
};
} // namespace tint::ast
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.bazel b/src/tint/lang/wgsl/ast/transform/BUILD.bazel
index 6410632..c8ff399 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.bazel
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.bazel
@@ -115,6 +115,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
@@ -187,6 +188,7 @@
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/ast:test",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.cmake b/src/tint/lang/wgsl/ast/transform/BUILD.cmake
index 9100dc7..35b0dcc 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.cmake
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.cmake
@@ -114,6 +114,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
@@ -188,6 +189,7 @@
tint_lang_wgsl_ast_transform
tint_lang_wgsl_ast_test
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
@@ -240,8 +242,10 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
+ tint_utils_bytes
tint_utils_containers
tint_utils_diagnostic
tint_utils_ice
@@ -249,6 +253,7 @@
tint_utils_macros
tint_utils_math
tint_utils_memory
+ tint_utils_reflection
tint_utils_result
tint_utils_rtti
tint_utils_symbol
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.gn b/src/tint/lang/wgsl/ast/transform/BUILD.gn
index 0a1bc92..e0af19e 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.gn
@@ -118,6 +118,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
@@ -189,6 +190,7 @@
"${tint_src_dir}/lang/wgsl/ast:unittests",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
@@ -227,8 +229,10 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
+ "${tint_src_dir}/utils/bytes",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
"${tint_src_dir}/utils/ice",
@@ -236,6 +240,7 @@
"${tint_src_dir}/utils/macros",
"${tint_src_dir}/utils/math",
"${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
"${tint_src_dir}/utils/result",
"${tint_src_dir}/utils/rtti",
"${tint_src_dir}/utils/symbol",
diff --git a/src/tint/lang/wgsl/ast/transform/builtin_polyfill_test.cc b/src/tint/lang/wgsl/ast/transform/builtin_polyfill_test.cc
index 8bc328b..e2d0dde 100644
--- a/src/tint/lang/wgsl/ast/transform/builtin_polyfill_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/builtin_polyfill_test.cc
@@ -456,8 +456,6 @@
TEST_F(BuiltinPolyfillTest, Bgra8unorm_TextureLoad) {
auto* src = R"(
-enable chromium_experimental_read_write_storage_texture;
-
@group(0) @binding(0) var tex : texture_storage_2d<bgra8unorm, read>;
fn f(coords : vec2<i32>) -> vec4<f32> {
@@ -466,8 +464,6 @@
)";
auto* expect = R"(
-enable chromium_experimental_read_write_storage_texture;
-
@group(0) @binding(0) var tex : texture_storage_2d<rgba8unorm, read>;
fn f(coords : vec2<i32>) -> vec4<f32> {
@@ -554,8 +550,6 @@
TEST_F(BuiltinPolyfillTest, Bgra8unorm_TextureLoadAndStore) {
auto* src = R"(
-enable chromium_experimental_read_write_storage_texture;
-
@group(0) @binding(0) var tex : texture_storage_2d<bgra8unorm, read_write>;
fn f(coords : vec2<i32>) {
@@ -564,8 +558,6 @@
)";
auto* expect = R"(
-enable chromium_experimental_read_write_storage_texture;
-
@group(0) @binding(0) var tex : texture_storage_2d<rgba8unorm, read_write>;
fn f(coords : vec2<i32>) {
diff --git a/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory_fuzz.cc b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory_fuzz.cc
index 246fa9b..7fe5685 100644
--- a/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory_fuzz.cc
+++ b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory_fuzz.cc
@@ -27,7 +27,7 @@
#include "src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.h"
-#include "src/tint/cmd/fuzz/wgsl/wgsl_fuzz.h"
+#include "src/tint/cmd/fuzz/wgsl/fuzz.h"
#include "src/tint/lang/wgsl/ast/module.h"
namespace tint::ast::transform {
diff --git a/src/tint/lang/wgsl/common/BUILD.bazel b/src/tint/lang/wgsl/common/BUILD.bazel
index d587bc9..6607f76 100644
--- a/src/tint/lang/wgsl/common/BUILD.bazel
+++ b/src/tint/lang/wgsl/common/BUILD.bazel
@@ -46,6 +46,7 @@
],
deps = [
"//src/tint/lang/wgsl",
+ "//src/tint/lang/wgsl/features",
"//src/tint/utils/containers",
"//src/tint/utils/ice",
"//src/tint/utils/macros",
diff --git a/src/tint/lang/wgsl/common/BUILD.cmake b/src/tint/lang/wgsl/common/BUILD.cmake
index e99cd84..308e43f 100644
--- a/src/tint/lang/wgsl/common/BUILD.cmake
+++ b/src/tint/lang/wgsl/common/BUILD.cmake
@@ -45,6 +45,7 @@
tint_target_add_dependencies(tint_lang_wgsl_common lib
tint_lang_wgsl
+ tint_lang_wgsl_features
tint_utils_containers
tint_utils_ice
tint_utils_macros
diff --git a/src/tint/lang/wgsl/common/BUILD.gn b/src/tint/lang/wgsl/common/BUILD.gn
index 7b21348..6751319 100644
--- a/src/tint/lang/wgsl/common/BUILD.gn
+++ b/src/tint/lang/wgsl/common/BUILD.gn
@@ -45,6 +45,7 @@
]
deps = [
"${tint_src_dir}/lang/wgsl",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/ice",
"${tint_src_dir}/utils/macros",
diff --git a/src/tint/lang/wgsl/common/allowed_features.h b/src/tint/lang/wgsl/common/allowed_features.h
index d494352..7549fc7 100644
--- a/src/tint/lang/wgsl/common/allowed_features.h
+++ b/src/tint/lang/wgsl/common/allowed_features.h
@@ -31,7 +31,7 @@
#include <unordered_set>
#include "src/tint/lang/wgsl/extension.h"
-#include "src/tint/lang/wgsl/language_feature.h"
+#include "src/tint/lang/wgsl/features/language_feature.h"
#include "src/tint/utils/reflection/reflection.h"
namespace tint::wgsl {
diff --git a/src/tint/lang/wgsl/diagnostic_rule_test.cc b/src/tint/lang/wgsl/diagnostic_rule_test.cc
index 2aa78b2..85eccfe 100644
--- a/src/tint/lang/wgsl/diagnostic_rule_test.cc
+++ b/src/tint/lang/wgsl/diagnostic_rule_test.cc
@@ -84,7 +84,7 @@
TEST_P(CoreDiagnosticRulePrintTest, Print) {
CoreDiagnosticRule value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, CoreDiagnosticRulePrintTest, testing::ValuesIn(kValidCases));
@@ -136,7 +136,7 @@
TEST_P(ChromiumDiagnosticRulePrintTest, Print) {
ChromiumDiagnosticRule value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases,
diff --git a/src/tint/lang/wgsl/diagnostic_severity_test.cc b/src/tint/lang/wgsl/diagnostic_severity_test.cc
index 5b09668..88e2b7a 100644
--- a/src/tint/lang/wgsl/diagnostic_severity_test.cc
+++ b/src/tint/lang/wgsl/diagnostic_severity_test.cc
@@ -90,7 +90,7 @@
TEST_P(DiagnosticSeverityPrintTest, Print) {
DiagnosticSeverity value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticSeverityPrintTest, testing::ValuesIn(kValidCases));
diff --git a/src/tint/lang/wgsl/extension.cc b/src/tint/lang/wgsl/extension.cc
index e30d7b2..6b001ef 100644
--- a/src/tint/lang/wgsl/extension.cc
+++ b/src/tint/lang/wgsl/extension.cc
@@ -60,9 +60,6 @@
if (str == "chromium_experimental_push_constant") {
return Extension::kChromiumExperimentalPushConstant;
}
- if (str == "chromium_experimental_read_write_storage_texture") {
- return Extension::kChromiumExperimentalReadWriteStorageTexture;
- }
if (str == "chromium_experimental_subgroups") {
return Extension::kChromiumExperimentalSubgroups;
}
@@ -94,8 +91,6 @@
return "chromium_experimental_pixel_local";
case Extension::kChromiumExperimentalPushConstant:
return "chromium_experimental_push_constant";
- case Extension::kChromiumExperimentalReadWriteStorageTexture:
- return "chromium_experimental_read_write_storage_texture";
case Extension::kChromiumExperimentalSubgroups:
return "chromium_experimental_subgroups";
case Extension::kChromiumInternalDualSourceBlending:
diff --git a/src/tint/lang/wgsl/extension.h b/src/tint/lang/wgsl/extension.h
index 0e259f1..259c925 100644
--- a/src/tint/lang/wgsl/extension.h
+++ b/src/tint/lang/wgsl/extension.h
@@ -52,7 +52,6 @@
kChromiumExperimentalFullPtrParameters,
kChromiumExperimentalPixelLocal,
kChromiumExperimentalPushConstant,
- kChromiumExperimentalReadWriteStorageTexture,
kChromiumExperimentalSubgroups,
kChromiumInternalDualSourceBlending,
kChromiumInternalRelaxedUniformLayout,
@@ -77,17 +76,11 @@
Extension ParseExtension(std::string_view str);
constexpr std::string_view kExtensionStrings[] = {
- "chromium_disable_uniformity_analysis",
- "chromium_experimental_dp4a",
- "chromium_experimental_framebuffer_fetch",
- "chromium_experimental_full_ptr_parameters",
- "chromium_experimental_pixel_local",
- "chromium_experimental_push_constant",
- "chromium_experimental_read_write_storage_texture",
- "chromium_experimental_subgroups",
- "chromium_internal_dual_source_blending",
- "chromium_internal_relaxed_uniform_layout",
- "f16",
+ "chromium_disable_uniformity_analysis", "chromium_experimental_dp4a",
+ "chromium_experimental_framebuffer_fetch", "chromium_experimental_full_ptr_parameters",
+ "chromium_experimental_pixel_local", "chromium_experimental_push_constant",
+ "chromium_experimental_subgroups", "chromium_internal_dual_source_blending",
+ "chromium_internal_relaxed_uniform_layout", "f16",
};
/// All extensions
@@ -98,7 +91,6 @@
Extension::kChromiumExperimentalFullPtrParameters,
Extension::kChromiumExperimentalPixelLocal,
Extension::kChromiumExperimentalPushConstant,
- Extension::kChromiumExperimentalReadWriteStorageTexture,
Extension::kChromiumExperimentalSubgroups,
Extension::kChromiumInternalDualSourceBlending,
Extension::kChromiumInternalRelaxedUniformLayout,
diff --git a/src/tint/lang/wgsl/extension_bench.cc b/src/tint/lang/wgsl/extension_bench.cc
index 06b7f67..63c8636 100644
--- a/src/tint/lang/wgsl/extension_bench.cc
+++ b/src/tint/lang/wgsl/extension_bench.cc
@@ -87,41 +87,34 @@
"chromium_epHrimentkk_psh_constant",
"chromium_expegimenja_puRRh_costant",
"chromium_bxperimental_push_contan",
- "chromium_experimental_read_wjite_storage_texture",
- "chromium_expeimental_read_write_storage_texture",
- "chqomium_experimentl_rad_write_storage_texture",
- "chromium_experimental_read_write_storage_texture",
- "chromium_experimental_read_writNN_storage_texure",
- "chromiumexperimental_read_write_stovvage_texure",
- "chromium_xperimental_read_write_storage_textQQre",
- "cffromium_experimenralsubgrous",
- "chromium_experimentjl_subgroups",
- "chromiu2ww8NNperimental_subgoups",
+ "chromium_experimental_sjbgroups",
+ "chromium_experimental_sbgroups",
+ "cromum_experimentalqsubgroups",
"chromium_experimental_subgroups",
- "chromium_experimental_subgroup",
- "chromiurr_experimental_subgroups",
- "cGromium_experimental_subgroups",
- "chromium_internFFl_dual_source_blending",
- "cEromum_internl_dual_source_bleding",
- "chromium_internal_dual_source_brrendin",
+ "chromium_expNNrimental_subgoups",
+ "chromium_experimetal_svvbgrous",
+ "chromium_experiQental_subgroups",
+ "chrorum_internal_dal_source_bleffding",
+ "chromium_internal_dual_source_jlending",
+ "chromiNNm_internal_dua8_sourwwe_blening",
"chromium_internal_dual_source_blending",
- "chromium_internal_dual_surce_blendin",
- "chromium_iXterJJa_dual_souDce_blending",
- "chromi8m_ineral_dual_source_blendin",
- "chromu11_internal_relaed_uniform_kayou",
- "chromium_internal_relaxd_uniform_layout",
- "chromium_internal_elaxed_uJiform_layout",
+ "chromium_internal_dual_soure_blending",
+ "chromium_irrternal_dual_source_blending",
+ "chromium_internal_duaG_source_blending",
+ "chromium_internalFFrelaxed_uniform_layout",
+ "chromEum_internal_relaxed_unifrmlyout",
+ "chromium_internalrrrelaxd_uniform_layout",
"chromium_internal_relaxed_uniform_layout",
- "chromium_intcrnal_relaxed_uniform_layout",
- "chromiOm_internal_relaxed_uniform_layout",
- "chromiutt_intervva_KK_relaxed_uniform_layout",
- "xx8",
- "__F",
- "f1q",
+ "chromiuminternal_relaxed_uniform_layut",
+ "cXroDium_internal_rJJlaed_uniform_layout",
+ "chromium_int8nal_relaed_uniform_layut",
+ "k",
+ "16",
+ "J1",
"f16",
- "331O",
- "ftt6QQ",
- "666",
+ "c16",
+ "fO6",
+ "_KKttvv",
};
for (auto _ : state) {
for (auto* str : kStrings) {
diff --git a/src/tint/lang/wgsl/extension_test.cc b/src/tint/lang/wgsl/extension_test.cc
index 029deb2..c40bacf 100644
--- a/src/tint/lang/wgsl/extension_test.cc
+++ b/src/tint/lang/wgsl/extension_test.cc
@@ -64,8 +64,6 @@
Extension::kChromiumExperimentalFullPtrParameters},
{"chromium_experimental_pixel_local", Extension::kChromiumExperimentalPixelLocal},
{"chromium_experimental_push_constant", Extension::kChromiumExperimentalPushConstant},
- {"chromium_experimental_read_write_storage_texture",
- Extension::kChromiumExperimentalReadWriteStorageTexture},
{"chromium_experimental_subgroups", Extension::kChromiumExperimentalSubgroups},
{"chromium_internal_dual_source_blending", Extension::kChromiumInternalDualSourceBlending},
{"chromium_internal_relaxed_uniform_layout", Extension::kChromiumInternalRelaxedUniformLayout},
@@ -91,21 +89,18 @@
{"chromium_experEmental_push_constant", Extension::kUndefined},
{"chPPomiumexperimental_push_conTTtant", Extension::kUndefined},
{"chromixxm_experimentddl_push_constnt", Extension::kUndefined},
- {"44hromium_experimental_read_write_storage_texture", Extension::kUndefined},
- {"chromium_experimental_reaSS_wriVVe_storage_texture", Extension::kUndefined},
- {"chro22ium_eRperimental_read_Rrite_storag_texture", Extension::kUndefined},
- {"chromium_experimental_sbgroup9", Extension::kUndefined},
- {"cromium_experimental_subgroups", Extension::kUndefined},
- {"VhrHium_experimental_subOOrouRRs", Extension::kUndefined},
- {"chromium_internay_dual_sorce_blending", Extension::kUndefined},
- {"chrnnmium_internal_duGrr_source_bllend77ng", Extension::kUndefined},
- {"chromiu4_inter00al_dual_source_blending", Extension::kUndefined},
- {"chrmoom_internal_relaxed_uniform_lyout", Extension::kUndefined},
- {"chroium_internal_rlaxed_uniform_layzzut", Extension::kUndefined},
- {"chromium_internaii_r11axed_uppifor_layout", Extension::kUndefined},
- {"f1XX", Extension::kUndefined},
- {"55199II", Extension::kUndefined},
- {"frSSHHa", Extension::kUndefined},
+ {"chromium_experimental_44ubgroups", Extension::kUndefined},
+ {"cSSromVVum_experimental_subgroups", Extension::kUndefined},
+ {"chrmium_e22perimental_suRgrRups", Extension::kUndefined},
+ {"chroFium_internal_dual_source_bl9ndig", Extension::kUndefined},
+ {"chrmium_internal_dual_source_blending", Extension::kUndefined},
+ {"cVromium_interHal_dualOOsouRRce_blening", Extension::kUndefined},
+ {"chromium_internl_relaxyd_uniform_layout", Extension::kUndefined},
+ {"chromnnum_internrr77_Gelaxell_uniform_layout", Extension::kUndefined},
+ {"chromium_intern4l_relaxe00_uniform_layout", Extension::kUndefined},
+ {"5", Extension::kUndefined},
+ {"u16", Extension::kUndefined},
+ {"f", Extension::kUndefined},
};
using ExtensionParseTest = testing::TestWithParam<Case>;
@@ -124,7 +119,7 @@
TEST_P(ExtensionPrintTest, Print) {
Extension value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, ExtensionPrintTest, testing::ValuesIn(kValidCases));
diff --git a/src/tint/lang/wgsl/features/BUILD.bazel b/src/tint/lang/wgsl/features/BUILD.bazel
new file mode 100644
index 0000000..cec9088
--- /dev/null
+++ b/src/tint/lang/wgsl/features/BUILD.bazel
@@ -0,0 +1,73 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+cc_library(
+ name = "features",
+ srcs = [
+ "language_feature.cc",
+ ],
+ hdrs = [
+ "language_feature.h",
+ ],
+ deps = [
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+cc_library(
+ name = "test",
+ alwayslink = True,
+ srcs = [
+ "language_feature_test.cc",
+ ],
+ deps = [
+ "//src/tint/lang/wgsl/features",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ "@gtest",
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+
diff --git a/src/tint/lang/wgsl/features/BUILD.cmake b/src/tint/lang/wgsl/features/BUILD.cmake
new file mode 100644
index 0000000..9bbfe60
--- /dev/null
+++ b/src/tint/lang/wgsl/features/BUILD.cmake
@@ -0,0 +1,68 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+################################################################################
+# Target: tint_lang_wgsl_features
+# Kind: lib
+################################################################################
+tint_add_target(tint_lang_wgsl_features lib
+ lang/wgsl/features/language_feature.cc
+ lang/wgsl/features/language_feature.h
+)
+
+################################################################################
+# Target: tint_lang_wgsl_features_test
+# Kind: test
+################################################################################
+tint_add_target(tint_lang_wgsl_features_test test
+ lang/wgsl/features/language_feature_test.cc
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_features_test test
+ tint_lang_wgsl_features
+ tint_utils_containers
+ tint_utils_ice
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_rtti
+ tint_utils_text
+ tint_utils_traits
+)
+
+tint_target_add_external_dependencies(tint_lang_wgsl_features_test test
+ "gtest"
+)
diff --git a/src/tint/lang/wgsl/features/BUILD.gn b/src/tint/lang/wgsl/features/BUILD.gn
new file mode 100644
index 0000000..db3557a
--- /dev/null
+++ b/src/tint/lang/wgsl/features/BUILD.gn
@@ -0,0 +1,50 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# NOTE: This file is intentionally *not* generated by 'tools/src/cmd/gen' as
+# this GN target is to be used outside of Dawn and must be entirely dependency
+# free.
+#
+# GEN_BUILD:DO_NOT_GENERATE
+#
+################################################################################
+
+source_set("features") {
+ sources = [
+ "language_feature.cc",
+ "language_feature.h",
+ ]
+ deps = []
+
+ include_dirs = [ "../../../../../" ]
+}
+
+source_set("unittests") {
+ testonly = true
+ sources = [] # empty as we don't want to depend on gtest, etc.
+}
diff --git a/src/tint/lang/wgsl/language_feature.cc b/src/tint/lang/wgsl/features/language_feature.cc
similarity index 95%
rename from src/tint/lang/wgsl/language_feature.cc
rename to src/tint/lang/wgsl/features/language_feature.cc
index a5e0430..df6a24c 100644
--- a/src/tint/lang/wgsl/language_feature.cc
+++ b/src/tint/lang/wgsl/features/language_feature.cc
@@ -27,14 +27,14 @@
////////////////////////////////////////////////////////////////////////////////
// File generated by 'tools/src/cmd/gen' using the template:
-// src/tint/lang/wgsl/language_feature.cc.tmpl
+// src/tint/lang/wgsl/features/language_feature.cc.tmpl
//
// To regenerate run: './tools/run gen'
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
-#include "src/tint/lang/wgsl/language_feature.h"
+#include "src/tint/lang/wgsl/features/language_feature.h"
namespace tint::wgsl {
diff --git a/src/tint/lang/wgsl/language_feature.cc.tmpl b/src/tint/lang/wgsl/features/language_feature.cc.tmpl
similarity index 91%
rename from src/tint/lang/wgsl/language_feature.cc.tmpl
rename to src/tint/lang/wgsl/features/language_feature.cc.tmpl
index 782b515..3e0b174 100644
--- a/src/tint/lang/wgsl/language_feature.cc.tmpl
+++ b/src/tint/lang/wgsl/features/language_feature.cc.tmpl
@@ -12,7 +12,7 @@
{{- Import "src/tint/utils/templates/enums.tmpl.inc" -}}
{{- $enum := ($I.Sem.Enum "language_feature") -}}
-#include "src/tint/lang/wgsl/language_feature.h"
+#include "src/tint/lang/wgsl/features/language_feature.h"
namespace tint::wgsl {
diff --git a/src/tint/lang/wgsl/language_feature.h b/src/tint/lang/wgsl/features/language_feature.h
similarity index 80%
rename from src/tint/lang/wgsl/language_feature.h
rename to src/tint/lang/wgsl/features/language_feature.h
index afdbdba..1187bfa 100644
--- a/src/tint/lang/wgsl/language_feature.h
+++ b/src/tint/lang/wgsl/features/language_feature.h
@@ -27,18 +27,18 @@
////////////////////////////////////////////////////////////////////////////////
// File generated by 'tools/src/cmd/gen' using the template:
-// src/tint/lang/wgsl/language_feature.h.tmpl
+// src/tint/lang/wgsl/features/language_feature.h.tmpl
//
// To regenerate run: './tools/run gen'
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
-#ifndef SRC_TINT_LANG_WGSL_LANGUAGE_FEATURE_H_
-#define SRC_TINT_LANG_WGSL_LANGUAGE_FEATURE_H_
+#ifndef SRC_TINT_LANG_WGSL_FEATURES_LANGUAGE_FEATURE_H_
+#define SRC_TINT_LANG_WGSL_FEATURES_LANGUAGE_FEATURE_H_
-#include "src/tint/utils/containers/unique_vector.h"
-#include "src/tint/utils/traits/traits.h"
+#include <cstdint>
+#include <string>
namespace tint::wgsl {
@@ -53,14 +53,6 @@
/// @returns the string for the given enum value
std::string_view ToString(LanguageFeature value);
-/// @param out the stream to write to
-/// @param value the LanguageFeature
-/// @returns @p out so calls can be chained
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
-auto& operator<<(STREAM& out, LanguageFeature value) {
- return out << ToString(value);
-}
-
/// ParseLanguageFeature parses a LanguageFeature from a string.
/// @param str the string to parse
/// @returns the parsed enum, or LanguageFeature::kUndefined if the string could not be parsed.
@@ -75,9 +67,6 @@
LanguageFeature::kReadonlyAndReadwriteStorageTextures,
};
-/// A unique vector of language features
-using LanguageFeatures = UniqueVector<LanguageFeature, 4>;
-
} // namespace tint::wgsl
-#endif // SRC_TINT_LANG_WGSL_LANGUAGE_FEATURE_H_
+#endif // SRC_TINT_LANG_WGSL_FEATURES_LANGUAGE_FEATURE_H_
diff --git a/src/tint/lang/wgsl/language_feature.h.tmpl b/src/tint/lang/wgsl/features/language_feature.h.tmpl
similarity index 71%
rename from src/tint/lang/wgsl/language_feature.h.tmpl
rename to src/tint/lang/wgsl/features/language_feature.h.tmpl
index 7c88975..da42959 100644
--- a/src/tint/lang/wgsl/language_feature.h.tmpl
+++ b/src/tint/lang/wgsl/features/language_feature.h.tmpl
@@ -12,17 +12,17 @@
{{- Import "src/tint/utils/templates/enums.tmpl.inc" -}}
{{- $enum := ($I.Sem.Enum "language_feature") -}}
-#ifndef SRC_TINT_LANG_WGSL_LANGUAGE_FEATURE_H_
-#define SRC_TINT_LANG_WGSL_LANGUAGE_FEATURE_H_
+#ifndef SRC_TINT_LANG_WGSL_FEATURES_LANGUAGE_FEATURE_H_
+#define SRC_TINT_LANG_WGSL_FEATURES_LANGUAGE_FEATURE_H_
-#include "src/tint/utils/traits/traits.h"
-#include "src/tint/utils/containers/unique_vector.h"
+#include <cstdint>
+#include <string>
namespace tint::wgsl {
/// An enumerator of WGSL language features
/// @see src/tint/lang/wgsl/intrinsics.def for language feature descriptions
-{{ Eval "DeclareEnum" $enum}}
+{{ Eval "DeclareEnum" "Enum" $enum "EmitOStream" false}}
/// All features
static constexpr LanguageFeature kAllLanguageFeatures[] = {
@@ -31,9 +31,6 @@
{{- end }}
};
-/// A unique vector of language features
-using LanguageFeatures = UniqueVector<LanguageFeature, 4>;
-
} // namespace tint::wgsl
-#endif // SRC_TINT_LANG_WGSL_LANGUAGE_FEATURE_H_
+#endif // SRC_TINT_LANG_WGSL_FEATURES_LANGUAGE_FEATURE_H_
diff --git a/src/tint/lang/wgsl/language_feature_test.cc b/src/tint/lang/wgsl/features/language_feature_test.cc
similarity index 95%
rename from src/tint/lang/wgsl/language_feature_test.cc
rename to src/tint/lang/wgsl/features/language_feature_test.cc
index 4597ce9..295e3a5 100644
--- a/src/tint/lang/wgsl/language_feature_test.cc
+++ b/src/tint/lang/wgsl/features/language_feature_test.cc
@@ -27,14 +27,14 @@
////////////////////////////////////////////////////////////////////////////////
// File generated by 'tools/src/cmd/gen' using the template:
-// src/tint/lang/wgsl/language_feature_test.cc.tmpl
+// src/tint/lang/wgsl/features/language_feature_test.cc.tmpl
//
// To regenerate run: './tools/run gen'
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
-#include "src/tint/lang/wgsl/language_feature.h"
+#include "src/tint/lang/wgsl/features/language_feature.h"
#include <gtest/gtest.h>
@@ -83,7 +83,7 @@
TEST_P(LanguageFeaturePrintTest, Print) {
LanguageFeature value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, LanguageFeaturePrintTest, testing::ValuesIn(kValidCases));
diff --git a/src/tint/lang/wgsl/language_feature_test.cc.tmpl b/src/tint/lang/wgsl/features/language_feature_test.cc.tmpl
similarity index 92%
rename from src/tint/lang/wgsl/language_feature_test.cc.tmpl
rename to src/tint/lang/wgsl/features/language_feature_test.cc.tmpl
index fe98798..1a3c4cb 100644
--- a/src/tint/lang/wgsl/language_feature_test.cc.tmpl
+++ b/src/tint/lang/wgsl/features/language_feature_test.cc.tmpl
@@ -12,7 +12,7 @@
{{- Import "src/tint/utils/templates/enums.tmpl.inc" -}}
{{- $enum := ($I.Sem.Enum "language_feature") -}}
-#include "src/tint/lang/wgsl/language_feature.h"
+#include "src/tint/lang/wgsl/features/language_feature.h"
#include <gtest/gtest.h>
diff --git a/src/tint/lang/wgsl/helpers/BUILD.bazel b/src/tint/lang/wgsl/helpers/BUILD.bazel
index acc0183..c43af56 100644
--- a/src/tint/lang/wgsl/helpers/BUILD.bazel
+++ b/src/tint/lang/wgsl/helpers/BUILD.bazel
@@ -58,6 +58,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/inspector",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
@@ -102,6 +103,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast:test",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/helpers",
"//src/tint/lang/wgsl/intrinsic",
"//src/tint/lang/wgsl/program",
diff --git a/src/tint/lang/wgsl/helpers/BUILD.cmake b/src/tint/lang/wgsl/helpers/BUILD.cmake
index dbf2a9e..f76d258 100644
--- a/src/tint/lang/wgsl/helpers/BUILD.cmake
+++ b/src/tint/lang/wgsl/helpers/BUILD.cmake
@@ -57,6 +57,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
+ tint_lang_wgsl_features
tint_lang_wgsl_inspector
tint_lang_wgsl_program
tint_lang_wgsl_sem
@@ -96,6 +97,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_test
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_helpers
tint_lang_wgsl_intrinsic
tint_lang_wgsl_program
diff --git a/src/tint/lang/wgsl/helpers/BUILD.gn b/src/tint/lang/wgsl/helpers/BUILD.gn
index 4ae3943..91edc4b 100644
--- a/src/tint/lang/wgsl/helpers/BUILD.gn
+++ b/src/tint/lang/wgsl/helpers/BUILD.gn
@@ -61,6 +61,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast/transform",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/inspector",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
@@ -98,6 +99,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast:unittests",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/helpers",
"${tint_src_dir}/lang/wgsl/intrinsic",
"${tint_src_dir}/lang/wgsl/program",
diff --git a/src/tint/lang/wgsl/inspector/BUILD.bazel b/src/tint/lang/wgsl/inspector/BUILD.bazel
index a85b5c8..84c7690 100644
--- a/src/tint/lang/wgsl/inspector/BUILD.bazel
+++ b/src/tint/lang/wgsl/inspector/BUILD.bazel
@@ -57,6 +57,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
@@ -95,6 +96,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/inspector",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
diff --git a/src/tint/lang/wgsl/inspector/BUILD.cmake b/src/tint/lang/wgsl/inspector/BUILD.cmake
index a36fd2c..71cddb5 100644
--- a/src/tint/lang/wgsl/inspector/BUILD.cmake
+++ b/src/tint/lang/wgsl/inspector/BUILD.cmake
@@ -56,6 +56,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
@@ -96,6 +97,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_inspector
tint_lang_wgsl_program
tint_lang_wgsl_resolver
diff --git a/src/tint/lang/wgsl/inspector/BUILD.gn b/src/tint/lang/wgsl/inspector/BUILD.gn
index a01205f..5b75094 100644
--- a/src/tint/lang/wgsl/inspector/BUILD.gn
+++ b/src/tint/lang/wgsl/inspector/BUILD.gn
@@ -60,6 +60,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
@@ -97,6 +98,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/inspector",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
diff --git a/src/tint/lang/wgsl/ir/builtin_call.cc b/src/tint/lang/wgsl/ir/builtin_call.cc
index 45cc898..b841a6d 100644
--- a/src/tint/lang/wgsl/ir/builtin_call.cc
+++ b/src/tint/lang/wgsl/ir/builtin_call.cc
@@ -48,7 +48,7 @@
BuiltinCall::~BuiltinCall() = default;
BuiltinCall* BuiltinCall::Clone(core::ir::CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result());
+ auto* new_result = ctx.Clone(Result(0));
auto new_args = ctx.Clone<BuiltinCall::kDefaultNumOperands>(Args());
return ctx.ir.instructions.Create<BuiltinCall>(new_result, fn_, new_args);
}
diff --git a/src/tint/lang/wgsl/ir/builtin_call.h b/src/tint/lang/wgsl/ir/builtin_call.h
index 331c558..043129e 100644
--- a/src/tint/lang/wgsl/ir/builtin_call.h
+++ b/src/tint/lang/wgsl/ir/builtin_call.h
@@ -54,16 +54,18 @@
BuiltinCall* Clone(core::ir::CloneContext& ctx) override;
/// @returns the builtin function
- BuiltinFn Func() { return fn_; }
+ BuiltinFn Func() const { return fn_; }
/// @returns the identifier for the function
- size_t FuncId() override { return static_cast<size_t>(fn_); }
+ size_t FuncId() const override { return static_cast<size_t>(fn_); }
/// @returns the friendly name for the instruction
- std::string FriendlyName() override { return std::string("wgsl.") + str(fn_); }
+ std::string FriendlyName() const override { return std::string("wgsl.") + str(fn_); }
/// @returns the table data to validate this builtin
- const core::intrinsic::TableData& TableData() override { return intrinsic::Dialect::kData; }
+ const core::intrinsic::TableData& TableData() const override {
+ return intrinsic::Dialect::kData;
+ }
private:
BuiltinFn fn_;
diff --git a/src/tint/lang/wgsl/ir_roundtrip_fuzz.cc b/src/tint/lang/wgsl/ir_roundtrip_fuzz.cc
index 8671ac9..12d97c1 100644
--- a/src/tint/lang/wgsl/ir_roundtrip_fuzz.cc
+++ b/src/tint/lang/wgsl/ir_roundtrip_fuzz.cc
@@ -29,9 +29,8 @@
#include <iostream>
-#include "src/tint/cmd/fuzz/wgsl/wgsl_fuzz.h"
+#include "src/tint/cmd/fuzz/ir/fuzz.h"
#include "src/tint/lang/core/ir/disassembler.h"
-#include "src/tint/lang/wgsl/helpers/apply_substitute_overrides.h"
#include "src/tint/lang/wgsl/reader/lower/lower.h"
#include "src/tint/lang/wgsl/reader/parser/parser.h"
#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
@@ -40,57 +39,16 @@
#include "src/tint/lang/wgsl/writer/writer.h"
namespace tint::wgsl {
-namespace {
-bool IsUnsupported(const tint::ast::Enable* enable) {
- for (auto ext : enable->extensions) {
- switch (ext->name) {
- case tint::wgsl::Extension::kChromiumExperimentalDp4A:
- case tint::wgsl::Extension::kChromiumExperimentalFullPtrParameters:
- case tint::wgsl::Extension::kChromiumExperimentalPixelLocal:
- case tint::wgsl::Extension::kChromiumExperimentalPushConstant:
- case tint::wgsl::Extension::kChromiumInternalDualSourceBlending:
- case tint::wgsl::Extension::kChromiumInternalRelaxedUniformLayout:
- return true;
- default:
- break;
- }
- }
- return false;
-}
-
-} // namespace
-
-void IRRoundtripFuzzer(const tint::Program& program) {
- if (program.AST().Enables().Any(IsUnsupported)) {
- return;
- }
-
- auto transformed = tint::wgsl::ApplySubstituteOverrides(program);
- auto& src = transformed ? transformed.value() : program;
- if (!src.IsValid()) {
- return;
- }
-
- auto ir = tint::wgsl::reader::ProgramToIR(src);
- if (!ir) {
- TINT_ICE() << ir.Failure();
- return;
- }
-
- if (auto res = tint::wgsl::reader::Lower(ir.Get()); !res) {
+void IRRoundtripFuzzer(core::ir::Module& ir) {
+ if (auto res = tint::wgsl::writer::Raise(ir); !res) {
TINT_ICE() << res.Failure();
return;
}
- if (auto res = tint::wgsl::writer::Raise(ir.Get()); !res) {
- TINT_ICE() << res.Failure();
- return;
- }
-
- auto dst = tint::wgsl::writer::IRToProgram(ir.Get());
+ auto dst = tint::wgsl::writer::IRToProgram(ir);
if (!dst.IsValid()) {
- std::cerr << "IR:\n" << core::ir::Disassemble(ir.Get()) << std::endl;
+ std::cerr << "IR:\n" << core::ir::Disassemble(ir) << std::endl;
if (auto result = tint::wgsl::writer::Generate(dst, {}); result) {
std::cerr << "WGSL:\n" << result->wgsl << std::endl << std::endl;
}
@@ -103,4 +61,4 @@
} // namespace tint::wgsl
-TINT_WGSL_PROGRAM_FUZZER(tint::wgsl::IRRoundtripFuzzer);
+TINT_IR_MODULE_FUZZER(tint::wgsl::IRRoundtripFuzzer);
diff --git a/src/tint/lang/wgsl/program/BUILD.bazel b/src/tint/lang/wgsl/program/BUILD.bazel
index 3950041..96c0879 100644
--- a/src/tint/lang/wgsl/program/BUILD.bazel
+++ b/src/tint/lang/wgsl/program/BUILD.bazel
@@ -55,6 +55,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
@@ -90,6 +91,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast:test",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/program/BUILD.cmake b/src/tint/lang/wgsl/program/BUILD.cmake
index 2e04315..c55fc5a 100644
--- a/src/tint/lang/wgsl/program/BUILD.cmake
+++ b/src/tint/lang/wgsl/program/BUILD.cmake
@@ -54,6 +54,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_sem
tint_utils_containers
tint_utils_diagnostic
@@ -89,6 +90,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_test
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
@@ -126,9 +128,11 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
+ tint_utils_bytes
tint_utils_containers
tint_utils_diagnostic
tint_utils_ice
diff --git a/src/tint/lang/wgsl/program/BUILD.gn b/src/tint/lang/wgsl/program/BUILD.gn
index 03d0b77..f3e03fd 100644
--- a/src/tint/lang/wgsl/program/BUILD.gn
+++ b/src/tint/lang/wgsl/program/BUILD.gn
@@ -58,6 +58,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
@@ -91,6 +92,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast:unittests",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
@@ -121,9 +123,11 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
+ "${tint_src_dir}/utils/bytes",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
"${tint_src_dir}/utils/ice",
diff --git a/src/tint/lang/wgsl/program/clone_context_fuzz.cc b/src/tint/lang/wgsl/program/clone_context_fuzz.cc
index e4cfc2f..17d802a 100644
--- a/src/tint/lang/wgsl/program/clone_context_fuzz.cc
+++ b/src/tint/lang/wgsl/program/clone_context_fuzz.cc
@@ -30,7 +30,7 @@
#include <string>
#include <unordered_set>
-#include "src/tint/cmd/fuzz/wgsl/wgsl_fuzz.h"
+#include "src/tint/cmd/fuzz/wgsl/fuzz.h"
#include "src/tint/lang/wgsl/reader/parser/parser.h"
#include "src/tint/lang/wgsl/writer/writer.h"
diff --git a/src/tint/lang/wgsl/program/program_builder.cc b/src/tint/lang/wgsl/program/program_builder.cc
index 596aa84..7f68f22 100644
--- a/src/tint/lang/wgsl/program/program_builder.cc
+++ b/src/tint/lang/wgsl/program/program_builder.cc
@@ -67,7 +67,7 @@
builder.ast_ =
builder.create<ast::Module>(program.AST().source, program.AST().GlobalDeclarations());
builder.sem_ = sem::Info::Wrap(program.Sem());
- builder.symbols_.Wrap(program.Symbols());
+ builder.symbols_ = SymbolTable::Wrap(program.Symbols());
builder.diagnostics_ = program.Diagnostics();
return builder;
}
diff --git a/src/tint/lang/wgsl/reader/BUILD.bazel b/src/tint/lang/wgsl/reader/BUILD.bazel
index 07fb326..bba5e4a 100644
--- a/src/tint/lang/wgsl/reader/BUILD.bazel
+++ b/src/tint/lang/wgsl/reader/BUILD.bazel
@@ -54,6 +54,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/reader/lower",
"//src/tint/lang/wgsl/resolver",
@@ -97,6 +98,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/wgsl/reader/BUILD.cmake b/src/tint/lang/wgsl/reader/BUILD.cmake
index a213212..f30cb80 100644
--- a/src/tint/lang/wgsl/reader/BUILD.cmake
+++ b/src/tint/lang/wgsl/reader/BUILD.cmake
@@ -59,6 +59,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_reader_lower
tint_lang_wgsl_resolver
@@ -106,6 +107,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/wgsl/reader/BUILD.gn b/src/tint/lang/wgsl/reader/BUILD.gn
index 8f4b35c..eb9cbc1 100644
--- a/src/tint/lang/wgsl/reader/BUILD.gn
+++ b/src/tint/lang/wgsl/reader/BUILD.gn
@@ -57,6 +57,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/reader/lower",
"${tint_src_dir}/lang/wgsl/resolver",
@@ -99,6 +100,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/wgsl/reader/lower/lower.cc b/src/tint/lang/wgsl/reader/lower/lower.cc
index dabab5d..381fad1 100644
--- a/src/tint/lang/wgsl/reader/lower/lower.cc
+++ b/src/tint/lang/wgsl/reader/lower/lower.cc
@@ -176,6 +176,9 @@
core::ir::Builder b{mod};
core::type::Manager& ty{mod.Types()};
for (auto* inst : mod.instructions.Objects()) {
+ if (!inst->Alive()) {
+ continue;
+ }
if (auto* call = inst->As<wgsl::ir::BuiltinCall>()) {
switch (call->Func()) {
case BuiltinFn::kWorkgroupUniformLoad: {
@@ -188,7 +191,7 @@
b.InsertBefore(call, [&] {
b.Call(ty.void_(), core::BuiltinFn::kWorkgroupBarrier);
auto* load = b.Load(call->Args()[0]);
- call->Result()->ReplaceAllUsesWith(load->Result());
+ call->Result(0)->ReplaceAllUsesWith(load->Result(0));
b.Call(ty.void_(), core::BuiltinFn::kWorkgroupBarrier);
});
break;
@@ -196,7 +199,7 @@
default: {
Vector<core::ir::Value*, 8> args(call->Args());
auto* replacement = mod.instructions.Create<core::ir::CoreBuiltinCall>(
- call->Result(), Convert(call->Func()), std::move(args));
+ call->Result(0), Convert(call->Func()), std::move(args));
call->ReplaceWith(replacement);
call->ClearResults();
break;
diff --git a/src/tint/lang/wgsl/reader/lower/lower_test.cc b/src/tint/lang/wgsl/reader/lower/lower_test.cc
index 6244192..dd05a5d 100644
--- a/src/tint/lang/wgsl/reader/lower/lower_test.cc
+++ b/src/tint/lang/wgsl/reader/lower/lower_test.cc
@@ -85,7 +85,7 @@
b.Append(f->Block(), [&] { //
auto* result = b.InstructionResult(ty.i32());
b.Append(b.ir.instructions.Create<wgsl::ir::BuiltinCall>(
- result, wgsl::BuiltinFn::kWorkgroupUniformLoad, Vector{wgvar->Result()}));
+ result, wgsl::BuiltinFn::kWorkgroupUniformLoad, Vector{wgvar->Result(0)}));
b.Return(f, result);
});
diff --git a/src/tint/lang/wgsl/reader/parser/BUILD.bazel b/src/tint/lang/wgsl/reader/parser/BUILD.bazel
index ce2d480..724f05d 100644
--- a/src/tint/lang/wgsl/reader/parser/BUILD.bazel
+++ b/src/tint/lang/wgsl/reader/parser/BUILD.bazel
@@ -59,6 +59,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
@@ -161,6 +162,7 @@
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast:test",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/reader/parser/BUILD.cmake b/src/tint/lang/wgsl/reader/parser/BUILD.cmake
index 427ec60..d2e9c49 100644
--- a/src/tint/lang/wgsl/reader/parser/BUILD.cmake
+++ b/src/tint/lang/wgsl/reader/parser/BUILD.cmake
@@ -60,6 +60,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
@@ -165,6 +166,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_ast_test
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
diff --git a/src/tint/lang/wgsl/reader/parser/BUILD.gn b/src/tint/lang/wgsl/reader/parser/BUILD.gn
index 9aca136..f68c92c 100644
--- a/src/tint/lang/wgsl/reader/parser/BUILD.gn
+++ b/src/tint/lang/wgsl/reader/parser/BUILD.gn
@@ -62,6 +62,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
@@ -164,6 +165,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/ast:unittests",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc b/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
index 893573c..6536271 100644
--- a/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
@@ -205,7 +205,7 @@
// Error when unknown extension found
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_framebuffer_fetch', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_pixel_local', 'chromium_experimental_push_constant', 'chromium_experimental_read_write_storage_texture', 'chromium_experimental_subgroups', 'chromium_internal_dual_source_blending', 'chromium_internal_relaxed_uniform_layout', 'f16')");
+Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_framebuffer_fetch', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_pixel_local', 'chromium_experimental_push_constant', 'chromium_experimental_subgroups', 'chromium_internal_dual_source_blending', 'chromium_internal_relaxed_uniform_layout', 'f16')");
auto program = p->program();
auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u);
diff --git a/src/tint/lang/wgsl/reader/parser/lexer.cc b/src/tint/lang/wgsl/reader/parser/lexer.cc
index 7b19d4c..102dffa 100644
--- a/src/tint/lang/wgsl/reader/parser/lexer.cc
+++ b/src/tint/lang/wgsl/reader/parser/lexer.cc
@@ -31,11 +31,10 @@
#include <charconv>
#include <cmath>
#include <cstring>
-#include <functional>
#include <limits>
#include <optional>
+#include <string>
#include <tuple>
-#include <type_traits>
#include <utility>
#include "src/tint/lang/core/fluent_types.h"
@@ -430,9 +429,9 @@
end_ptr = &at(length() - 1) + 1;
}
- auto ret = tint::ParseDouble(std::string_view(&at(start), end - start));
+ auto ret = tint::strconv::ParseDouble(std::string_view(&at(start), end - start));
double value = ret ? ret.Get() : 0.0;
- bool overflow = !ret && ret.Failure() == tint::ParseNumberError::kResultOutOfRange;
+ bool overflow = !ret && ret.Failure() == tint::strconv::ParseNumberError::kResultOutOfRange;
// If the value didn't fit in a double, check for underflow as that is 0.0 in WGSL and not an
// error.
diff --git a/src/tint/lang/wgsl/reader/parser/lexer.h b/src/tint/lang/wgsl/reader/parser/lexer.h
index 7d10dd9..6e97551 100644
--- a/src/tint/lang/wgsl/reader/parser/lexer.h
+++ b/src/tint/lang/wgsl/reader/parser/lexer.h
@@ -29,7 +29,6 @@
#define SRC_TINT_LANG_WGSL_READER_PARSER_LEXER_H_
#include <optional>
-#include <string>
#include <vector>
#include "src/tint/lang/wgsl/reader/parser/token.h"
diff --git a/src/tint/lang/wgsl/reader/parser/lexer_test.cc b/src/tint/lang/wgsl/reader/parser/lexer_test.cc
index 105c9f6..1464396 100644
--- a/src/tint/lang/wgsl/reader/parser/lexer_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/lexer_test.cc
@@ -28,6 +28,7 @@
#include "src/tint/lang/wgsl/reader/parser/lexer.h"
#include <limits>
+#include <string>
#include <tuple>
#include <vector>
diff --git a/src/tint/lang/wgsl/reader/parser/parser.cc b/src/tint/lang/wgsl/reader/parser/parser.cc
index 8cc0bba..e3698f9 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.cc
+++ b/src/tint/lang/wgsl/reader/parser/parser.cc
@@ -474,7 +474,7 @@
return add_error(t.source(), "requires directives don't take parenthesis");
}
- wgsl::LanguageFeatures features;
+ ast::Requires::LanguageFeatures features;
while (continue_parsing()) {
auto& t2 = next();
if (handle_error(t2)) {
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel
index 619764a..551faa8 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel
+++ b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel
@@ -53,6 +53,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/intrinsic",
"//src/tint/lang/wgsl/ir",
"//src/tint/lang/wgsl/program",
@@ -101,6 +102,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/helpers:test",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/reader/lower",
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake
index c869ca2..1c43bfe 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake
+++ b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake
@@ -54,6 +54,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_intrinsic
tint_lang_wgsl_ir
tint_lang_wgsl_program
@@ -105,6 +106,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_helpers_test
tint_lang_wgsl_program
tint_lang_wgsl_reader_lower
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
index 9948752..41ff6f8 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
+++ b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
@@ -56,6 +56,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/intrinsic",
"${tint_src_dir}/lang/wgsl/ir",
"${tint_src_dir}/lang/wgsl/program",
@@ -104,6 +105,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/helpers:unittests",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/reader/lower",
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/accessor_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/accessor_test.cc
index 3f939fa..9e666f9 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/accessor_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/accessor_test.cc
@@ -58,7 +58,8 @@
%b1 = block {
%a:ptr<function, array<u32, 3>, read_write> = var
%3:ptr<function, u32, read_write> = access %a, 2u
- %b:u32 = load %3
+ %4:u32 = load %3
+ %b:u32 = let %4
ret
}
}
@@ -83,8 +84,10 @@
R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
%a:vec3<u32> = let vec3<u32>(0u)
- %b:u32 = access %a, 2u
- %c:u32 = access %a, 1u
+ %3:u32 = access %a, 2u
+ %b:u32 = let %3
+ %5:u32 = access %a, 1u
+ %c:u32 = let %5
ret
}
}
@@ -106,7 +109,8 @@
R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
%a:ptr<function, vec3<u32>, read_write> = var
- %b:u32 = load_vector_element %a, 2u
+ %3:u32 = load_vector_element %a, 2u
+ %b:u32 = let %3
ret
}
}
@@ -129,7 +133,8 @@
%b1 = block {
%a:ptr<function, array<array<f32, 4>, 3>, read_write> = var
%3:ptr<function, f32, read_write> = access %a, 2u, 3u
- %b:f32 = load %3
+ %4:f32 = load %3
+ %b:f32 = let %4
ret
}
}
@@ -152,7 +157,8 @@
%b1 = block {
%a:ptr<function, mat3x4<f32>, read_write> = var
%3:ptr<function, vec4<f32>, read_write> = access %a, 2u
- %b:f32 = load_vector_element %3, 3u
+ %4:f32 = load_vector_element %3, 3u
+ %b:f32 = let %4
ret
}
}
@@ -183,7 +189,8 @@
%b1 = block {
%a:ptr<function, MyStruct, read_write> = var
%3:ptr<function, i32, read_write> = access %a, 0u
- %b:i32 = load %3
+ %4:i32 = load %3
+ %b:i32 = let %4
ret
}
}
@@ -224,7 +231,8 @@
%b1 = block {
%a:ptr<function, Outer, read_write> = var
%3:ptr<function, f32, read_write> = access %a, 1u, 0u
- %b:f32 = load %3
+ %4:f32 = load %3
+ %b:f32 = let %4
ret
}
}
@@ -271,7 +279,8 @@
%b1 = block {
%a:ptr<function, array<Outer, 4>, read_write> = var
%3:ptr<function, vec4<f32>, read_write> = access %a, 0u, 1u, 1u, 2u
- %b:vec4<f32> = load %3
+ %4:vec4<f32> = load %3
+ %b:vec4<f32> = let %4
ret
}
}
@@ -316,7 +325,8 @@
R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
%a:ptr<function, vec2<f32>, read_write> = var
- %b:f32 = load_vector_element %a, 1u
+ %3:f32 = load_vector_element %a, 1u
+ %b:f32 = let %3
ret
}
}
@@ -339,7 +349,8 @@
%b1 = block {
%a:ptr<function, vec3<f32>, read_write> = var
%3:vec3<f32> = load %a
- %b:vec4<f32> = swizzle %3, zyxz
+ %4:vec4<f32> = swizzle %3, zyxz
+ %b:vec4<f32> = let %4
ret
}
}
@@ -363,7 +374,8 @@
%a:ptr<function, vec3<f32>, read_write> = var
%3:vec3<f32> = load %a
%4:vec3<f32> = swizzle %3, zyx
- %b:vec2<f32> = swizzle %4, yy
+ %5:vec2<f32> = swizzle %4, yy
+ %b:vec2<f32> = let %5
ret
}
}
@@ -401,7 +413,8 @@
%4:vec4<f32> = load %3
%5:vec3<f32> = swizzle %4, zyx
%6:vec2<f32> = swizzle %5, yx
- %b:f32 = access %6, 0u
+ %7:f32 = access %6, 0u
+ %b:f32 = let %7
ret
}
}
@@ -422,7 +435,8 @@
R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
%a:vec3<u32> = let vec3<u32>(0u)
- %b:u32 = access %a, 2u
+ %3:u32 = access %a, 2u
+ %b:u32 = let %3
ret
}
}
@@ -444,7 +458,8 @@
R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
%a:mat3x4<f32> = let mat3x4<f32>(vec4<f32>(0.0f))
- %b:f32 = access %a, 2u, 3u
+ %3:f32 = access %a, 2u, 3u
+ %b:f32 = let %3
ret
}
}
@@ -474,7 +489,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
%a:MyStruct = let MyStruct(0i)
- %b:i32 = access %a, 0u
+ %3:i32 = access %a, 0u
+ %b:i32 = let %3
ret
}
}
@@ -514,7 +530,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
%a:Outer = let Outer(0i, Inner(0.0f))
- %b:f32 = access %a, 1u, 0u
+ %3:f32 = access %a, 1u, 0u
+ %b:f32 = let %3
ret
}
}
@@ -560,7 +577,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
%a:array<Outer, 4> = let array<Outer, 4>(Outer(0i, array<Inner, 4>(Inner(0i, 0.0f, vec4<f32>(0.0f)))))
- %b:vec4<f32> = access %a, 0u, 1u, 1u, 2u
+ %3:vec4<f32> = access %a, 0u, 1u, 1u, 2u
+ %b:vec4<f32> = let %3
ret
}
}
@@ -582,7 +600,8 @@
R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
%a:vec2<f32> = let vec2<f32>(0.0f)
- %b:f32 = access %a, 1u
+ %3:f32 = access %a, 1u
+ %b:f32 = let %3
ret
}
}
@@ -604,7 +623,8 @@
R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
%a:vec3<f32> = let vec3<f32>(0.0f)
- %b:vec4<f32> = swizzle %a, zyxz
+ %3:vec4<f32> = swizzle %a, zyxz
+ %b:vec4<f32> = let %3
ret
}
}
@@ -627,7 +647,8 @@
%b1 = block {
%a:vec3<f32> = let vec3<f32>(0.0f)
%3:vec3<f32> = swizzle %a, zyx
- %b:vec2<f32> = swizzle %3, yy
+ %4:vec2<f32> = swizzle %3, yy
+ %b:vec2<f32> = let %4
ret
}
}
@@ -664,7 +685,8 @@
%3:vec4<f32> = access %a, 1u
%4:vec3<f32> = swizzle %3, zyx
%5:vec2<f32> = swizzle %4, yx
- %b:f32 = access %5, 0u
+ %6:f32 = access %5, 0u
+ %b:f32 = let %6
ret
}
}
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/binary_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/binary_test.cc
index 31d31ef..11df6fa 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/binary_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/binary_test.cc
@@ -54,7 +54,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:u32 = add %3, 4u
+ %4:u32 = add %3, 4u
+ %tint_symbol:u32 = let %4
ret
}
}
@@ -123,7 +124,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:u32 = sub %3, 4u
+ %4:u32 = sub %3, 4u
+ %tint_symbol:u32 = let %4
ret
}
}
@@ -192,7 +194,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:u32 = mul %3, 4u
+ %4:u32 = mul %3, 4u
+ %tint_symbol:u32 = let %4
ret
}
}
@@ -238,7 +241,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:u32 = div %3, 4u
+ %4:u32 = div %3, 4u
+ %tint_symbol:u32 = let %4
ret
}
}
@@ -284,7 +288,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:u32 = mod %3, 4u
+ %4:u32 = mod %3, 4u
+ %tint_symbol:u32 = let %4
ret
}
}
@@ -330,7 +335,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:u32 = and %3, 4u
+ %4:u32 = and %3, 4u
+ %tint_symbol:u32 = let %4
ret
}
}
@@ -376,7 +382,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:u32 = or %3, 4u
+ %4:u32 = or %3, 4u
+ %tint_symbol:u32 = let %4
ret
}
}
@@ -422,7 +429,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:u32 = xor %3, 4u
+ %4:u32 = xor %3, 4u
+ %tint_symbol:u32 = let %4
ret
}
}
@@ -469,7 +477,7 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:bool = call %my_func
- %logical_and:bool = if %3 [t: %b3, f: %b4] { # if_1
+ %4:bool = if %3 [t: %b3, f: %b4] { # if_1
%b3 = block { # true
exit_if false # if_1
}
@@ -477,6 +485,7 @@
exit_if false # if_1
}
}
+ %logical_and:bool = let %4
if %logical_and [t: %b5] { # if_2
%b5 = block { # true
exit_if # if_2
@@ -505,7 +514,7 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:bool = call %my_func
- %logical_or:bool = if %3 [t: %b3, f: %b4] { # if_1
+ %4:bool = if %3 [t: %b3, f: %b4] { # if_1
%b3 = block { # true
exit_if true # if_1
}
@@ -513,6 +522,7 @@
exit_if true # if_1
}
}
+ %logical_or:bool = let %4
if %logical_or [t: %b5] { # if_2
%b5 = block { # true
exit_if # if_2
@@ -540,7 +550,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:bool = eq %3, 4u
+ %4:bool = eq %3, 4u
+ %tint_symbol:bool = let %4
ret
}
}
@@ -563,7 +574,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:bool = neq %3, 4u
+ %4:bool = neq %3, 4u
+ %tint_symbol:bool = let %4
ret
}
}
@@ -586,7 +598,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:bool = lt %3, 4u
+ %4:bool = lt %3, 4u
+ %tint_symbol:bool = let %4
ret
}
}
@@ -609,7 +622,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:bool = gt %3, 4u
+ %4:bool = gt %3, 4u
+ %tint_symbol:bool = let %4
ret
}
}
@@ -632,7 +646,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:bool = lte %3, 4u
+ %4:bool = lte %3, 4u
+ %tint_symbol:bool = let %4
ret
}
}
@@ -655,7 +670,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:bool = gte %3, 4u
+ %4:bool = gte %3, 4u
+ %tint_symbol:bool = let %4
ret
}
}
@@ -678,7 +694,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:u32 = shiftl %3, 4u
+ %4:u32 = shiftl %3, 4u
+ %tint_symbol:u32 = let %4
ret
}
}
@@ -724,7 +741,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:u32 = shiftr %3, 4u
+ %4:u32 = shiftr %3, 4u
+ %tint_symbol:u32 = let %4
ret
}
}
@@ -773,7 +791,7 @@
%b2 = block {
%3:f32 = call %my_func
%4:bool = lt %3, 2.0f
- %tint_symbol:bool = if %4 [t: %b3, f: %b4] { # if_1
+ %5:bool = if %4 [t: %b3, f: %b4] { # if_1
%b3 = block { # true
%6:f32 = call %my_func
%7:f32 = call %my_func
@@ -786,6 +804,7 @@
exit_if false # if_1
}
}
+ %tint_symbol:bool = let %5
ret
}
}
@@ -808,7 +827,8 @@
}
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
- %tint_symbol:bool = call %my_func, false
+ %4:bool = call %my_func, false
+ %tint_symbol:bool = let %4
ret
}
}
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/builtin_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/builtin_test.cc
index fd6f77e..b92e960 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/builtin_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/builtin_test.cc
@@ -53,7 +53,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:f32 = load %i
- %tint_symbol:f32 = asin %3
+ %4:f32 = asin %3
+ %tint_symbol:f32 = let %4
ret
}
}
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/call_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/call_test.cc
index 4c1dbfc..52cd00c 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/call_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/call_test.cc
@@ -56,7 +56,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:f32 = call %my_func
- %tint_symbol:f32 = bitcast %3
+ %4:f32 = bitcast %3
+ %tint_symbol:f32 = let %4
ret
}
}
@@ -119,7 +120,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:i32 = load %i
- %tint_symbol:f32 = convert %3
+ %4:f32 = convert %3
+ %tint_symbol:f32 = let %4
ret
}
}
@@ -155,7 +157,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:f32 = load %i
- %tint_symbol:vec3<f32> = construct 2.0f, 3.0f, %3
+ %4:vec3<f32> = construct 2.0f, 3.0f, %3
+ %tint_symbol:vec3<f32> = let %4
ret
}
}
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
index e2c1c43..4644964 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
@@ -205,11 +205,11 @@
diagnostics_.add_error(tint::diag::System::IR, err, s);
}
- bool NeedTerminator() { return current_block_ && !current_block_->HasTerminator(); }
+ bool NeedTerminator() { return current_block_ && !current_block_->Terminator(); }
void SetTerminator(core::ir::Terminator* terminator) {
TINT_ASSERT(current_block_);
- TINT_ASSERT(!current_block_->HasTerminator());
+ TINT_ASSERT(!current_block_->Terminator());
current_block_->Append(terminator);
current_block_ = nullptr;
@@ -574,13 +574,13 @@
auto b = builder_.Append(current_block_);
if (auto* v = std::get_if<core::ir::Value*>(&lhs)) {
auto* load = b.Load(*v);
- auto* ty = load->Result()->Type();
- auto* inst = current_block_->Append(BinaryOp(ty, load->Result(), rhs, op));
+ auto* ty = load->Result(0)->Type();
+ auto* inst = current_block_->Append(BinaryOp(ty, load->Result(0), rhs, op));
b.Store(*v, inst);
} else if (auto ref = std::get_if<VectorRefElementAccess>(&lhs)) {
auto* load = b.LoadVectorElement(ref->vector, ref->index);
- auto* ty = load->Result()->Type();
- auto* inst = b.Append(BinaryOp(ty, load->Result(), rhs, op));
+ auto* ty = load->Result(0)->Type();
+ auto* inst = b.Append(BinaryOp(ty, load->Result(0), rhs, op));
b.StoreVectorElement(ref->vector, ref->index, inst);
}
}
@@ -771,12 +771,12 @@
const auto* sem = program_.Sem().Get(stmt);
for (const auto* c : sem->Cases()) {
- Vector<core::ir::Switch::CaseSelector, 4> selectors;
+ Vector<core::ir::Constant*, 4> selectors;
for (const auto* selector : c->Selectors()) {
if (selector->IsDefault()) {
- selectors.Push({nullptr});
+ selectors.Push(nullptr);
} else {
- selectors.Push({builder_.Constant(selector->Value()->Clone(clone_ctx_))});
+ selectors.Push(builder_.Constant(selector->Value()->Clone(clone_ctx_)));
}
}
@@ -878,7 +878,7 @@
if (impl.program_.Sem().Get<sem::Load>(expr)) {
auto* load = impl.builder_.Load(value);
impl.current_block_->Append(load);
- value = load->Result();
+ value = load->Result(0);
}
bindings_.Add(expr, value);
}
@@ -888,7 +888,7 @@
if (impl.program_.Sem().Get<sem::Load>(expr)) {
auto* load = impl.builder_.LoadVectorElement(access.vector, access.index);
impl.current_block_->Append(load);
- bindings_.Add(expr, load->Result());
+ bindings_.Add(expr, load->Result(0));
} else {
bindings_.Add(expr, access);
}
@@ -978,7 +978,7 @@
}
auto* val = impl.builder_.Swizzle(ty, obj, std::move(indices));
impl.current_block_->Append(val);
- Bind(expr, val->Result());
+ Bind(expr, val->Result(0));
return nullptr;
}, //
TINT_ICE_ON_NO_MATCH);
@@ -991,16 +991,16 @@
// of another access, then we can just append the index to that access.
if (!impl.mod.NameOf(obj).IsValid()) {
if (auto* inst_res = obj->As<core::ir::InstructionResult>()) {
- if (auto* access = inst_res->Source()->As<core::ir::Access>()) {
+ if (auto* access = inst_res->Instruction()->As<core::ir::Access>()) {
access->AddIndex(index);
- access->Result()->SetType(ty);
+ access->Result(0)->SetType(ty);
bindings_.Remove(expr->object);
// Move the access after the index expression.
if (impl.current_block_->Back() != access) {
impl.current_block_->Remove(access);
impl.current_block_->Append(access);
}
- Bind(expr, access->Result());
+ Bind(expr, access->Result(0));
return;
}
}
@@ -1009,7 +1009,7 @@
// Create a new access
auto* access = impl.builder_.Access(ty, obj, index);
impl.current_block_->Append(access);
- Bind(expr, access->Result());
+ Bind(expr, access->Result(0));
}
void EmitBinary(const ast::BinaryExpression* b) {
@@ -1028,7 +1028,7 @@
return;
}
impl.current_block_->Append(inst);
- Bind(b, inst->Result());
+ Bind(b, inst->Result(0));
}
void EmitUnary(const ast::UnaryOpExpression* expr) {
@@ -1057,7 +1057,7 @@
break;
}
impl.current_block_->Append(inst);
- Bind(expr, inst->Result());
+ Bind(expr, inst->Result(0));
}
void EmitBitcast(const ast::BitcastExpression* b) {
@@ -1069,7 +1069,7 @@
auto* ty = sem->Type()->Clone(impl.clone_ctx_.type_ctx);
auto* inst = impl.builder_.Bitcast(ty, val);
impl.current_block_->Append(inst);
- Bind(b, inst->Result());
+ Bind(b, inst->Result(0));
}
void EmitCall(const ast::CallExpression* expr) {
@@ -1128,7 +1128,7 @@
return;
}
impl.current_block_->Append(inst);
- Bind(expr, inst->Result());
+ Bind(expr, inst->Result(0));
}
void EmitIdentifier(const ast::IdentifierExpression* i) {
@@ -1225,7 +1225,7 @@
void EndShortCircuit(const ast::BinaryExpression* b) {
auto res = GetValue(b);
- auto* src = res->As<core::ir::InstructionResult>()->Source();
+ auto* src = res->As<core::ir::InstructionResult>()->Instruction();
auto* if_ = src->As<core::ir::If>();
TINT_ASSERT_OR_RETURN(if_);
auto rhs = GetValue(b->rhs);
@@ -1328,34 +1328,21 @@
}
// Store the declaration so we can get the instruction to store too
- scopes_.Set(v->name->symbol, val->Result());
+ scopes_.Set(v->name->symbol, val->Result(0));
// Record the original name of the var
builder_.ir.SetName(val, v->name->symbol.Name());
},
[&](const ast::Let* l) {
- auto* last_stmt = current_block_->Back();
auto init = EmitValueExpression(l->initializer);
if (!init) {
return;
}
- auto* value = init;
- if (current_block_->Back() == last_stmt) {
- // Emitting the let's initializer didn't create an instruction.
- // Create an core::ir::Let to give the let an instruction. This gives the let a
- // place of declaration and name, which preserves runtime semantics of the
- // let, and can be used by consumers of the IR to produce a variable or
- // debug info.
- auto* let = current_block_->Append(builder_.Let(l->name->symbol.Name(), value));
- value = let->Result();
- } else {
- // Record the original name of the let
- builder_.ir.SetName(value, l->name->symbol.Name());
- }
+ auto* let = current_block_->Append(builder_.Let(l->name->symbol.Name(), init));
// Store the results of the initialization
- scopes_.Set(l->name->symbol, value);
+ scopes_.Set(l->name->symbol, let->Result(0));
},
[&](const ast::Override*) {
add_error(var->source,
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
index f704fa5..bd204c0 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
@@ -77,7 +77,7 @@
ASSERT_EQ(1u, m->functions.Length());
- auto* f = m->functions[0];
+ core::ir::Function* f = m->functions[0];
ASSERT_NE(f->Block(), nullptr);
EXPECT_EQ(m->functions[0]->Stage(), core::ir::Function::PipelineStage::kUndefined);
@@ -98,7 +98,7 @@
ASSERT_EQ(1u, m->functions.Length());
- auto* f = m->functions[0];
+ core::ir::Function* f = m->functions[0];
ASSERT_NE(f->Block(), nullptr);
EXPECT_EQ(m->functions[0]->Stage(), core::ir::Function::PipelineStage::kUndefined);
@@ -120,7 +120,7 @@
ASSERT_EQ(1u, m->functions.Length());
- auto* f = m->functions[0];
+ core::ir::Function* f = m->functions[0];
ASSERT_NE(f->Block(), nullptr);
EXPECT_EQ(m->functions[0]->Stage(), core::ir::Function::PipelineStage::kUndefined);
@@ -850,7 +850,7 @@
ASSERT_EQ(1u, m.functions.Length());
- auto cases = swtch->Cases();
+ auto& cases = swtch->Cases();
ASSERT_EQ(3u, cases.Length());
ASSERT_EQ(1u, cases[0].selectors.Length());
@@ -901,7 +901,7 @@
ASSERT_EQ(1u, m.functions.Length());
- auto cases = swtch->Cases();
+ auto& cases = swtch->Cases();
ASSERT_EQ(1u, cases.Length());
ASSERT_EQ(3u, cases[0].selectors.Length());
ASSERT_TRUE(cases[0].selectors[0].val->Value()->Is<core::constant::Scalar<i32>>());
@@ -940,7 +940,7 @@
ASSERT_EQ(1u, m.functions.Length());
- auto cases = swtch->Cases();
+ auto& cases = swtch->Cases();
ASSERT_EQ(1u, cases.Length());
ASSERT_EQ(1u, cases[0].selectors.Length());
EXPECT_TRUE(cases[0].selectors[0].IsDefault());
@@ -973,7 +973,7 @@
ASSERT_EQ(1u, m.functions.Length());
- auto cases = swtch->Cases();
+ auto& cases = swtch->Cases();
ASSERT_EQ(2u, cases.Length());
ASSERT_EQ(1u, cases[0].selectors.Length());
ASSERT_TRUE(cases[0].selectors[0].val->Value()->Is<core::constant::Scalar<i32>>());
@@ -1017,7 +1017,7 @@
ASSERT_EQ(1u, m.functions.Length());
- auto cases = swtch->Cases();
+ auto& cases = swtch->Cases();
ASSERT_EQ(2u, cases.Length());
ASSERT_EQ(1u, cases[0].selectors.Length());
ASSERT_TRUE(cases[0].selectors[0].val->Value()->Is<core::constant::Scalar<i32>>());
@@ -1151,7 +1151,7 @@
ASSERT_EQ(1u, m->functions.Length());
- auto* f = m->functions[0];
+ core::ir::Function* f = m->functions[0];
ASSERT_NE(f->Block(), nullptr);
EXPECT_EQ(m->functions[0]->Stage(), core::ir::Function::PipelineStage::kUndefined);
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/shadowing_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/shadowing_test.cc
index 1536188..09af944 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/shadowing_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/shadowing_test.cc
@@ -59,8 +59,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-S = struct @align(4) {
+ EXPECT_EQ(Disassemble(m.Get()), R"(S = struct @align(4) {
i:i32 @offset(0)
}
@@ -88,8 +87,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-S = struct @align(4) {
+ EXPECT_EQ(Disassemble(m.Get()), R"(S = struct @align(4) {
i:i32 @offset(0)
}
@@ -115,8 +113,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%b1 = block { # root
+ EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block { # root
%i:ptr<private, i32, read_write> = var, 1i
}
@@ -148,8 +145,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%b1 = block { # root
+ EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block { # root
%i:ptr<private, i32, read_write> = var, 1i
}
@@ -159,7 +155,8 @@
%4:i32 = add %3, 1i
store %i, %4
%5:i32 = load %i
- %i_1:i32 = add %5, 1i # %i_1: 'i'
+ %6:i32 = add %5, 1i
+ %i_1:i32 = let %6 # %i_1: 'i'
ret %i_1
}
}
@@ -181,8 +178,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
if true [t: %b2] { # if_1
@@ -221,8 +217,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
if true [t: %b2] { # if_1
@@ -231,12 +226,13 @@
%4:i32 = add %3, 1i
store %i, %4
%5:i32 = load %i
- %i_1:i32 = add %5, 1i # %i_1: 'i'
+ %6:i32 = add %5, 1i
+ %i_1:i32 = let %6 # %i_1: 'i'
ret %i_1
}
}
- %7:i32 = load %i
- ret %7
+ %8:i32 = load %i
+ ret %8
}
}
)");
@@ -256,8 +252,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
loop [b: %b2, c: %b3] { # loop_1
@@ -303,8 +298,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
loop [b: %b2, c: %b3] { # loop_1
@@ -320,15 +314,16 @@
}
}
%5:i32 = load %i
- %i_1:i32 = add %5, 1i # %i_1: 'i'
+ %6:i32 = add %5, 1i
+ %i_1:i32 = let %6 # %i_1: 'i'
ret %i_1
}
%b3 = block { # continuing
next_iteration %b2
}
}
- %7:i32 = load %i
- ret %7
+ %8:i32 = load %i
+ ret %8
}
}
)");
@@ -347,8 +342,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
loop [i: %b2, b: %b3] { # loop_1
@@ -367,12 +361,13 @@
exit_loop # loop_1
}
}
- %j:f32 = load %i_1
+ %6:f32 = load %i_1
+ %j:f32 = let %6
continue %b6
}
}
- %7:i32 = load %i
- ret %7
+ %8:i32 = load %i
+ ret %8
}
}
)");
@@ -391,8 +386,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
loop [i: %b2, b: %b3] { # loop_1
@@ -435,8 +429,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
loop [i: %b2, b: %b3] { # loop_1
@@ -483,8 +476,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
loop [i: %b2, b: %b3] { # loop_1
@@ -504,12 +496,13 @@
}
}
%6:i32 = load %i
- %i_1:i32 = add %6, 1i # %i_1: 'i'
+ %7:i32 = add %6, 1i
+ %i_1:i32 = let %7 # %i_1: 'i'
ret %i_1
}
}
- %8:i32 = load %i
- ret %8
+ %9:i32 = load %i
+ ret %9
}
}
)");
@@ -534,8 +527,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
loop [b: %b2, c: %b3] { # loop_1
@@ -589,8 +581,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
loop [b: %b2, c: %b3] { # loop_1
@@ -603,9 +594,10 @@
}
}
%5:i32 = load %i
- %i_1:i32 = add %5, 1i # %i_1: 'i'
- %7:bool = eq %i_1, 3i
- if %7 [t: %b5] { # if_2
+ %6:i32 = add %5, 1i
+ %i_1:i32 = let %6 # %i_1: 'i'
+ %8:bool = eq %i_1, 3i
+ if %8 [t: %b5] { # if_2
%b5 = block { # true
exit_loop # loop_1
}
@@ -616,8 +608,8 @@
next_iteration %b2
}
}
- %8:i32 = load %i
- ret %8
+ %9:i32 = load %i
+ ret %9
}
}
)");
@@ -643,8 +635,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
loop [b: %b2, c: %b3] { # loop_1
@@ -694,8 +685,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
loop [b: %b2, c: %b3] { # loop_1
@@ -711,13 +701,14 @@
}
%b3 = block { # continuing
%5:i32 = load %i
- %i_1:i32 = add %5, 1i # %i_1: 'i'
- %7:bool = gt %i_1, 2i
- break_if %7 %b2
+ %6:i32 = add %5, 1i
+ %i_1:i32 = let %6 # %i_1: 'i'
+ %8:bool = gt %i_1, 2i
+ break_if %8 %b2
}
}
- %8:i32 = load %i
- ret %8
+ %9:i32 = load %i
+ ret %9
}
}
)");
@@ -744,8 +735,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
%3:i32 = load %i
@@ -793,8 +783,7 @@
ASSERT_TRUE(m) << m;
- EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
-%f = func():i32 -> %b1 {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%f = func():i32 -> %b1 {
%b1 = block {
%i:ptr<function, i32, read_write> = var
%3:i32 = load %i
@@ -805,12 +794,13 @@
}
%b3 = block { # case
%5:i32 = load %i
- %i_1:i32 = add %5, 1i # %i_1: 'i'
+ %6:i32 = add %5, 1i
+ %i_1:i32 = let %6 # %i_1: 'i'
ret %i_1
}
%b4 = block { # case
- %7:i32 = load %i
- ret %7
+ %8:i32 = load %i
+ ret %8
}
}
unreachable
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/unary_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/unary_test.cc
index 0db5a17..98ff492 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/unary_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/unary_test.cc
@@ -54,7 +54,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:bool = call %my_func
- %tint_symbol:bool = eq %3, false
+ %4:bool = eq %3, false
+ %tint_symbol:bool = let %4
ret
}
}
@@ -77,7 +78,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:vec4<bool> = call %my_func
- %tint_symbol:vec4<bool> = eq %3, vec4<bool>(false)
+ %4:vec4<bool> = eq %3, vec4<bool>(false)
+ %tint_symbol:vec4<bool> = let %4
ret
}
}
@@ -100,7 +102,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:u32 = call %my_func
- %tint_symbol:u32 = complement %3
+ %4:u32 = complement %3
+ %tint_symbol:u32 = let %4
ret
}
}
@@ -123,7 +126,8 @@
%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
%b2 = block {
%3:i32 = call %my_func
- %tint_symbol:i32 = negation %3
+ %4:i32 = negation %3
+ %tint_symbol:i32 = let %4
ret
}
}
diff --git a/src/tint/lang/wgsl/reader/reader.cc b/src/tint/lang/wgsl/reader/reader.cc
index df1dc7b..f74d837 100644
--- a/src/tint/lang/wgsl/reader/reader.cc
+++ b/src/tint/lang/wgsl/reader/reader.cc
@@ -55,4 +55,19 @@
return module;
}
+tint::Result<core::ir::Module> ProgramToLoweredIR(const Program& program) {
+ auto ir = tint::wgsl::reader::ProgramToIR(program);
+ if (!ir) {
+ return ir.Failure();
+ }
+
+ // Lower from WGSL-dialect to core-dialect
+ auto res = tint::wgsl::reader::Lower(ir.Get());
+ if (!res) {
+ return res.Failure();
+ }
+
+ return ir;
+}
+
} // namespace tint::wgsl::reader
diff --git a/src/tint/lang/wgsl/reader/reader.h b/src/tint/lang/wgsl/reader/reader.h
index 40c973a..8594250 100644
--- a/src/tint/lang/wgsl/reader/reader.h
+++ b/src/tint/lang/wgsl/reader/reader.h
@@ -49,6 +49,15 @@
/// @returns the resulting IR module, or failure
Result<core::ir::Module> WgslToIR(const Source::File* file, const Options& options = {});
+/// Builds a core-dialect core::ir::Module from the given Program
+/// @param program the Program to use.
+/// @returns the core-dialect IR module.
+///
+/// @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.
+tint::Result<core::ir::Module> ProgramToLoweredIR(const Program& program);
+
} // namespace tint::wgsl::reader
#endif // SRC_TINT_LANG_WGSL_READER_READER_H_
diff --git a/src/tint/lang/wgsl/resolver/BUILD.bazel b/src/tint/lang/wgsl/resolver/BUILD.bazel
index 4187995..51904b9 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.bazel
+++ b/src/tint/lang/wgsl/resolver/BUILD.bazel
@@ -67,6 +67,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/intrinsic",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
@@ -168,6 +169,7 @@
"//src/tint/lang/wgsl/ast/transform",
"//src/tint/lang/wgsl/ast:test",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/intrinsic",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
diff --git a/src/tint/lang/wgsl/resolver/BUILD.cmake b/src/tint/lang/wgsl/resolver/BUILD.cmake
index 745d508..6cb53ed 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.cmake
+++ b/src/tint/lang/wgsl/resolver/BUILD.cmake
@@ -66,6 +66,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_intrinsic
tint_lang_wgsl_program
tint_lang_wgsl_sem
@@ -162,6 +163,7 @@
tint_lang_wgsl_ast_transform
tint_lang_wgsl_ast_test
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_intrinsic
tint_lang_wgsl_program
tint_lang_wgsl_resolver
diff --git a/src/tint/lang/wgsl/resolver/BUILD.gn b/src/tint/lang/wgsl/resolver/BUILD.gn
index f5e4097..18cab8b 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.gn
+++ b/src/tint/lang/wgsl/resolver/BUILD.gn
@@ -70,6 +70,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/intrinsic",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
@@ -164,6 +165,7 @@
"${tint_src_dir}/lang/wgsl/ast:unittests",
"${tint_src_dir}/lang/wgsl/ast/transform",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/intrinsic",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
diff --git a/src/tint/lang/wgsl/resolver/resolver.cc b/src/tint/lang/wgsl/resolver/resolver.cc
index aa54ccf..6e60fa8 100644
--- a/src/tint/lang/wgsl/resolver/resolver.cc
+++ b/src/tint/lang/wgsl/resolver/resolver.cc
@@ -4017,7 +4017,8 @@
for (auto feature : req->features) {
if (!allowed_features_.features.count(feature)) {
StringStream ss;
- ss << "language feature '" << feature << "' is not allowed in the current environment";
+ ss << "language feature '" << wgsl::ToString(feature)
+ << "' is not allowed in the current environment";
AddError(ss.str(), req->source);
return false;
}
diff --git a/src/tint/lang/wgsl/resolver/uniformity_test.cc b/src/tint/lang/wgsl/resolver/uniformity_test.cc
index 671d6f2..769ab82 100644
--- a/src/tint/lang/wgsl/resolver/uniformity_test.cc
+++ b/src/tint/lang/wgsl/resolver/uniformity_test.cc
@@ -305,8 +305,6 @@
auto condition = static_cast<Condition>(std::get<0>(GetParam()));
auto function = static_cast<Function>(std::get<1>(GetParam()));
std::string src = R"(
-enable chromium_experimental_read_write_storage_texture;
-
var<private> p : i32;
var<workgroup> w : i32;
@group(0) @binding(0) var<uniform> u : i32;
@@ -8247,8 +8245,6 @@
TEST_F(UniformityAnalysisTest, StorageTextureLoad_ReadOnly) {
std::string src = R"(
-enable chromium_experimental_read_write_storage_texture;
-
@group(0) @binding(0) var t : texture_storage_2d<r32sint, read>;
fn foo() {
@@ -8263,8 +8259,6 @@
TEST_F(UniformityAnalysisTest, StorageTextureLoad_ReadWrite) {
std::string src = R"(
-enable chromium_experimental_read_write_storage_texture;
-
@group(0) @binding(0) var t : texture_storage_2d<r32sint, read_write>;
fn foo() {
@@ -8276,15 +8270,15 @@
RunTest(src, false);
EXPECT_EQ(error_,
- R"(test:8:5 error: 'storageBarrier' must only be called from uniform control flow
+ R"(test:6:5 error: 'storageBarrier' must only be called from uniform control flow
storageBarrier();
^^^^^^^^^^^^^^
-test:7:3 note: control flow depends on possibly non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
if (textureLoad(t, vec2()).r == 0) {
^^
-test:7:7 note: return value of 'textureLoad' may be non-uniform
+test:5:7 note: return value of 'textureLoad' may be non-uniform
if (textureLoad(t, vec2()).r == 0) {
^^^^^^^^^^^^^^^^^^^^^^
)");
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index 05b2a44..106d739 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -1850,7 +1850,7 @@
if (feature != wgsl::LanguageFeature::kUndefined) {
if (!allowed_features_.features.count(feature)) {
AddError("built-in function '" + std::string(builtin->str()) + "' requires the " +
- tint::ToString(feature) +
+ std::string(wgsl::ToString(feature)) +
" language feature, which is not allowed in the current environment",
call->Declaration()->source);
return false;
diff --git a/src/tint/lang/wgsl/sem/BUILD.bazel b/src/tint/lang/wgsl/sem/BUILD.bazel
index 22b1c0e..b8fc112 100644
--- a/src/tint/lang/wgsl/sem/BUILD.bazel
+++ b/src/tint/lang/wgsl/sem/BUILD.bazel
@@ -116,6 +116,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
"//src/tint/utils/ice",
@@ -151,6 +152,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/sem/BUILD.cmake b/src/tint/lang/wgsl/sem/BUILD.cmake
index 119cde7..732d1e9 100644
--- a/src/tint/lang/wgsl/sem/BUILD.cmake
+++ b/src/tint/lang/wgsl/sem/BUILD.cmake
@@ -115,6 +115,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_utils_containers
tint_utils_diagnostic
tint_utils_ice
@@ -150,6 +151,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
diff --git a/src/tint/lang/wgsl/sem/BUILD.gn b/src/tint/lang/wgsl/sem/BUILD.gn
index 6d7dfe9..0f29ddc 100644
--- a/src/tint/lang/wgsl/sem/BUILD.gn
+++ b/src/tint/lang/wgsl/sem/BUILD.gn
@@ -119,6 +119,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
"${tint_src_dir}/utils/ice",
@@ -152,6 +153,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/sem/builtin_fn.h b/src/tint/lang/wgsl/sem/builtin_fn.h
index 44e3138..83d62bf 100644
--- a/src/tint/lang/wgsl/sem/builtin_fn.h
+++ b/src/tint/lang/wgsl/sem/builtin_fn.h
@@ -33,7 +33,7 @@
#include "src/tint/lang/wgsl/builtin_fn.h"
#include "src/tint/lang/wgsl/extension.h"
-#include "src/tint/lang/wgsl/language_feature.h"
+#include "src/tint/lang/wgsl/features/language_feature.h"
#include "src/tint/lang/wgsl/sem/call_target.h"
#include "src/tint/lang/wgsl/sem/pipeline_stage_set.h"
#include "src/tint/utils/math/hash.h"
diff --git a/src/tint/lang/wgsl/wgsl.def b/src/tint/lang/wgsl/wgsl.def
index 8c545c9..23ba104 100644
--- a/src/tint/lang/wgsl/wgsl.def
+++ b/src/tint/lang/wgsl/wgsl.def
@@ -78,8 +78,6 @@
// A Chromium-specific extension that enables passing of uniform, storage and workgroup
// address-spaced pointers as parameters, as well as pointers into sub-objects.
chromium_experimental_full_ptr_parameters
- // A Chromium-specific extension that adds support for read-write storage textures.
- chromium_experimental_read_write_storage_texture
// A Chromium-specific extension that adds basic subgroup functionality.
chromium_experimental_subgroups
// A Chromium-specific extension that relaxes memory layout requirements for uniform storage.
diff --git a/src/tint/lang/wgsl/writer/ast_printer/BUILD.bazel b/src/tint/lang/wgsl/writer/ast_printer/BUILD.bazel
index bd87e10..fa89968 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/BUILD.bazel
+++ b/src/tint/lang/wgsl/writer/ast_printer/BUILD.bazel
@@ -50,6 +50,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
@@ -115,6 +116,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/resolver",
"//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/writer/ast_printer/BUILD.cmake b/src/tint/lang/wgsl/writer/ast_printer/BUILD.cmake
index 94c711f..11af11b 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/ast_printer/BUILD.cmake
@@ -51,6 +51,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
@@ -119,6 +120,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_resolver
tint_lang_wgsl_sem
@@ -166,6 +168,7 @@
tint_lang_wgsl_ast
tint_lang_wgsl_program
tint_lang_wgsl_sem
+ tint_utils_bytes
tint_utils_containers
tint_utils_diagnostic
tint_utils_generator
@@ -174,6 +177,7 @@
tint_utils_macros
tint_utils_math
tint_utils_memory
+ tint_utils_reflection
tint_utils_result
tint_utils_rtti
tint_utils_symbol
diff --git a/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn b/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn
index 88734f2..dd5524f 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn
@@ -53,6 +53,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
@@ -118,6 +119,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/resolver",
"${tint_src_dir}/lang/wgsl/sem",
@@ -154,6 +156,7 @@
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
+ "${tint_src_dir}/utils/bytes",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
"${tint_src_dir}/utils/generator",
@@ -162,6 +165,7 @@
"${tint_src_dir}/utils/macros",
"${tint_src_dir}/utils/math",
"${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
"${tint_src_dir}/utils/result",
"${tint_src_dir}/utils/rtti",
"${tint_src_dir}/utils/symbol",
diff --git a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
index 12688b4..2f51a4c 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
@@ -27,7 +27,7 @@
#include "src/tint/lang/wgsl/writer/ast_printer/ast_printer.h"
-#include <algorithm>
+#include <string>
#include "src/tint/lang/core/texel_format.h"
#include "src/tint/lang/wgsl/ast/accessor_expression.h"
@@ -161,7 +161,7 @@
if (!first) {
out << ", ";
}
- out << feature;
+ out << wgsl::ToString(feature);
first = false;
}
out << ";";
@@ -263,9 +263,9 @@
// and Inf are not allowed to be spelled in literal, it should be fine to emit f16
// literals in this way.
if (l->suffix == ast::FloatLiteralExpression::Suffix::kNone) {
- out << tint::writer::DoubleToBitPreservingString(l->value);
+ out << tint::strconv::DoubleToBitPreservingString(l->value);
} else {
- out << tint::writer::FloatToBitPreservingString(static_cast<float>(l->value))
+ out << tint::strconv::FloatToBitPreservingString(static_cast<float>(l->value))
<< l->suffix;
}
},
diff --git a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.h b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.h
index 71bb09a..4fa1655 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.h
+++ b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.h
@@ -28,10 +28,7 @@
#ifndef SRC_TINT_LANG_WGSL_WRITER_AST_PRINTER_AST_PRINTER_H_
#define SRC_TINT_LANG_WGSL_WRITER_AST_PRINTER_AST_PRINTER_H_
-#include <string>
-
#include "src/tint/lang/core/binary_op.h"
-#include "src/tint/lang/wgsl/sem/struct.h"
#include "src/tint/utils/generator/text_generator.h"
#include "src/tint/utils/text/string_stream.h"
diff --git a/src/tint/lang/wgsl/writer/ast_printer/ast_printer_fuzz.cc b/src/tint/lang/wgsl/writer/ast_printer/ast_printer_fuzz.cc
index 77022be..230ab20 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/ast_printer_fuzz.cc
+++ b/src/tint/lang/wgsl/writer/ast_printer/ast_printer_fuzz.cc
@@ -29,7 +29,7 @@
#include "src/tint/lang/wgsl/writer/ast_printer/ast_printer.h"
-#include "src/tint/cmd/fuzz/wgsl/wgsl_fuzz.h"
+#include "src/tint/cmd/fuzz/wgsl/fuzz.h"
namespace tint::wgsl::writer {
namespace {
diff --git a/src/tint/lang/wgsl/writer/ast_printer/requires_test.cc b/src/tint/lang/wgsl/writer/ast_printer/requires_test.cc
index 1526fbb..d3a2684 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/requires_test.cc
+++ b/src/tint/lang/wgsl/writer/ast_printer/requires_test.cc
@@ -47,9 +47,9 @@
// TODO(jrprice): Enable this once we have multiple language features.
TEST_F(WgslASTPrinterTest, DISABLED_Emit_Requires_Multiple) {
- auto* req = create<ast::Requires>(
- wgsl::LanguageFeatures({wgsl::LanguageFeature::kReadonlyAndReadwriteStorageTextures,
- wgsl::LanguageFeature::kReadonlyAndReadwriteStorageTextures}));
+ auto* req = create<ast::Requires>(ast::Requires::LanguageFeatures(
+ {wgsl::LanguageFeature::kReadonlyAndReadwriteStorageTextures,
+ wgsl::LanguageFeature::kReadonlyAndReadwriteStorageTextures}));
AST().AddRequires(req);
ASTPrinter& gen = Build();
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel
index 9eae515..812a463 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel
@@ -40,11 +40,9 @@
name = "ir_to_program",
srcs = [
"ir_to_program.cc",
- "rename_conflicts.cc",
],
hdrs = [
"ir_to_program.h",
- "rename_conflicts.h",
],
deps = [
"//src/tint/api/common",
@@ -56,6 +54,7 @@
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/intrinsic",
"//src/tint/lang/wgsl/ir",
"//src/tint/lang/wgsl/program",
@@ -83,7 +82,6 @@
alwayslink = True,
srcs = [
"ir_to_program_test.h",
- "rename_conflicts_test.cc",
] + select({
":tint_build_wgsl_writer": [
"inlining_test.cc",
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake
index d86a7dc..6fd9f71 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake
@@ -41,8 +41,6 @@
tint_add_target(tint_lang_wgsl_writer_ir_to_program lib
lang/wgsl/writer/ir_to_program/ir_to_program.cc
lang/wgsl/writer/ir_to_program/ir_to_program.h
- lang/wgsl/writer/ir_to_program/rename_conflicts.cc
- lang/wgsl/writer/ir_to_program/rename_conflicts.h
)
tint_target_add_dependencies(tint_lang_wgsl_writer_ir_to_program lib
@@ -55,6 +53,7 @@
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
+ tint_lang_wgsl_features
tint_lang_wgsl_intrinsic
tint_lang_wgsl_ir
tint_lang_wgsl_program
@@ -81,7 +80,6 @@
################################################################################
tint_add_target(tint_lang_wgsl_writer_ir_to_program_test test
lang/wgsl/writer/ir_to_program/ir_to_program_test.h
- lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc
)
tint_target_add_dependencies(tint_lang_wgsl_writer_ir_to_program_test test
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
index e2957b0..ed032db 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
@@ -46,8 +46,6 @@
sources = [
"ir_to_program.cc",
"ir_to_program.h",
- "rename_conflicts.cc",
- "rename_conflicts.h",
]
deps = [
"${tint_src_dir}/api/common",
@@ -59,6 +57,7 @@
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/intrinsic",
"${tint_src_dir}/lang/wgsl/ir",
"${tint_src_dir}/lang/wgsl/program",
@@ -81,10 +80,7 @@
}
if (tint_build_unittests) {
tint_unittests_source_set("unittests") {
- sources = [
- "ir_to_program_test.h",
- "rename_conflicts_test.cc",
- ]
+ sources = [ "ir_to_program_test.h" ]
deps = [
"${tint_src_dir}:gmock_and_gtest",
"${tint_src_dir}/api/common",
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/inlining_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/inlining_test.cc
index d08dbbf..e69347d 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/inlining_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/inlining_test.cc
@@ -934,7 +934,7 @@
b.Append(fn->Block(), [&] {
auto* v = b.Add(ty.i32(), 1_i, 2_i);
auto* switch_ = b.Switch(3_i);
- auto* case_ = b.Case(switch_, {core::ir::Switch::CaseSelector{}});
+ auto* case_ = b.DefaultCase(switch_);
b.Append(case_, [&] { b.Return(fn, v); });
b.Return(fn, 0_i);
});
@@ -959,7 +959,7 @@
auto* v_1 = b.Load(var);
auto* v_2 = b.Add(ty.i32(), v_1, 2_i);
auto* switch_ = b.Switch(3_i);
- auto* case_ = b.Case(switch_, {core::ir::Switch::CaseSelector{}});
+ auto* case_ = b.DefaultCase(switch_);
b.Append(case_, [&] { b.Return(fn, v_2); });
b.Return(fn, 0_i);
});
@@ -983,7 +983,7 @@
b.Append(fn->Block(), [&] {
auto* v = b.Add(ty.i32(), 1_i, 2_i);
auto* switch_ = b.Switch(v);
- auto* case_ = b.Case(switch_, {core::ir::Switch::CaseSelector{}});
+ auto* case_ = b.DefaultCase(switch_);
b.Append(case_, [&] { b.Return(fn, 3_i); });
b.Return(fn, 0_i);
});
@@ -1007,7 +1007,7 @@
var->SetInitializer(b.Constant(1_i));
auto* v_1 = b.Load(var);
auto* switch_ = b.Switch(v_1);
- auto* case_ = b.Case(switch_, {core::ir::Switch::CaseSelector{}});
+ auto* case_ = b.DefaultCase(switch_);
b.Append(case_, [&] { b.Return(fn, 3_i); });
b.Return(fn, 0_i);
});
@@ -1032,7 +1032,7 @@
b.Store(var, 1_i);
auto* load = b.Load(var);
auto* switch_ = b.Switch(1_i);
- auto* case_ = b.Case(switch_, {core::ir::Switch::CaseSelector{}});
+ auto* case_ = b.DefaultCase(switch_);
b.Append(case_, [&] {
b.Store(var, 2_i);
b.ExitSwitch(switch_);
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index e3650e6..9f83536 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -79,7 +79,6 @@
#include "src/tint/lang/wgsl/ir/builtin_call.h"
#include "src/tint/lang/wgsl/program/program_builder.h"
#include "src/tint/lang/wgsl/resolver/resolve.h"
-#include "src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h"
#include "src/tint/utils/containers/hashmap.h"
#include "src/tint/utils/containers/predicates.h"
#include "src/tint/utils/containers/reverse.h"
@@ -102,18 +101,9 @@
class State {
public:
- explicit State(core::ir::Module& m) : mod(m) {}
+ explicit State(const core::ir::Module& m) : mod(m) {}
Program Run() {
- // Run transforms need to sanitize for WGSL.
- {
- auto result = RenameConflicts(&mod);
- if (!result) {
- b.Diagnostics().add(result.Failure().reason);
- return Program(std::move(b));
- }
- }
-
if (auto res = core::ir::Validate(mod); !res) {
// IR module failed validation.
b.Diagnostics() = res.Failure().reason;
@@ -123,7 +113,7 @@
RootBlock(mod.root_block);
// TODO(crbug.com/tint/1902): Emit user-declared types
- for (auto* fn : mod.functions) {
+ for (auto& fn : mod.functions) {
Fn(fn);
}
return Program{resolver::Resolve(b)};
@@ -137,7 +127,7 @@
};
/// The source IR module
- core::ir::Module& mod;
+ const core::ir::Module& mod;
/// The target ProgramBuilder
ProgramBuilder b;
@@ -162,10 +152,10 @@
using ValueBinding = std::variant<VariableValue, InlinedValue, ConsumedValue>;
/// IR values to their representation
- Hashmap<core::ir::Value*, ValueBinding, 32> bindings_;
+ Hashmap<const core::ir::Value*, ValueBinding, 32> bindings_;
/// Names for values
- Hashmap<core::ir::Value*, Symbol, 32> names_;
+ Hashmap<const core::ir::Value*, Symbol, 32> names_;
/// The nesting depth of the currently generated AST
/// 0 is module scope
@@ -178,10 +168,10 @@
StatementList* statements_ = nullptr;
/// The current switch case block
- core::ir::Block* current_switch_case_ = nullptr;
+ const core::ir::Block* current_switch_case_ = nullptr;
/// Values that can be inlined.
- Hashset<core::ir::Value*, 64> can_inline_;
+ Hashset<const core::ir::Value*, 64> can_inline_;
/// Set of enable directives emitted.
Hashset<wgsl::Extension, 4> enables_;
@@ -192,20 +182,20 @@
/// True if 'diagnostic(off, derivative_uniformity)' has been emitted
bool disabled_derivative_uniformity_ = false;
- void RootBlock(core::ir::Block* root) {
+ void RootBlock(const core::ir::Block* root) {
for (auto* inst : *root) {
tint::Switch(
- inst, //
- [&](core::ir::Var* var) { Var(var); }, //
+ inst, //
+ [&](const core::ir::Var* var) { Var(var); }, //
TINT_ICE_ON_NO_MATCH);
}
}
- const ast::Function* Fn(core::ir::Function* fn) {
+ const ast::Function* Fn(const core::ir::Function* fn) {
SCOPED_NESTING();
// TODO(crbug.com/tint/1915): Properly implement this when we've fleshed out Function
static constexpr size_t N = decltype(ast::Function::params)::static_length;
- auto params = tint::Transform<N>(fn->Params(), [&](core::ir::FunctionParam* param) {
+ auto params = tint::Transform<N>(fn->Params(), [&](const core::ir::FunctionParam* param) {
auto ty = Type(param->Type());
auto name = NameFor(param);
Bind(param, name, PtrKind::kPtr);
@@ -225,12 +215,12 @@
std::move(ret_attrs));
}
- const ast::BlockStatement* Block(core::ir::Block* block) {
+ const ast::BlockStatement* Block(const core::ir::Block* block) {
// TODO(crbug.com/tint/1902): Handle block arguments.
return b.Block(Statements(block));
}
- StatementList Statements(core::ir::Block* block) {
+ StatementList Statements(const core::ir::Block* block) {
StatementList stmts;
if (block) {
MarkInlinable(block);
@@ -242,10 +232,10 @@
return stmts;
}
- void MarkInlinable(core::ir::Block* block) {
+ void MarkInlinable(const core::ir::Block* block) {
// An ordered list of possibly-inlinable values returned by sequenced instructions that have
// not yet been marked-for or ruled-out-for inlining.
- UniqueVector<core::ir::Value*, 32> pending_resolution;
+ UniqueVector<const core::ir::Value*, 32> pending_resolution;
// Walk the instructions of the block starting with the first.
for (auto* inst : *block) {
@@ -283,10 +273,10 @@
if (inst->Results().Length() == 1) {
// Instruction has a single result value.
// Check to see if the result of this instruction is a candidate for inlining.
- auto* result = inst->Result();
+ auto* result = inst->Result(0);
// Only values with a single usage can be inlined.
// Named values are not inlined, as we want to emit the name for a let.
- if (result->Usages().Count() == 1 && !mod.NameOf(result).IsValid()) {
+ if (result->NumUsages() == 1 && !mod.NameOf(result).IsValid()) {
if (sequenced) {
// The value comes from a sequenced instruction. We need to ensure
// instruction ordering so add it to 'pending_resolution'.
@@ -311,35 +301,35 @@
void Append(const ast::Statement* inst) { statements_->Push(inst); }
- void Instruction(core::ir::Instruction* inst) {
+ void Instruction(const core::ir::Instruction* inst) {
tint::Switch(
- inst, //
- [&](core::ir::Access* i) { Access(i); }, //
- [&](core::ir::Binary* i) { Binary(i); }, //
- [&](core::ir::BreakIf* i) { BreakIf(i); }, //
- [&](core::ir::Call* i) { Call(i); }, //
- [&](core::ir::Continue*) {}, //
- [&](core::ir::ExitIf*) {}, //
- [&](core::ir::ExitLoop* i) { ExitLoop(i); }, //
- [&](core::ir::ExitSwitch* i) { ExitSwitch(i); }, //
- [&](core::ir::If* i) { If(i); }, //
- [&](core::ir::Let* i) { Let(i); }, //
- [&](core::ir::Load* l) { Load(l); }, //
- [&](core::ir::LoadVectorElement* i) { LoadVectorElement(i); }, //
- [&](core::ir::Loop* l) { Loop(l); }, //
- [&](core::ir::NextIteration*) {}, //
- [&](core::ir::Return* i) { Return(i); }, //
- [&](core::ir::Store* i) { Store(i); }, //
- [&](core::ir::StoreVectorElement* i) { StoreVectorElement(i); }, //
- [&](core::ir::Switch* i) { Switch(i); }, //
- [&](core::ir::Swizzle* i) { Swizzle(i); }, //
- [&](core::ir::Unary* i) { Unary(i); }, //
- [&](core::ir::Unreachable*) {}, //
- [&](core::ir::Var* i) { Var(i); }, //
+ inst, //
+ [&](const core::ir::Access* i) { Access(i); }, //
+ [&](const core::ir::Binary* i) { Binary(i); }, //
+ [&](const core::ir::BreakIf* i) { BreakIf(i); }, //
+ [&](const core::ir::Call* i) { Call(i); }, //
+ [&](const core::ir::Continue*) {}, //
+ [&](const core::ir::ExitIf*) {}, //
+ [&](const core::ir::ExitLoop* i) { ExitLoop(i); }, //
+ [&](const core::ir::ExitSwitch* i) { ExitSwitch(i); }, //
+ [&](const core::ir::If* i) { If(i); }, //
+ [&](const core::ir::Let* i) { Let(i); }, //
+ [&](const core::ir::Load* l) { Load(l); }, //
+ [&](const core::ir::LoadVectorElement* i) { LoadVectorElement(i); }, //
+ [&](const core::ir::Loop* l) { Loop(l); }, //
+ [&](const core::ir::NextIteration*) {}, //
+ [&](const core::ir::Return* i) { Return(i); }, //
+ [&](const core::ir::Store* i) { Store(i); }, //
+ [&](const core::ir::StoreVectorElement* i) { StoreVectorElement(i); }, //
+ [&](const core::ir::Switch* i) { Switch(i); }, //
+ [&](const core::ir::Swizzle* i) { Swizzle(i); }, //
+ [&](const core::ir::Unary* i) { Unary(i); }, //
+ [&](const core::ir::Unreachable*) {}, //
+ [&](const core::ir::Var* i) { Var(i); }, //
TINT_ICE_ON_NO_MATCH);
}
- void If(core::ir::If* if_) {
+ void If(const core::ir::If* if_) {
SCOPED_NESTING();
auto true_stmts = Statements(if_->True());
@@ -367,7 +357,7 @@
Append(b.If(cond, true_block, b.Else(false_block)));
}
- void Loop(core::ir::Loop* l) {
+ void Loop(const core::ir::Loop* l) {
SCOPED_NESTING();
// Build all the initializer statements
@@ -398,7 +388,7 @@
for (auto* inst : *l->Body()) {
if (body_stmts.IsEmpty()) {
if (auto* if_ = inst->As<core::ir::If>()) {
- if (!if_->HasResults() && //
+ if (if_->Results().IsEmpty() && //
if_->True()->Length() == 1 && //
if_->False()->Length() == 1 && //
tint::Is<core::ir::ExitIf>(if_->True()->Front()) && //
@@ -464,24 +454,24 @@
statements_->Push(loop);
}
- void Switch(core::ir::Switch* s) {
+ void Switch(const core::ir::Switch* s) {
SCOPED_NESTING();
auto* cond = Expr(s->Condition());
- auto cases = tint::Transform(
+ auto cases = tint::Transform<4>(
s->Cases(), //
- [&](core::ir::Switch::Case c) -> const tint::ast::CaseStatement* {
+ [&](const core::ir::Switch::Case& c) -> const tint::ast::CaseStatement* {
SCOPED_NESTING();
const ast::BlockStatement* body = nullptr;
{
- TINT_SCOPED_ASSIGNMENT(current_switch_case_, c.Block());
- body = Block(c.Block());
+ TINT_SCOPED_ASSIGNMENT(current_switch_case_, c.block);
+ body = Block(c.block);
}
auto selectors = tint::Transform(c.selectors, //
- [&](core::ir::Switch::CaseSelector cs) {
+ [&](const core::ir::Switch::CaseSelector& cs) {
return cs.IsDefault()
? b.DefaultCaseSelector()
: b.CaseSelector(Expr(cs.val));
@@ -501,9 +491,9 @@
void ExitLoop(const core::ir::ExitLoop*) { Append(b.Break()); }
- void BreakIf(core::ir::BreakIf* i) { Append(b.BreakIf(Expr(i->Condition()))); }
+ void BreakIf(const core::ir::BreakIf* i) { Append(b.BreakIf(Expr(i->Condition()))); }
- void Return(core::ir::Return* ret) {
+ void Return(const core::ir::Return* ret) {
if (ret->Args().IsEmpty()) {
// Return has no arguments.
// If this block is nested withing some control flow, then we must
@@ -524,12 +514,12 @@
Append(b.Return(Expr(ret->Args().Front())));
}
- void Var(core::ir::Var* var) {
- auto* val = var->Result();
+ void Var(const core::ir::Var* var) {
+ auto* val = var->Result(0);
auto* ptr = As<core::type::Pointer>(val->Type());
auto ty = Type(ptr->StoreType());
- Symbol name = NameFor(var->Result());
- Bind(var->Result(), name, PtrKind::kRef);
+ Symbol name = NameFor(var->Result(0));
+ Bind(var->Result(0), name, PtrKind::kRef);
Vector<const ast::Attribute*, 4> attrs;
if (auto bp = var->BindingPoint()) {
@@ -557,32 +547,32 @@
}
}
- void Let(core::ir::Let* let) {
- Symbol name = NameFor(let->Result());
+ void Let(const core::ir::Let* let) {
+ Symbol name = NameFor(let->Result(0));
Append(b.Decl(b.Let(name, Expr(let->Value(), PtrKind::kPtr))));
- Bind(let->Result(), name, PtrKind::kPtr);
+ Bind(let->Result(0), name, PtrKind::kPtr);
}
- void Store(core::ir::Store* store) {
+ void Store(const core::ir::Store* store) {
auto* dst = Expr(store->To());
auto* src = Expr(store->From());
Append(b.Assign(dst, src));
}
- void StoreVectorElement(core::ir::StoreVectorElement* store) {
+ void StoreVectorElement(const core::ir::StoreVectorElement* store) {
auto* ptr = Expr(store->To());
auto* val = Expr(store->Value());
Append(b.Assign(VectorMemberAccess(ptr, store->Index()), val));
}
- void Call(core::ir::Call* call) {
- auto args = tint::Transform<4>(call->Args(), [&](core::ir::Value* arg) {
+ void Call(const core::ir::Call* call) {
+ auto args = tint::Transform<4>(call->Args(), [&](const core::ir::Value* arg) {
// Pointer-like arguments are passed by pointer, never reference.
return Expr(arg, PtrKind::kPtr);
});
tint::Switch(
call, //
- [&](core::ir::UserCall* c) {
+ [&](const core::ir::UserCall* c) {
for (auto* arg : call->Args()) {
if (ArgRequiresFullPtrParameters(arg)) {
Enable(wgsl::Extension::kChromiumExperimentalFullPtrParameters);
@@ -590,13 +580,13 @@
}
}
auto* expr = b.Call(NameFor(c->Target()), std::move(args));
- if (!call->HasResults() || call->Result()->Usages().IsEmpty()) {
+ if (call->Results().IsEmpty() || !call->Result(0)->IsUsed()) {
Append(b.CallStmt(expr));
return;
}
- Bind(c->Result(), expr, PtrKind::kPtr);
+ Bind(c->Result(0), expr, PtrKind::kPtr);
},
- [&](wgsl::ir::BuiltinCall* c) {
+ [&](const wgsl::ir::BuiltinCall* c) {
if (!disabled_derivative_uniformity_ && RequiresDerivativeUniformity(c->Func())) {
// TODO(crbug.com/tint/1985): Be smarter about disabling derivative uniformity.
b.DiagnosticDirective(wgsl::DiagnosticSeverity::kOff,
@@ -614,36 +604,36 @@
}
auto* expr = b.Call(c->Func(), std::move(args));
- if (!call->HasResults() || call->Result()->Type()->Is<core::type::Void>()) {
+ if (call->Results().IsEmpty() || call->Result(0)->Type()->Is<core::type::Void>()) {
Append(b.CallStmt(expr));
return;
}
- Bind(c->Result(), expr, PtrKind::kPtr);
+ Bind(c->Result(0), expr, PtrKind::kPtr);
},
- [&](core::ir::Construct* c) {
- auto ty = Type(c->Result()->Type());
- Bind(c->Result(), b.Call(ty, std::move(args)), PtrKind::kPtr);
+ [&](const core::ir::Construct* c) {
+ auto ty = Type(c->Result(0)->Type());
+ Bind(c->Result(0), b.Call(ty, std::move(args)), PtrKind::kPtr);
},
- [&](core::ir::Convert* c) {
- auto ty = Type(c->Result()->Type());
- Bind(c->Result(), b.Call(ty, std::move(args)), PtrKind::kPtr);
+ [&](const core::ir::Convert* c) {
+ auto ty = Type(c->Result(0)->Type());
+ Bind(c->Result(0), b.Call(ty, std::move(args)), PtrKind::kPtr);
},
- [&](core::ir::Bitcast* c) {
- auto ty = Type(c->Result()->Type());
- Bind(c->Result(), b.Bitcast(ty, args[0]), PtrKind::kPtr);
+ [&](const core::ir::Bitcast* c) {
+ auto ty = Type(c->Result(0)->Type());
+ Bind(c->Result(0), b.Bitcast(ty, args[0]), PtrKind::kPtr);
},
- [&](core::ir::Discard*) { Append(b.Discard()); }, //
+ [&](const core::ir::Discard*) { Append(b.Discard()); }, //
TINT_ICE_ON_NO_MATCH);
}
- void Load(core::ir::Load* l) { Bind(l->Result(), Expr(l->From())); }
+ void Load(const core::ir::Load* l) { Bind(l->Result(0), Expr(l->From())); }
- void LoadVectorElement(core::ir::LoadVectorElement* load) {
+ void LoadVectorElement(const core::ir::LoadVectorElement* load) {
auto* ptr = Expr(load->From());
- Bind(load->Result(), VectorMemberAccess(ptr, load->Index()));
+ Bind(load->Result(0), VectorMemberAccess(ptr, load->Index()));
}
- void Unary(core::ir::Unary* u) {
+ void Unary(const core::ir::Unary* u) {
const ast::Expression* expr = nullptr;
switch (u->Op()) {
case core::ir::UnaryOp::kComplement:
@@ -653,10 +643,10 @@
expr = b.Negation(Expr(u->Val()));
break;
}
- Bind(u->Result(), expr);
+ Bind(u->Result(0), expr);
}
- void Access(core::ir::Access* a) {
+ void Access(const core::ir::Access* a) {
auto* expr = Expr(a->Object());
auto* obj_ty = a->Object()->Type()->UnwrapPtr();
for (auto* index : a->Indices()) {
@@ -687,10 +677,10 @@
}, //
TINT_ICE_ON_NO_MATCH);
}
- Bind(a->Result(), expr);
+ Bind(a->Result(0), expr);
}
- void Swizzle(core::ir::Swizzle* s) {
+ void Swizzle(const core::ir::Swizzle* s) {
auto* vec = Expr(s->Object());
Vector<char, 4> components;
for (uint32_t i : s->Indices()) {
@@ -702,16 +692,16 @@
}
auto* swizzle =
b.MemberAccessor(vec, std::string_view(components.begin(), components.Length()));
- Bind(s->Result(), swizzle);
+ Bind(s->Result(0), swizzle);
}
- void Binary(core::ir::Binary* e) {
+ void Binary(const core::ir::Binary* e) {
if (e->Op() == core::ir::BinaryOp::kEqual) {
auto* rhs = e->RHS()->As<core::ir::Constant>();
if (rhs && rhs->Type()->Is<core::type::Bool>() &&
rhs->Value()->ValueAs<bool>() == false) {
// expr == false
- Bind(e->Result(), b.Not(Expr(e->LHS())));
+ Bind(e->Result(0), b.Not(Expr(e->LHS())));
return;
}
}
@@ -768,17 +758,18 @@
expr = b.Shr(lhs, rhs);
break;
}
- Bind(e->Result(), expr);
+ Bind(e->Result(0), expr);
}
TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
- const ast::Expression* Expr(core::ir::Value* value, PtrKind want_ptr_kind = PtrKind::kRef) {
+ const ast::Expression* Expr(const core::ir::Value* value,
+ PtrKind want_ptr_kind = PtrKind::kRef) {
using ExprAndPtrKind = std::pair<const ast::Expression*, PtrKind>;
auto [expr, got_ptr_kind] = tint::Switch(
value,
- [&](core::ir::Constant* c) -> ExprAndPtrKind {
+ [&](const core::ir::Constant* c) -> ExprAndPtrKind {
return {Constant(c), PtrKind::kRef};
},
[&](Default) -> ExprAndPtrKind {
@@ -829,7 +820,7 @@
TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
- const ast::Expression* Constant(core::ir::Constant* c) { return Constant(c->Value()); }
+ const ast::Expression* Constant(const core::ir::Constant* c) { return Constant(c->Value()); }
const ast::Expression* Constant(const core::constant::Value* c) {
auto composite = [&](bool can_splat) {
@@ -1020,7 +1011,7 @@
/// @returns the AST name for the given value, creating and returning a new name on the first
/// call.
- Symbol NameFor(core::ir::Value* value, std::string_view suggested = {}) {
+ Symbol NameFor(const core::ir::Value* value, std::string_view suggested = {}) {
return names_.GetOrCreate(value, [&] {
if (!suggested.empty()) {
return b.Symbols().Register(suggested);
@@ -1034,7 +1025,7 @@
/// Associates the IR value @p value with the AST expression @p expr.
/// @p ptr_kind defines how pointer values are represented by @p expr.
- void Bind(core::ir::Value* value,
+ void Bind(const core::ir::Value* value,
const ast::Expression* expr,
PtrKind ptr_kind = PtrKind::kRef) {
TINT_ASSERT(value);
@@ -1048,7 +1039,7 @@
expr = ToPtrKind(expr, ptr_kind, PtrKind::kPtr);
}
auto mod_name = mod.NameOf(value);
- if (value->Usages().IsEmpty() && !mod_name.IsValid()) {
+ if (!value->IsUsed() && !mod_name.IsValid()) {
// Value has no usages and no name.
// Assign to a phony. These support more data types than a 'let', and avoids
// allocation of unused names.
@@ -1067,7 +1058,7 @@
/// Associates the IR value @p value with the AST 'var', 'let' or parameter with the name @p
/// name.
/// @p ptr_kind defines how pointer values are represented by @p expr.
- void Bind(core::ir::Value* value, Symbol name, PtrKind ptr_kind) {
+ void Bind(const core::ir::Value* value, Symbol name, PtrKind ptr_kind) {
TINT_ASSERT(value);
bool added = bindings_.Add(value, VariableValue{name, ptr_kind});
@@ -1079,13 +1070,13 @@
////////////////////////////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////////////////////////////
- bool AsShortCircuit(core::ir::If* i,
+ bool AsShortCircuit(const core::ir::If* i,
const StatementList& true_stmts,
const StatementList& false_stmts) {
- if (!i->HasResults()) {
+ if (i->Results().IsEmpty()) {
return false;
}
- auto* result = i->Result();
+ auto* result = i->Result(0);
if (!result->Type()->Is<core::type::Bool>()) {
return false; // Wrong result type
}
@@ -1140,7 +1131,7 @@
return false;
}
- bool IsConstant(core::ir::Value* val, bool value) {
+ bool IsConstant(const core::ir::Value* val, bool value) {
if (auto* c = val->As<core::ir::Constant>()) {
if (c->Type()->Is<core::type::Bool>()) {
return c->Value()->ValueAs<bool>() == value;
@@ -1149,7 +1140,8 @@
return false;
}
- const ast::Expression* VectorMemberAccess(const ast::Expression* expr, core::ir::Value* index) {
+ const ast::Expression* VectorMemberAccess(const ast::Expression* expr,
+ const core::ir::Value* index) {
if (auto* c = index->As<core::ir::Constant>()) {
switch (c->Value()->ValueAs<int>()) {
case 0:
@@ -1215,14 +1207,14 @@
/// @returns true if the argument @p arg requires the kChromiumExperimentalFullPtrParameters
/// extension to be enabled.
- bool ArgRequiresFullPtrParameters(core::ir::Value* arg) {
+ bool ArgRequiresFullPtrParameters(const core::ir::Value* arg) {
if (!arg->Type()->Is<core::type::Pointer>()) {
return false;
}
auto res = arg->As<core::ir::InstructionResult>();
while (res) {
- auto* inst = res->Source();
+ auto* inst = res->Instruction();
if (inst->Is<core::ir::Access>()) {
return true; // Passing pointer into sub-object
}
@@ -1238,7 +1230,7 @@
} // namespace
-Program IRToProgram(core::ir::Module& i) {
+Program IRToProgram(const core::ir::Module& i) {
return State{i}.Run();
}
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h
index 267bb29..089a1e7 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h
@@ -40,7 +40,7 @@
/// @param module the IR module
/// @return the tint::Program.
/// @note Check the returned Program::Diagnostics() for any errors.
-Program IRToProgram(core::ir::Module& module);
+Program IRToProgram(const core::ir::Module& module);
} // namespace tint::wgsl::writer
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
index 53af431..d034c0d 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
@@ -1870,11 +1870,11 @@
auto* va = b.Var("a", ty.ptr<function, i32>());
va->SetInitializer(b.Constant(42_i));
- auto* la = b.Load(va)->Result();
+ auto* la = b.Load(va)->Result(0);
auto* vb = b.Var("b", ty.ptr<function, i32>());
vb->SetInitializer(la);
- auto* lb = b.Load(vb)->Result();
+ auto* lb = b.Load(vb)->Result(0);
auto* vc = b.Var("c", ty.ptr<function, i32>());
vc->SetInitializer(lb);
@@ -2206,7 +2206,7 @@
v->SetInitializer(b.Constant(42_i));
auto s = b.Switch(b.Load(v));
- b.Append(b.Case(s, {core::ir::Switch::CaseSelector{}}), [&] {
+ b.Append(b.DefaultCase(s), [&] {
b.Call(ty.void_(), fn_a);
b.ExitSwitch(s);
});
@@ -2246,20 +2246,15 @@
v->SetInitializer(b.Constant(42_i));
auto s = b.Switch(b.Load(v));
- b.Append(b.Case(s, {core::ir::Switch::CaseSelector{b.Constant(0_i)}}), [&] {
+ b.Append(b.Case(s, {b.Constant(0_i)}), [&] {
b.Call(ty.void_(), fn_a);
b.ExitSwitch(s);
});
- b.Append(b.Case(s,
- {
- core::ir::Switch::CaseSelector{b.Constant(1_i)},
- core::ir::Switch::CaseSelector{},
- }),
- [&] {
- b.Call(ty.void_(), fn_b);
- b.ExitSwitch(s);
- });
- b.Append(b.Case(s, {core::ir::Switch::CaseSelector{b.Constant(2_i)}}), [&] {
+ b.Append(b.Case(s, {b.Constant(1_i), nullptr}), [&] {
+ b.Call(ty.void_(), fn_b);
+ b.ExitSwitch(s);
+ });
+ b.Append(b.Case(s, {b.Constant(2_i)}), [&] {
b.Call(ty.void_(), fn_c);
b.ExitSwitch(s);
});
@@ -2305,16 +2300,9 @@
v->SetInitializer(b.Constant(42_i));
auto s = b.Switch(b.Load(v));
- b.Append(b.Case(s, {core::ir::Switch::CaseSelector{b.Constant(0_i)}}),
- [&] { b.Return(fn); });
- b.Append(b.Case(s,
- {
- core::ir::Switch::CaseSelector{b.Constant(1_i)},
- core::ir::Switch::CaseSelector{},
- }),
- [&] { b.Return(fn); });
- b.Append(b.Case(s, {core::ir::Switch::CaseSelector{b.Constant(2_i)}}),
- [&] { b.Return(fn); });
+ b.Append(b.Case(s, {b.Constant(0_i)}), [&] { b.Return(fn); });
+ b.Append(b.Case(s, {b.Constant(1_i), nullptr}), [&] { b.Return(fn); });
+ b.Append(b.Case(s, {b.Constant(2_i)}), [&] { b.Return(fn); });
b.Call(ty.void_(), fn_a);
b.Return(fn);
@@ -2361,29 +2349,18 @@
v2->SetInitializer(b.Constant(24_i));
auto s1 = b.Switch(b.Load(v1));
- b.Append(b.Case(s1, {core::ir::Switch::CaseSelector{b.Constant(0_i)}}), [&] {
+ b.Append(b.Case(s1, {b.Constant(0_i)}), [&] {
b.Call(ty.void_(), fn_a);
b.ExitSwitch(s1);
});
- b.Append(b.Case(s1,
- {
- core::ir::Switch::CaseSelector{b.Constant(1_i)},
- core::ir::Switch::CaseSelector{},
- }),
- [&] {
- auto s2 = b.Switch(b.Load(v2));
- b.Append(b.Case(s2, {core::ir::Switch::CaseSelector{b.Constant(0_i)}}),
- [&] { b.ExitSwitch(s2); });
- b.Append(b.Case(s2,
- {
- core::ir::Switch::CaseSelector{b.Constant(1_i)},
- core::ir::Switch::CaseSelector{},
- }),
- [&] { b.Return(fn); });
+ b.Append(b.Case(s1, {b.Constant(1_i), nullptr}), [&] {
+ auto s2 = b.Switch(b.Load(v2));
+ b.Append(b.Case(s2, {b.Constant(0_i)}), [&] { b.ExitSwitch(s2); });
+ b.Append(b.Case(s2, {b.Constant(1_i), nullptr}), [&] { b.Return(fn); });
- b.ExitSwitch(s1);
- });
- b.Append(b.Case(s1, {core::ir::Switch::CaseSelector{b.Constant(2_i)}}), [&] {
+ b.ExitSwitch(s1);
+ });
+ b.Append(b.Case(s1, {b.Constant(2_i)}), [&] {
b.Call(ty.void_(), fn_c);
b.ExitSwitch(s1);
});
@@ -2694,7 +2671,7 @@
auto* loop = b.Loop();
b.Append(loop->Initializer(), [&] {
- auto* n_0 = b.Call(ty.i32(), fn_n, 0_i)->Result();
+ auto* n_0 = b.Call(ty.i32(), fn_n, 0_i)->Result(0);
auto* i = b.Var("i", ty.ptr<function, i32>());
i->SetInitializer(n_0);
b.NextIteration(loop);
diff --git a/src/tint/lang/wgsl/writer/raise/BUILD.bazel b/src/tint/lang/wgsl/writer/raise/BUILD.bazel
index 4378fbe..e403363 100644
--- a/src/tint/lang/wgsl/writer/raise/BUILD.bazel
+++ b/src/tint/lang/wgsl/writer/raise/BUILD.bazel
@@ -40,9 +40,11 @@
name = "raise",
srcs = [
"raise.cc",
+ "rename_conflicts.cc",
],
hdrs = [
"raise.h",
+ "rename_conflicts.h",
],
deps = [
"//src/tint/api/common",
@@ -76,6 +78,7 @@
alwayslink = True,
srcs = [
"raise_test.cc",
+ "rename_conflicts_test.cc",
],
deps = [
"//src/tint/api/common",
diff --git a/src/tint/lang/wgsl/writer/raise/BUILD.cmake b/src/tint/lang/wgsl/writer/raise/BUILD.cmake
index 153221c..cf18c7f 100644
--- a/src/tint/lang/wgsl/writer/raise/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/raise/BUILD.cmake
@@ -41,6 +41,8 @@
tint_add_target(tint_lang_wgsl_writer_raise lib
lang/wgsl/writer/raise/raise.cc
lang/wgsl/writer/raise/raise.h
+ lang/wgsl/writer/raise/rename_conflicts.cc
+ lang/wgsl/writer/raise/rename_conflicts.h
)
tint_target_add_dependencies(tint_lang_wgsl_writer_raise lib
@@ -74,6 +76,7 @@
################################################################################
tint_add_target(tint_lang_wgsl_writer_raise_test test
lang/wgsl/writer/raise/raise_test.cc
+ lang/wgsl/writer/raise/rename_conflicts_test.cc
)
tint_target_add_dependencies(tint_lang_wgsl_writer_raise_test test
diff --git a/src/tint/lang/wgsl/writer/raise/BUILD.gn b/src/tint/lang/wgsl/writer/raise/BUILD.gn
index db96351..53b013a 100644
--- a/src/tint/lang/wgsl/writer/raise/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/raise/BUILD.gn
@@ -46,6 +46,8 @@
sources = [
"raise.cc",
"raise.h",
+ "rename_conflicts.cc",
+ "rename_conflicts.h",
]
deps = [
"${tint_src_dir}/api/common",
@@ -74,7 +76,10 @@
}
if (tint_build_unittests) {
tint_unittests_source_set("unittests") {
- sources = [ "raise_test.cc" ]
+ sources = [
+ "raise_test.cc",
+ "rename_conflicts_test.cc",
+ ]
deps = [
"${tint_src_dir}:gmock_and_gtest",
"${tint_src_dir}/api/common",
diff --git a/src/tint/lang/wgsl/writer/raise/raise.cc b/src/tint/lang/wgsl/writer/raise/raise.cc
index 407d4e1..cf0f06e 100644
--- a/src/tint/lang/wgsl/writer/raise/raise.cc
+++ b/src/tint/lang/wgsl/writer/raise/raise.cc
@@ -35,6 +35,7 @@
#include "src/tint/lang/core/type/pointer.h"
#include "src/tint/lang/wgsl/builtin_fn.h"
#include "src/tint/lang/wgsl/ir/builtin_call.h"
+#include "src/tint/lang/wgsl/writer/raise/rename_conflicts.h"
namespace tint::wgsl::writer {
namespace {
@@ -169,7 +170,7 @@
void ReplaceBuiltinFnCall(core::ir::Module& mod, core::ir::CoreBuiltinCall* call) {
Vector<core::ir::Value*, 8> args(call->Args());
auto* replacement = mod.instructions.Create<wgsl::ir::BuiltinCall>(
- call->Result(), Convert(call->Func()), std::move(args));
+ call->Result(0), Convert(call->Func()), std::move(args));
call->ReplaceWith(replacement);
call->ClearResults();
call->Destroy();
@@ -183,7 +184,7 @@
// And replace with:
// %value = call workgroupUniformLoad %ptr
- auto* load = As<core::ir::Load>(call->next);
+ auto* load = As<core::ir::Load>(call->next.Get());
if (!load || load->From()->Type()->As<core::type::Pointer>()->AddressSpace() !=
core::AddressSpace::kWorkgroup) {
// No match
@@ -191,7 +192,7 @@
return;
}
- auto* post_load = As<core::ir::CoreBuiltinCall>(load->next);
+ auto* post_load = As<core::ir::CoreBuiltinCall>(load->next.Get());
if (!post_load || post_load->Func() != core::BuiltinFn::kWorkgroupBarrier) {
// No match
ReplaceBuiltinFnCall(mod, call);
@@ -204,7 +205,7 @@
// Replace load with workgroupUniformLoad
auto* replacement = mod.instructions.Create<wgsl::ir::BuiltinCall>(
- load->Result(), wgsl::BuiltinFn::kWorkgroupUniformLoad, Vector{load->From()});
+ load->Result(0), wgsl::BuiltinFn::kWorkgroupUniformLoad, Vector{load->From()});
load->ReplaceWith(replacement);
load->ClearResults();
load->Destroy();
@@ -228,6 +229,10 @@
}
}
}
+ if (auto result = RenameConflicts(&mod); !result) {
+ return result.Failure();
+ }
+
return Success;
}
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc b/src/tint/lang/wgsl/writer/raise/rename_conflicts.cc
similarity index 97%
rename from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc
rename to src/tint/lang/wgsl/writer/raise/rename_conflicts.cc
index a7f210f..7636059 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc
+++ b/src/tint/lang/wgsl/writer/raise/rename_conflicts.cc
@@ -42,7 +42,7 @@
#include "src/tint/lang/core/type/scalar.h"
#include "src/tint/lang/core/type/struct.h"
#include "src/tint/lang/core/type/vector.h"
-#include "src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h"
+#include "src/tint/lang/wgsl/writer/raise/rename_conflicts.h"
#include "src/tint/utils/containers/hashset.h"
#include "src/tint/utils/containers/reverse.h"
#include "src/tint/utils/containers/scope_stack.h"
@@ -74,7 +74,7 @@
}
// Process the functions
- for (auto* fn : ir->functions) {
+ for (core::ir::Function* fn : ir->functions) {
scopes.Push(Scope{});
TINT_DEFER(scopes.Pop());
for (auto* param : fn->Params()) {
@@ -121,7 +121,7 @@
}
// Declare all the functions
- for (auto* fn : ir->functions) {
+ for (core::ir::Function* fn : ir->functions) {
if (auto symbol = ir->NameOf(fn); symbol.IsValid()) {
Declare(scopes.Back(), fn, symbol.NameView());
}
@@ -181,11 +181,11 @@
},
[&](core::ir::Var*) {
// Ensure the var's type is resolvable
- EnsureResolvable(inst->Result()->Type());
+ EnsureResolvable(inst->Result(0)->Type());
},
[&](core::ir::Construct*) {
// Ensure the type of a type constructor is resolvable
- EnsureResolvable(inst->Result()->Type());
+ EnsureResolvable(inst->Result(0)->Type());
},
[&](core::ir::CoreBuiltinCall* call) {
// Ensure builtin of a builtin call is resolvable
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/lang/wgsl/writer/raise/rename_conflicts.h
similarity index 90%
rename from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
rename to src/tint/lang/wgsl/writer/raise/rename_conflicts.h
index 6f0f657..9f5d989 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/lang/wgsl/writer/raise/rename_conflicts.h
@@ -25,8 +25,8 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
-#define SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#ifndef SRC_TINT_LANG_WGSL_WRITER_RAISE_RENAME_CONFLICTS_H_
+#define SRC_TINT_LANG_WGSL_WRITER_RAISE_RENAME_CONFLICTS_H_
#include <string>
@@ -49,4 +49,4 @@
} // namespace tint::wgsl::writer
-#endif // SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#endif // SRC_TINT_LANG_WGSL_WRITER_RAISE_RENAME_CONFLICTS_H_
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc b/src/tint/lang/wgsl/writer/raise/rename_conflicts_test.cc
similarity index 99%
rename from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc
rename to src/tint/lang/wgsl/writer/raise/rename_conflicts_test.cc
index 98066fd..bc46235 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc
+++ b/src/tint/lang/wgsl/writer/raise/rename_conflicts_test.cc
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h"
+#include "src/tint/lang/wgsl/writer/raise/rename_conflicts.h"
#include <string>
#include <utility>
@@ -1032,7 +1032,7 @@
auto* fn = b.Function("f", ty.i32());
b.Append(fn->Block(), [&] { //
- auto* res = b.Call(ty.i32(), core::BuiltinFn::kMax, 1_i, 2_i)->Result();
+ auto* res = b.Call(ty.i32(), core::BuiltinFn::kMax, 1_i, 2_i)->Result(0);
b.Return(fn, res);
});
@@ -1065,7 +1065,7 @@
auto* fn = b.Function("f", ty.i32());
b.Append(fn->Block(), [&] { //
- auto* res = b.Call(ty.i32(), core::BuiltinFn::kMax, 1_i, 2_i)->Result();
+ auto* res = b.Call(ty.i32(), core::BuiltinFn::kMax, 1_i, 2_i)->Result(0);
b.Return(fn, res);
});
diff --git a/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.bazel b/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.bazel
index 7a522bd..96fdf82 100644
--- a/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.bazel
+++ b/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.bazel
@@ -50,6 +50,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.cmake b/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.cmake
index c92f99b..859fa03 100644
--- a/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.cmake
@@ -49,6 +49,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.gn b/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.gn
index c210fa6..71df0af 100644
--- a/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/syntax_tree_printer/BUILD.gn
@@ -49,6 +49,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.cc b/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.cc
index b157a0c..529f9c2 100644
--- a/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.cc
+++ b/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.cc
@@ -27,10 +27,7 @@
#include "src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.h"
-#include <algorithm>
-
#include "src/tint/lang/core/texel_format.h"
-#include "src/tint/lang/wgsl/ast/accessor_expression.h"
#include "src/tint/lang/wgsl/ast/alias.h"
#include "src/tint/lang/wgsl/ast/assignment_statement.h"
#include "src/tint/lang/wgsl/ast/binary_expression.h"
@@ -82,7 +79,6 @@
#include "src/tint/lang/wgsl/sem/struct.h"
#include "src/tint/lang/wgsl/sem/switch_statement.h"
#include "src/tint/utils/macros/scoped_assignment.h"
-#include "src/tint/utils/math/math.h"
#include "src/tint/utils/rtti/switch.h"
#include "src/tint/utils/strconv/float_to_string.h"
#include "src/tint/utils/text/string.h"
@@ -263,9 +259,10 @@
// NaN and Inf are not allowed to be spelled in literal, it should be fine to emit
// f16 literals in this way.
if (l->suffix == ast::FloatLiteralExpression::Suffix::kNone) {
- Line() << tint::writer::DoubleToBitPreservingString(l->value);
+ Line() << tint::strconv::DoubleToBitPreservingString(l->value);
} else {
- Line() << tint::writer::FloatToBitPreservingString(static_cast<float>(l->value))
+ Line() << tint::strconv::FloatToBitPreservingString(
+ static_cast<float>(l->value))
<< l->suffix;
}
},
diff --git a/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.h b/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.h
index d47ea65..4a94bac 100644
--- a/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.h
+++ b/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.h
@@ -28,12 +28,8 @@
#ifndef SRC_TINT_LANG_WGSL_WRITER_SYNTAX_TREE_PRINTER_SYNTAX_TREE_PRINTER_H_
#define SRC_TINT_LANG_WGSL_WRITER_SYNTAX_TREE_PRINTER_SYNTAX_TREE_PRINTER_H_
-#include <string>
-
#include "src/tint/lang/wgsl/program/program.h"
-#include "src/tint/lang/wgsl/sem/struct.h"
#include "src/tint/utils/generator/text_generator.h"
-#include "src/tint/utils/text/string_stream.h"
// Forward declarations
namespace tint::core {
diff --git a/src/tint/tint.gni b/src/tint/tint.gni
index 137def3..8ae6c91 100644
--- a/src/tint/tint.gni
+++ b/src/tint/tint.gni
@@ -29,6 +29,20 @@
import("../../scripts/tint_overrides_with_defaults.gni")
+if (tint_has_protobuf) {
+ import("//third_party/protobuf/proto_library.gni")
+}
+
+###############################################################################
+# OS defines
+###############################################################################
+tint_build_is_win = is_win
+tint_build_is_mac = is_mac
+tint_build_is_linux = is_linux
+
+###############################################################################
+# Tint library target
+###############################################################################
template("libtint_source_set") {
source_set(target_name) {
forward_variables_from(invoker, "*", [ "configs" ])
@@ -57,6 +71,21 @@
}
###############################################################################
+# Tint protobuf library target
+###############################################################################
+template("tint_proto_library") {
+ if (!tint_has_protobuf) {
+ error("Tint needs protobuf to build a proto library")
+ }
+ proto_library(target_name) {
+ forward_variables_from(invoker, "*", [ "configs" ])
+ generate_cc = true
+ generate_python = false
+ use_protobuf_full = true
+ }
+}
+
+###############################################################################
# Executables - only built when tint_build_cmds is enabled
###############################################################################
template("tint_executable") {
diff --git a/src/tint/utils/BUILD.cmake b/src/tint/utils/BUILD.cmake
index 659c2a2..badeb73 100644
--- a/src/tint/utils/BUILD.cmake
+++ b/src/tint/utils/BUILD.cmake
@@ -34,6 +34,7 @@
# Do not modify this file directly
################################################################################
+include(utils/bytes/BUILD.cmake)
include(utils/cli/BUILD.cmake)
include(utils/command/BUILD.cmake)
include(utils/containers/BUILD.cmake)
diff --git a/src/tint/utils/bytes/BUILD.bazel b/src/tint/utils/bytes/BUILD.bazel
new file mode 100644
index 0000000..1b60b1d
--- /dev/null
+++ b/src/tint/utils/bytes/BUILD.bazel
@@ -0,0 +1,92 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+cc_library(
+ name = "bytes",
+ srcs = [
+ "bytes.cc",
+ ],
+ hdrs = [
+ "decoder.h",
+ "endianness.h",
+ "reader.h",
+ "swap.h",
+ ],
+ deps = [
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+cc_library(
+ name = "test",
+ alwayslink = True,
+ srcs = [
+ "decoder_test.cc",
+ "reader_test.cc",
+ "swap_test.cc",
+ ],
+ deps = [
+ "//src/tint/utils/bytes",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ "@gtest",
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+
diff --git a/src/tint/utils/bytes/BUILD.cmake b/src/tint/utils/bytes/BUILD.cmake
new file mode 100644
index 0000000..1012db6
--- /dev/null
+++ b/src/tint/utils/bytes/BUILD.cmake
@@ -0,0 +1,90 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+################################################################################
+# Target: tint_utils_bytes
+# Kind: lib
+################################################################################
+tint_add_target(tint_utils_bytes lib
+ utils/bytes/bytes.cc
+ utils/bytes/decoder.h
+ utils/bytes/endianness.h
+ utils/bytes/reader.h
+ utils/bytes/swap.h
+)
+
+tint_target_add_dependencies(tint_utils_bytes lib
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_text
+ tint_utils_traits
+)
+
+################################################################################
+# Target: tint_utils_bytes_test
+# Kind: test
+################################################################################
+tint_add_target(tint_utils_bytes_test test
+ utils/bytes/decoder_test.cc
+ utils/bytes/reader_test.cc
+ utils/bytes/swap_test.cc
+)
+
+tint_target_add_dependencies(tint_utils_bytes_test test
+ tint_utils_bytes
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_text
+ tint_utils_traits
+)
+
+tint_target_add_external_dependencies(tint_utils_bytes_test test
+ "gtest"
+)
diff --git a/src/tint/utils/bytes/BUILD.gn b/src/tint/utils/bytes/BUILD.gn
new file mode 100644
index 0000000..97931f1
--- /dev/null
+++ b/src/tint/utils/bytes/BUILD.gn
@@ -0,0 +1,90 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+import("../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+
+if (tint_build_unittests || tint_build_benchmarks) {
+ import("//testing/test.gni")
+}
+
+libtint_source_set("bytes") {
+ sources = [
+ "bytes.cc",
+ "decoder.h",
+ "endianness.h",
+ "reader.h",
+ "swap.h",
+ ]
+ deps = [
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+}
+if (tint_build_unittests) {
+ tint_unittests_source_set("unittests") {
+ sources = [
+ "decoder_test.cc",
+ "reader_test.cc",
+ "swap_test.cc",
+ ]
+ deps = [
+ "${tint_src_dir}:gmock_and_gtest",
+ "${tint_src_dir}/utils/bytes",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+ }
+}
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/utils/bytes/bytes.cc
similarity index 65%
copy from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
copy to src/tint/utils/bytes/bytes.cc
index 6f0f657..392f0ea 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/utils/bytes/bytes.cc
@@ -25,28 +25,9 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
-#define SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
+#endif
-#include <string>
-
-#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/result/result.h"
-
-// Forward declarations.
-namespace tint::core::ir {
-class Module;
-}
-
-namespace tint::wgsl::writer {
-
-/// RenameConflicts is a transform that renames declarations which prevent identifiers from
-/// resolving to the correct declaration, and those with identical identifiers declared in the same
-/// scope.
-/// @param module the module to transform
-/// @returns success or failure
-Result<SuccessType> RenameConflicts(core::ir::Module* module);
-
-} // namespace tint::wgsl::writer
-
-#endif // SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+// A placeholder symbol used to emit a symbol for this lib target.
+int tint_utils_bytes_symbol = 1;
diff --git a/src/tint/utils/bytes/decoder.h b/src/tint/utils/bytes/decoder.h
new file mode 100644
index 0000000..591f255
--- /dev/null
+++ b/src/tint/utils/bytes/decoder.h
@@ -0,0 +1,192 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_UTILS_BYTES_DECODER_H_
+#define SRC_TINT_UTILS_BYTES_DECODER_H_
+
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <utility>
+
+#include "src/tint/utils/bytes/reader.h"
+#include "src/tint/utils/result/result.h"
+
+namespace tint::bytes {
+
+template <typename T, typename = void>
+struct Decoder;
+
+/// Decodes T from @p reader.
+/// @param reader the byte reader
+/// @returns the decoded object
+template <typename T>
+Result<T> Decode(Reader& reader) {
+ return Decoder<T>::Decode(reader);
+}
+
+/// Decoder specialization for integer types
+template <typename T>
+struct Decoder<T, std::enable_if_t<std::is_integral_v<T>>> {
+ /// Decode decodes the integer type from @p reader.
+ /// @param reader the reader to decode from
+ /// @returns the decoded integer type, or an error if the stream is too short.
+ static Result<T> Decode(Reader& reader) {
+ if (reader.BytesRemaining() < sizeof(T)) {
+ return Failure{"EOF"};
+ }
+ return reader.Int<T>();
+ }
+};
+
+/// Decoder specialization for floating point types
+template <typename T>
+struct Decoder<T, std::enable_if_t<std::is_floating_point_v<T>>> {
+ /// Decode decodes the floating point type from @p reader.
+ /// @param reader the reader to decode from
+ /// @returns the decoded floating point type, or an error if the stream is too short.
+ static Result<T> Decode(Reader& reader) {
+ if (reader.BytesRemaining() < sizeof(T)) {
+ return Failure{"EOF"};
+ }
+ return reader.Float<T>();
+ }
+};
+
+/// Decoder specialization for a uint16_t length prefixed string.
+template <typename T>
+struct Decoder<T, std::enable_if_t<std::is_same_v<T, std::string>>> {
+ /// Decode decodes the string from @p reader.
+ /// @param reader the reader to decode from
+ /// @returns the decoded string, or an error if the stream is too short.
+ static Result<T> Decode(Reader& reader) {
+ if (reader.BytesRemaining() < sizeof(uint16_t)) {
+ return Failure{"EOF"};
+ }
+ auto len = reader.Int<uint16_t>();
+ if (reader.BytesRemaining() < len) {
+ return Failure{"EOF"};
+ }
+ return reader.String(len);
+ }
+};
+
+/// Decoder specialization for bool types
+template <>
+struct Decoder<bool, void> {
+ static Result<bool> Decode(Reader& reader) {
+ /// Decode decodes the boolean from @p reader.
+ /// @param reader the reader to decode from
+ /// @returns the decoded boolean, or an error if the stream is too short.
+ if (reader.IsEOF()) {
+ return Failure{"EOF"};
+ }
+ return reader.Bool();
+ }
+};
+
+/// Decoder specialization for types that use TINT_REFLECT
+template <typename T>
+struct Decoder<T, std::enable_if_t<HasReflection<T>>> {
+ /// Decode decodes the reflected type from @p reader.
+ /// @param reader the reader to decode from
+ /// @returns the decoded reflected type, or an error if the stream is too short.
+ static Result<T> Decode(Reader& reader) {
+ T object{};
+ diag::List errs;
+ ForeachField(object, [&](auto& field) { //
+ auto value = bytes::Decode<std::decay_t<decltype(field)>>(reader);
+ if (value) {
+ field = value.Get();
+ } else {
+ errs.add(value.Failure().reason);
+ }
+ });
+ if (errs.empty()) {
+ return object;
+ }
+ return Failure{errs};
+ }
+};
+
+/// Decoder specialization for std::unordered_map
+template <typename K, typename V>
+struct Decoder<std::unordered_map<K, V>, void> {
+ /// Decode decodes the map from @p reader.
+ /// @param reader the reader to decode from
+ /// @returns the decoded map, or an error if the stream is too short.
+ static Result<std::unordered_map<K, V>> Decode(Reader& reader) {
+ std::unordered_map<K, V> out;
+
+ while (true) {
+ if (reader.IsEOF()) {
+ return Failure{"EOF"};
+ }
+ if (reader.Bool()) {
+ break;
+ }
+ auto key = bytes::Decode<K>(reader);
+ if (!key) {
+ return key.Failure();
+ }
+ auto val = bytes::Decode<V>(reader);
+ if (!val) {
+ return val.Failure();
+ }
+ out.emplace(std::move(key.Get()), std::move(val.Get()));
+ }
+
+ return out;
+ }
+};
+
+/// Decoder specialization for std::tuple
+template <typename FIRST, typename... OTHERS>
+struct Decoder<std::tuple<FIRST, OTHERS...>, void> {
+ /// Decode decodes the tuple from @p reader.
+ /// @param reader the reader to decode from
+ /// @returns the decoded tuple, or an error if the stream is too short.
+ static Result<std::tuple<FIRST, OTHERS...>> Decode(Reader& reader) {
+ auto first = bytes::Decode<FIRST>(reader);
+ if (!first) {
+ return first.Failure();
+ }
+ if constexpr (sizeof...(OTHERS) > 0) {
+ auto others = bytes::Decode<std::tuple<OTHERS...>>(reader);
+ if (!others) {
+ return others.Failure();
+ }
+ return std::tuple_cat(std::tuple<FIRST>(first.Get()), others.Get());
+ } else {
+ return std::tuple<FIRST>(first.Get());
+ }
+ }
+};
+
+} // namespace tint::bytes
+
+#endif // SRC_TINT_UTILS_BYTES_DECODER_H_
diff --git a/src/tint/utils/bytes/decoder_test.cc b/src/tint/utils/bytes/decoder_test.cc
new file mode 100644
index 0000000..cce8e5a
--- /dev/null
+++ b/src/tint/utils/bytes/decoder_test.cc
@@ -0,0 +1,150 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/utils/bytes/decoder.h"
+
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <utility>
+
+#include "gmock/gmock.h"
+
+namespace tint::bytes {
+namespace {
+
+template <typename... ARGS>
+auto Data(ARGS&&... args) {
+ return std::array{std::byte{static_cast<uint8_t>(args)}...};
+}
+
+TEST(BytesDecoderTest, Uint8) {
+ auto data = Data(0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80);
+ auto reader = Reader{Slice{data}, 0, Endianness::kLittle};
+ EXPECT_EQ(Decode<uint8_t>(reader).Get(), 0x10u);
+ EXPECT_EQ(Decode<uint8_t>(reader).Get(), 0x20u);
+ EXPECT_EQ(Decode<uint8_t>(reader).Get(), 0x30u);
+ EXPECT_EQ(Decode<uint8_t>(reader).Get(), 0x40u);
+ EXPECT_EQ(Decode<uint8_t>(reader).Get(), 0x50u);
+ EXPECT_EQ(Decode<uint8_t>(reader).Get(), 0x60u);
+ EXPECT_EQ(Decode<uint8_t>(reader).Get(), 0x70u);
+ EXPECT_EQ(Decode<uint8_t>(reader).Get(), 0x80u);
+ EXPECT_FALSE(Decode<uint8_t>(reader));
+}
+
+TEST(BytesDecoderTest, Uint16) {
+ auto data = Data(0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80);
+ auto reader = Reader{Slice{data}, 0, Endianness::kLittle};
+ EXPECT_EQ(Decode<uint16_t>(reader).Get(), 0x2010u);
+ EXPECT_EQ(Decode<uint16_t>(reader).Get(), 0x4030u);
+ EXPECT_EQ(Decode<uint16_t>(reader).Get(), 0x6050u);
+ EXPECT_EQ(Decode<uint16_t>(reader).Get(), 0x8070u);
+ EXPECT_FALSE(Decode<uint16_t>(reader));
+}
+
+TEST(BytesDecoderTest, Uint32) {
+ auto data = Data(0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80);
+ auto reader = Reader{Slice{data}, 0, Endianness::kBig};
+ EXPECT_EQ(Decode<uint32_t>(reader).Get(), 0x10203040u);
+ EXPECT_EQ(Decode<uint32_t>(reader).Get(), 0x50607080u);
+ EXPECT_FALSE(Decode<uint32_t>(reader));
+}
+
+TEST(BytesDecoderTest, Float) {
+ auto data = Data(0x00, 0x00, 0x08, 0x41);
+ auto reader = Reader{Slice{data}};
+ EXPECT_EQ(Decode<float>(reader).Get(), 8.5f);
+ EXPECT_FALSE(Decode<float>(reader));
+}
+
+TEST(BytesDecoderTest, Bool) {
+ auto data = Data(0x0, 0x1, 0x2, 0x1, 0x0);
+ auto reader = Reader{Slice{data}};
+ EXPECT_EQ(Decode<bool>(reader).Get(), false);
+ EXPECT_EQ(Decode<bool>(reader).Get(), true);
+ EXPECT_EQ(Decode<bool>(reader).Get(), true);
+ EXPECT_EQ(Decode<bool>(reader).Get(), true);
+ EXPECT_EQ(Decode<bool>(reader).Get(), false);
+ EXPECT_FALSE(Decode<bool>(reader));
+}
+
+TEST(BytesDecoderTest, String) {
+ auto data = Data(0x0, 0x5, 'h', 'e', 'l', 'l', 'o', 0x0, 0x5, 'w', 'o', 'r', 'l', 'd');
+ auto reader = Reader{Slice{data}, 0, Endianness::kBig};
+ EXPECT_EQ(Decode<std::string>(reader).Get(), "hello");
+ EXPECT_EQ(Decode<std::string>(reader).Get(), "world");
+ EXPECT_FALSE(Decode<std::string>(reader));
+}
+
+struct S {
+ uint8_t a;
+ uint16_t b;
+ uint32_t c;
+ TINT_REFLECT(a, b, c);
+};
+
+TEST(BytesDecoderTest, ReflectedObject) {
+ auto data = Data(0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80);
+ auto reader = Reader{Slice{data}, 0, Endianness::kBig};
+ auto got = Decode<S>(reader);
+ EXPECT_EQ(got->a, 0x10u);
+ EXPECT_EQ(got->b, 0x2030u);
+ EXPECT_EQ(got->c, 0x40506070u);
+ EXPECT_FALSE(Decode<S>(reader));
+}
+
+TEST(BytesDecoderTest, UnorderedMap) {
+ using M = std::unordered_map<uint8_t, uint16_t>;
+ auto data = Data(0x00, 0x10, 0x02, 0x20, //
+ 0x00, 0x30, 0x04, 0x40, //
+ 0x00, 0x50, 0x06, 0x60, //
+ 0x00, 0x70, 0x08, 0x80, //
+ 0x01);
+ auto reader = Reader{Slice{data}, 0, Endianness::kBig};
+ auto got = Decode<M>(reader);
+ EXPECT_THAT(got.Get(), testing::ContainerEq(M{
+ std::pair<uint8_t, uint32_t>(0x10u, 0x0220u),
+ std::pair<uint8_t, uint32_t>(0x30u, 0x0440u),
+ std::pair<uint8_t, uint32_t>(0x50u, 0x0660u),
+ std::pair<uint8_t, uint32_t>(0x70u, 0x0880u),
+ }));
+ EXPECT_FALSE(Decode<M>(reader));
+}
+
+TEST(BytesDecoderTest, Tuple) {
+ using T = std::tuple<uint8_t, uint16_t, uint32_t>;
+ auto data = Data(0x10, //
+ 0x20, 0x30, //
+ 0x40, 0x50, 0x60, 0x70, //
+ 0x80);
+ auto reader = Reader{Slice{data}, 0, Endianness::kBig};
+ EXPECT_THAT(Decode<T>(reader).Get(), (T{0x10u, 0x2030u, 0x40506070u}));
+ EXPECT_FALSE(Decode<T>(reader));
+}
+
+} // namespace
+} // namespace tint::bytes
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/utils/bytes/endianness.h
similarity index 65%
copy from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
copy to src/tint/utils/bytes/endianness.h
index 6f0f657..81db319 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/utils/bytes/endianness.h
@@ -25,28 +25,23 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
-#define SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#ifndef SRC_TINT_UTILS_BYTES_ENDIANNESS_H_
+#define SRC_TINT_UTILS_BYTES_ENDIANNESS_H_
-#include <string>
+#include <cstdint>
+#include <cstring>
-#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/result/result.h"
+namespace tint::bytes {
-// Forward declarations.
-namespace tint::core::ir {
-class Module;
+enum class Endianness : uint8_t { kBig, kLittle };
+
+inline Endianness NativeEndianness() {
+ uint8_t u8[4];
+ uint32_t u32 = 0x01020304;
+ memcpy(u8, &u32, 4);
+ return u8[0] == 1 ? Endianness::kBig : Endianness::kLittle;
}
-namespace tint::wgsl::writer {
+} // namespace tint::bytes
-/// RenameConflicts is a transform that renames declarations which prevent identifiers from
-/// resolving to the correct declaration, and those with identical identifiers declared in the same
-/// scope.
-/// @param module the module to transform
-/// @returns success or failure
-Result<SuccessType> RenameConflicts(core::ir::Module* module);
-
-} // namespace tint::wgsl::writer
-
-#endif // SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#endif // SRC_TINT_UTILS_BYTES_ENDIANNESS_H_
diff --git a/src/tint/utils/bytes/reader.h b/src/tint/utils/bytes/reader.h
new file mode 100644
index 0000000..38bbf4e
--- /dev/null
+++ b/src/tint/utils/bytes/reader.h
@@ -0,0 +1,140 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_UTILS_BYTES_READER_H_
+#define SRC_TINT_UTILS_BYTES_READER_H_
+
+#include <algorithm>
+#include <cstdint>
+#include <string>
+
+#include "src/tint/utils/bytes/endianness.h"
+#include "src/tint/utils/bytes/swap.h"
+#include "src/tint/utils/containers/slice.h"
+#include "src/tint/utils/reflection/reflection.h"
+
+namespace tint::bytes {
+
+/// A binary stream reader.
+struct Reader {
+ /// @returns true if there are no more bytes remaining
+ bool IsEOF() const { return offset >= bytes.len; }
+
+ /// @returns the number of bytes remaining in the stream
+ size_t BytesRemaining() const { return IsEOF() ? 0 : bytes.len - offset; }
+
+ /// Reads an integer from the stream, performing byte swapping if the stream's endianness
+ /// differs from the native endianness. If there are too few bytes remaining in the stream, then
+ /// the missing data will be substituted with zeros.
+ /// @return the deserialized integer
+ template <typename T>
+ T Int() {
+ static_assert(std::is_integral_v<T>);
+ T out = 0;
+ if (!IsEOF()) {
+ size_t n = std::min(sizeof(T), BytesRemaining());
+ memcpy(&out, &bytes[offset], n);
+ offset += n;
+ if (NativeEndianness() != endianness) {
+ out = Swap(out);
+ }
+ }
+ return out;
+ }
+
+ /// Reads a float from the stream. If there are too few bytes remaining in the stream, then
+ /// the missing data will be substituted with zeros.
+ /// @return the deserialized floating point number
+ template <typename T>
+ T Float() {
+ static_assert(std::is_floating_point_v<T>);
+ T out = 0;
+ if (!IsEOF()) {
+ size_t n = std::min(sizeof(T), BytesRemaining());
+ memcpy(&out, &bytes[offset], n);
+ offset += n;
+ }
+ return out;
+ }
+
+ /// Reads a boolean from the stream
+ /// @returns true if the next byte is non-zero
+ bool Bool() {
+ if (IsEOF()) {
+ return false;
+ }
+ return bytes[offset++] != std::byte{0};
+ }
+
+ /// Reads a string of @p len bytes from the stream. If there are too few bytes remaining in the
+ /// stream, then the returned string will be truncated.
+ /// @param len the length of the returned string in bytes
+ /// @return the deserialized string
+ std::string String(size_t len) {
+ if (IsEOF()) {
+ return "";
+ }
+ size_t n = std::min(len, BytesRemaining());
+ std::string out(reinterpret_cast<const char*>(&bytes[offset]), n);
+ offset += n;
+ return out;
+ }
+
+ /// The data to read from
+ Slice<const std::byte> bytes;
+
+ /// The current byte offset
+ size_t offset = 0;
+
+ /// The endianness of integers serialized in the stream
+ Endianness endianness = Endianness::kLittle;
+};
+
+/// Reads the templated type from the reader and assigns it to @p out
+/// @note This function does not
+template <typename T>
+Reader& operator>>(Reader& reader, T& out) {
+ constexpr bool is_numeric = std::is_integral_v<T> || std::is_floating_point_v<T>;
+ static_assert(is_numeric);
+
+ if constexpr (std::is_integral_v<T>) {
+ out = reader.Int<T>();
+ return reader;
+ }
+
+ if constexpr (std::is_floating_point_v<T>) {
+ out = reader.Float<T>();
+ return reader;
+ }
+
+ // Unreachable
+ return reader;
+}
+
+} // namespace tint::bytes
+
+#endif // SRC_TINT_UTILS_BYTES_READER_H_
diff --git a/src/tint/utils/bytes/reader_test.cc b/src/tint/utils/bytes/reader_test.cc
new file mode 100644
index 0000000..e8af39d
--- /dev/null
+++ b/src/tint/utils/bytes/reader_test.cc
@@ -0,0 +1,107 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/utils/bytes/reader.h"
+
+#include "gtest/gtest.h"
+
+namespace tint::bytes {
+namespace {
+
+template <typename... ARGS>
+auto Data(ARGS&&... args) {
+ return std::array{std::byte{static_cast<uint8_t>(args)}...};
+}
+
+TEST(BytesReaderTest, IntegerBigEndian) {
+ auto data = Data(0x10, 0x20, 0x30, 0x40);
+ auto u32 = Reader{Slice{data}, 0, Endianness::kBig}.Int<uint32_t>();
+ EXPECT_EQ(u32, 0x10203040u);
+ auto i32 = Reader{Slice{data}, 0, Endianness::kBig}.Int<int32_t>();
+ EXPECT_EQ(i32, 0x10203040);
+}
+
+TEST(BytesReaderTest, IntegerBigEndian_Offset) {
+ auto data = Data(0x10, 0x20, 0x30, 0x40, 0x50, 0x60);
+ auto u32 = Reader{Slice{data}, 2, Endianness::kBig}.Int<uint32_t>();
+ EXPECT_EQ(u32, 0x30405060u);
+ auto i32 = Reader{Slice{data}, 2, Endianness::kBig}.Int<int32_t>();
+ EXPECT_EQ(i32, 0x30405060);
+}
+
+TEST(BytesReaderTest, IntegerBigEndian_Clipped) {
+ auto data = Data(0x10, 0x20, 0x30, 0x40);
+ auto u32 = Reader{Slice{data}, 2, Endianness::kBig}.Int<uint32_t>();
+ EXPECT_EQ(u32, 0x30400000u);
+ auto i32 = Reader{Slice{data}, 2, Endianness::kBig}.Int<int32_t>();
+ EXPECT_EQ(i32, 0x30400000);
+}
+
+TEST(BytesReaderTest, IntegerLittleEndian) {
+ auto data = Data(0x10, 0x20, 0x30, 0x40);
+ auto u32 = Reader{Slice{data}, 0, Endianness::kLittle}.Int<uint32_t>();
+ EXPECT_EQ(u32, 0x40302010u);
+ auto i32 = Reader{Slice{data}, 0, Endianness::kLittle}.Int<int32_t>();
+ EXPECT_EQ(i32, 0x40302010);
+}
+
+TEST(BytesReaderTest, IntegerLittleEndian_Offset) {
+ auto data = Data(0x10, 0x20, 0x30, 0x40, 0x50, 0x60);
+ auto u32 = Reader{Slice{data}, 2, Endianness::kLittle}.Int<uint32_t>();
+ EXPECT_EQ(u32, 0x60504030u);
+ auto i32 = Reader{Slice{data}, 2, Endianness::kLittle}.Int<int32_t>();
+ EXPECT_EQ(i32, 0x60504030);
+}
+
+TEST(BytesReaderTest, IntegerLittleEndian_Clipped) {
+ auto data = Data(0x10, 0x20, 0x30, 0x40);
+ auto u32 = Reader{Slice{data}, 2, Endianness::kLittle}.Int<uint32_t>();
+ EXPECT_EQ(u32, 0x00004030u);
+ auto i32 = Reader{Slice{data}, 2, Endianness::kLittle}.Int<int32_t>();
+ EXPECT_EQ(i32, 0x00004030);
+}
+
+TEST(BytesReaderTest, Float) {
+ auto data = Data(0x00, 0x00, 0x08, 0x41);
+ float f32 = Reader{Slice{data}}.Float<float>();
+ EXPECT_EQ(f32, 8.5f);
+}
+
+TEST(BytesReaderTest, Float_Offset) {
+ auto data = Data(0x00, 0x00, 0x08, 0x41, 0x80, 0x3e);
+ float f32 = Reader{Slice{data}, 2}.Float<float>();
+ EXPECT_EQ(f32, 0.25049614f);
+}
+
+TEST(BytesReaderTest, Float_Clipped) {
+ auto data = Data(0x00, 0x00, 0x08, 0x41);
+ float f32 = Reader{Slice{data}, 2}.Float<float>();
+ EXPECT_EQ(f32, 2.3329e-41f);
+}
+
+} // namespace
+} // namespace tint::bytes
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/utils/bytes/swap.h
similarity index 65%
copy from src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
copy to src/tint/utils/bytes/swap.h
index 6f0f657..da4c6e6 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/utils/bytes/swap.h
@@ -25,28 +25,31 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
-#define SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#ifndef SRC_TINT_UTILS_BYTES_SWAP_H_
+#define SRC_TINT_UTILS_BYTES_SWAP_H_
-#include <string>
+#include <cstdint>
+#include <cstring>
+#include <type_traits>
+#include <utility>
-#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/result/result.h"
+namespace tint::bytes {
-// Forward declarations.
-namespace tint::core::ir {
-class Module;
+/// @return the input integer value with all bytes reversed
+/// @param value the input value
+template <typename T>
+[[nodiscard]] inline T Swap(T value) {
+ static_assert(std::is_integral_v<T>);
+ uint8_t bytes[sizeof(T)];
+ memcpy(bytes, &value, sizeof(T));
+ for (size_t i = 0; i < sizeof(T) / 2; i++) {
+ std::swap(bytes[i], bytes[sizeof(T) - i - 1]);
+ }
+ T out;
+ memcpy(&out, bytes, sizeof(T));
+ return out;
}
-namespace tint::wgsl::writer {
+} // namespace tint::bytes
-/// RenameConflicts is a transform that renames declarations which prevent identifiers from
-/// resolving to the correct declaration, and those with identical identifiers declared in the same
-/// scope.
-/// @param module the module to transform
-/// @returns success or failure
-Result<SuccessType> RenameConflicts(core::ir::Module* module);
-
-} // namespace tint::wgsl::writer
-
-#endif // SRC_TINT_LANG_WGSL_WRITER_IR_TO_PROGRAM_RENAME_CONFLICTS_H_
+#endif // SRC_TINT_UTILS_BYTES_SWAP_H_
diff --git a/src/tint/utils/bytes/swap_test.cc b/src/tint/utils/bytes/swap_test.cc
new file mode 100644
index 0000000..5d950c0
--- /dev/null
+++ b/src/tint/utils/bytes/swap_test.cc
@@ -0,0 +1,54 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/utils/bytes/swap.h"
+
+#include "gtest/gtest.h"
+
+namespace tint::bytes {
+namespace {
+
+TEST(BytesSwapTest, Uint) {
+ EXPECT_EQ(Swap<uint8_t>(0x41), static_cast<uint8_t>(0x41));
+ EXPECT_EQ(Swap<uint16_t>(0x4152), static_cast<uint16_t>(0x5241));
+ EXPECT_EQ(Swap<uint32_t>(0x41526374), static_cast<uint32_t>(0x74635241));
+ EXPECT_EQ(Swap<uint64_t>(0x415263748596A7B8), static_cast<uint64_t>(0xB8A7968574635241));
+}
+
+TEST(BytesSwapTest, Sint) {
+ EXPECT_EQ(Swap<int8_t>(0x41), static_cast<int8_t>(0x41));
+ EXPECT_EQ(Swap<int8_t>(-0x41), static_cast<int8_t>(-0x41));
+ EXPECT_EQ(Swap<int16_t>(0x4152), static_cast<int16_t>(0x5241));
+ EXPECT_EQ(Swap<int16_t>(-0x4152), static_cast<int16_t>(0xAEBE));
+ EXPECT_EQ(Swap<int32_t>(0x41526374), static_cast<int32_t>(0x74635241));
+ EXPECT_EQ(Swap<int32_t>(-0x41526374), static_cast<int32_t>(0x8C9CADBE));
+ EXPECT_EQ(Swap<int64_t>(0x415263748596A7B8), static_cast<int64_t>(0xB8A7968574635241));
+ EXPECT_EQ(Swap<int64_t>(-0x415263748596A7B8), static_cast<int64_t>(0x4858697A8B9CADBE));
+}
+
+} // namespace
+} // namespace tint::bytes
diff --git a/src/tint/utils/cli/cli.h b/src/tint/utils/cli/cli.h
index b315884..b0e89e4 100644
--- a/src/tint/utils/cli/cli.h
+++ b/src/tint/utils/cli/cli.h
@@ -282,13 +282,13 @@
auto arg = arguments.front();
if constexpr (is_number) {
- auto result = ParseNumber<T>(arg);
+ auto result = strconv::ParseNumber<T>(arg);
if (result) {
value = result.Get();
arguments.pop_front();
return Success;
}
- if (result.Failure() == ParseNumberError::kResultOutOfRange) {
+ if (result.Failure() == strconv::ParseNumberError::kResultOutOfRange) {
return ErrInvalidArgument(arg, "value out of range");
}
return ErrInvalidArgument(arg, "failed to parse value");
diff --git a/src/tint/utils/command/BUILD.bazel b/src/tint/utils/command/BUILD.bazel
index f3388db..ffcef85 100644
--- a/src/tint/utils/command/BUILD.bazel
+++ b/src/tint/utils/command/BUILD.bazel
@@ -40,17 +40,17 @@
name = "command",
srcs = [
] + select({
- ":_not_is_linux__and__not_is_mac__and__not_is_win_": [
+ ":_not_tint_build_is_linux__and__not_tint_build_is_mac__and__not_tint_build_is_win_": [
"command_other.cc",
],
"//conditions:default": [],
}) + select({
- ":is_linux_or_is_mac": [
+ ":tint_build_is_linux_or_tint_build_is_mac": [
"command_posix.cc",
],
"//conditions:default": [],
}) + select({
- ":is_win": [
+ ":tint_build_is_win": [
"command_windows.cc",
],
"//conditions:default": [],
@@ -80,49 +80,49 @@
)
alias(
- name = "is_linux",
- actual = "//src/tint:is_linux_true",
+ name = "tint_build_is_linux",
+ actual = "//src/tint:tint_build_is_linux_true",
)
alias(
- name = "_not_is_linux_",
- actual = "//src/tint:is_linux_false",
+ name = "_not_tint_build_is_linux_",
+ actual = "//src/tint:tint_build_is_linux_false",
)
alias(
- name = "is_mac",
- actual = "//src/tint:is_mac_true",
+ name = "tint_build_is_mac",
+ actual = "//src/tint:tint_build_is_mac_true",
)
alias(
- name = "_not_is_mac_",
- actual = "//src/tint:is_mac_false",
+ name = "_not_tint_build_is_mac_",
+ actual = "//src/tint:tint_build_is_mac_false",
)
alias(
- name = "is_win",
- actual = "//src/tint:is_win_true",
+ name = "tint_build_is_win",
+ actual = "//src/tint:tint_build_is_win_true",
)
alias(
- name = "_not_is_win_",
- actual = "//src/tint:is_win_false",
+ name = "_not_tint_build_is_win_",
+ actual = "//src/tint:tint_build_is_win_false",
)
selects.config_setting_group(
- name = "is_linux_or_is_mac",
+ name = "tint_build_is_linux_or_tint_build_is_mac",
match_any = [
- "is_linux",
- "is_mac",
+ "tint_build_is_linux",
+ "tint_build_is_mac",
],
)
selects.config_setting_group(
- name = "_not_is_linux__and__not_is_mac__and__not_is_win_",
+ name = "_not_tint_build_is_linux__and__not_tint_build_is_mac__and__not_tint_build_is_win_",
match_all = [
- ":_not_is_linux_",
- ":_not_is_mac_",
- ":_not_is_win_",
+ ":_not_tint_build_is_linux_",
+ ":_not_tint_build_is_mac_",
+ ":_not_tint_build_is_win_",
],
)
diff --git a/src/tint/utils/command/BUILD.cmake b/src/tint/utils/command/BUILD.cmake
index 51778af..4e40cc0 100644
--- a/src/tint/utils/command/BUILD.cmake
+++ b/src/tint/utils/command/BUILD.cmake
@@ -47,23 +47,23 @@
tint_utils_text
)
-if((NOT IS_LINUX) AND (NOT IS_MAC) AND (NOT IS_WIN))
+if((NOT TINT_BUILD_IS_LINUX) AND (NOT TINT_BUILD_IS_MAC) AND (NOT TINT_BUILD_IS_WIN))
tint_target_add_sources(tint_utils_command lib
"utils/command/command_other.cc"
)
-endif((NOT IS_LINUX) AND (NOT IS_MAC) AND (NOT IS_WIN))
+endif((NOT TINT_BUILD_IS_LINUX) AND (NOT TINT_BUILD_IS_MAC) AND (NOT TINT_BUILD_IS_WIN))
-if(IS_LINUX OR IS_MAC)
+if(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
tint_target_add_sources(tint_utils_command lib
"utils/command/command_posix.cc"
)
-endif(IS_LINUX OR IS_MAC)
+endif(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
-if(IS_WIN)
+if(TINT_BUILD_IS_WIN)
tint_target_add_sources(tint_utils_command lib
"utils/command/command_windows.cc"
)
-endif(IS_WIN)
+endif(TINT_BUILD_IS_WIN)
################################################################################
# Target: tint_utils_command_test
diff --git a/src/tint/utils/command/BUILD.gn b/src/tint/utils/command/BUILD.gn
index 898eebe..4f42d68 100644
--- a/src/tint/utils/command/BUILD.gn
+++ b/src/tint/utils/command/BUILD.gn
@@ -49,15 +49,15 @@
"${tint_src_dir}/utils/text",
]
- if (!is_linux && !is_mac && !is_win) {
+ if (!tint_build_is_linux && !tint_build_is_mac && !tint_build_is_win) {
sources += [ "command_other.cc" ]
}
- if (is_linux || is_mac) {
+ if (tint_build_is_linux || tint_build_is_mac) {
sources += [ "command_posix.cc" ]
}
- if (is_win) {
+ if (tint_build_is_win) {
sources += [ "command_windows.cc" ]
}
}
diff --git a/src/tint/utils/command/command_other.cc b/src/tint/utils/command/command_other.cc
index 2e47a8b..49a090a 100644
--- a/src/tint/utils/command/command_other.cc
+++ b/src/tint/utils/command/command_other.cc
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// GEN_BUILD:CONDITION((!is_linux) && (!is_mac) && (!is_win))
+// GEN_BUILD:CONDITION((!tint_build_is_linux) && (!tint_build_is_mac) && (!tint_build_is_win))
#include "src/tint/utils/command/command.h"
diff --git a/src/tint/utils/command/command_posix.cc b/src/tint/utils/command/command_posix.cc
index cf9219f..61bb0b1 100644
--- a/src/tint/utils/command/command_posix.cc
+++ b/src/tint/utils/command/command_posix.cc
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// GEN_BUILD:CONDITION(is_linux || is_mac)
+// GEN_BUILD:CONDITION(tint_build_is_linux || tint_build_is_mac)
#include "src/tint/utils/command/command.h"
diff --git a/src/tint/utils/command/command_windows.cc b/src/tint/utils/command/command_windows.cc
index 0c12bc8..2916d9a 100644
--- a/src/tint/utils/command/command_windows.cc
+++ b/src/tint/utils/command/command_windows.cc
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// GEN_BUILD:CONDITION(is_win)
+// GEN_BUILD:CONDITION(tint_build_is_win)
#include "src/tint/utils/command/command.h"
diff --git a/src/tint/utils/containers/BUILD.bazel b/src/tint/utils/containers/BUILD.bazel
index c143cd7..36431b1 100644
--- a/src/tint/utils/containers/BUILD.bazel
+++ b/src/tint/utils/containers/BUILD.bazel
@@ -43,6 +43,7 @@
],
hdrs = [
"bitset.h",
+ "const_propagating_ptr.h",
"enum_set.h",
"hashmap.h",
"hashmap_base.h",
@@ -93,6 +94,7 @@
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
"//src/tint/lang/wgsl/program",
"//src/tint/lang/wgsl/sem",
"//src/tint/utils/containers",
diff --git a/src/tint/utils/containers/BUILD.cmake b/src/tint/utils/containers/BUILD.cmake
index b7de673..b5bbaae 100644
--- a/src/tint/utils/containers/BUILD.cmake
+++ b/src/tint/utils/containers/BUILD.cmake
@@ -40,6 +40,7 @@
################################################################################
tint_add_target(tint_utils_containers lib
utils/containers/bitset.h
+ utils/containers/const_propagating_ptr.h
utils/containers/containers.cc
utils/containers/enum_set.h
utils/containers/hashmap.h
@@ -92,6 +93,7 @@
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
+ tint_lang_wgsl_features
tint_lang_wgsl_program
tint_lang_wgsl_sem
tint_utils_containers
diff --git a/src/tint/utils/containers/BUILD.gn b/src/tint/utils/containers/BUILD.gn
index 0d47ff8..be16640 100644
--- a/src/tint/utils/containers/BUILD.gn
+++ b/src/tint/utils/containers/BUILD.gn
@@ -45,6 +45,7 @@
libtint_source_set("containers") {
sources = [
"bitset.h",
+ "const_propagating_ptr.h",
"containers.cc",
"enum_set.h",
"hashmap.h",
@@ -94,6 +95,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
"${tint_src_dir}/lang/wgsl/program",
"${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils/containers",
diff --git a/src/tint/utils/containers/const_propagating_ptr.h b/src/tint/utils/containers/const_propagating_ptr.h
new file mode 100644
index 0000000..873ce39
--- /dev/null
+++ b/src/tint/utils/containers/const_propagating_ptr.h
@@ -0,0 +1,114 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_UTILS_CONTAINERS_CONST_PROPAGATING_PTR_H_
+#define SRC_TINT_UTILS_CONTAINERS_CONST_PROPAGATING_PTR_H_
+
+namespace tint {
+
+/// ConstPropagatingPtr is a `const` propagating pointer - if the ConstPropagatingPtr is const, then
+/// you will only be able to obtain a const pointee pointer.
+template <typename T>
+class ConstPropagatingPtr {
+ public:
+ /// Constructor.
+ /// The pointer is initialized to null.
+ ConstPropagatingPtr() : ptr_(nullptr) {}
+
+ /// Constructor.
+ /// @param ptr the pointer value.
+ ConstPropagatingPtr(T* ptr) : ptr_(ptr) {} // NOLINT(runtime/explicit)
+
+ /// Move constructor.
+ /// @param other the ConstPropagatingPtr to move.
+ ConstPropagatingPtr(ConstPropagatingPtr&& other) = default;
+
+ /// Copy (non-const) constructor.
+ /// @param other the ConstPropagatingPtr to move.
+ ConstPropagatingPtr(ConstPropagatingPtr& other) : ptr_(other.ptr_) {}
+
+ /// Assignment operator
+ /// @param ptr the new pointer value
+ /// @return this ConstPropagatingPtr
+ ConstPropagatingPtr& operator=(T* ptr) {
+ ptr_ = ptr;
+ return *this;
+ }
+
+ /// Move assignment operator.
+ /// @param other the ConstPropagatingPtr to move.
+ /// @return this ConstPropagatingPtr
+ ConstPropagatingPtr& operator=(ConstPropagatingPtr&& other) = default;
+
+ /// Copy (non-const) assignment operator.
+ /// @param other the ConstPropagatingPtr to move.
+ /// @return this ConstPropagatingPtr
+ ConstPropagatingPtr& operator=(ConstPropagatingPtr& other) {
+ ptr_ = other.ptr_;
+ return *this;
+ }
+
+ /// @returns the pointer
+ operator T*() { return ptr_; }
+
+ /// @returns the const pointer
+ operator const T*() const { return ptr_; }
+
+ /// @returns the pointer
+ T* operator->() { return ptr_; }
+
+ /// @returns the const pointer
+ const T* operator->() const { return ptr_; }
+
+ /// @returns the pointer
+ T* Get() { return ptr_; }
+
+ /// @returns the const pointer
+ const T* Get() const { return ptr_; }
+
+ /// Equality operator
+ /// @param ptr the pointer to compare against
+ /// @return true if the pointers are equal
+ bool operator==(T* ptr) const { return ptr_ == ptr; }
+
+ /// Inequality operator
+ /// @param ptr the pointer to compare against
+ /// @return true if the pointers are not equal
+ bool operator!=(T* ptr) const { return ptr_ != ptr; }
+
+ private:
+ // Delete copy constructor and copy-assignment to prevent making a copy of the
+ // ConstPropagatingPtr to break const propagation.
+ ConstPropagatingPtr(const ConstPropagatingPtr&) = delete;
+ ConstPropagatingPtr& operator=(const ConstPropagatingPtr&) = delete;
+
+ T* ptr_ = nullptr;
+};
+
+} // namespace tint
+
+#endif // SRC_TINT_UTILS_CONTAINERS_CONST_PROPAGATING_PTR_H_
diff --git a/src/tint/utils/containers/slice.h b/src/tint/utils/containers/slice.h
index f2cf7c3..3c60913 100644
--- a/src/tint/utils/containers/slice.h
+++ b/src/tint/utils/containers/slice.h
@@ -28,6 +28,7 @@
#ifndef SRC_TINT_UTILS_CONTAINERS_SLICE_H_
#define SRC_TINT_UTILS_CONTAINERS_SLICE_H_
+#include <array>
#include <cstdint>
#include <iterator>
@@ -158,6 +159,12 @@
constexpr Slice(T (&elements)[N]) // NOLINT
: data(elements), len(N), cap(N) {}
+ /// Constructor
+ /// @param array std::array of elements
+ template <size_t N>
+ constexpr Slice(std::array<T, N>& array) // NOLINT
+ : data(array.data()), len(N), cap(N) {}
+
/// Reinterprets this slice as `const Slice<TO>&`
/// @returns the reinterpreted slice
/// @see CanReinterpretSlice
diff --git a/src/tint/utils/containers/slice_test.cc b/src/tint/utils/containers/slice_test.cc
index 2432aeb..01932fd 100644
--- a/src/tint/utils/containers/slice_test.cc
+++ b/src/tint/utils/containers/slice_test.cc
@@ -118,6 +118,16 @@
EXPECT_FALSE(slice.IsEmpty());
}
+TEST(TintSliceTest, CtorStdArray) {
+ std::array elements{1, 2, 3};
+
+ auto slice = Slice{elements};
+ EXPECT_EQ(slice.data, &elements[0]);
+ EXPECT_EQ(slice.len, 3u);
+ EXPECT_EQ(slice.cap, 3u);
+ EXPECT_FALSE(slice.IsEmpty());
+}
+
TEST(TintSliceTest, Index) {
int elements[] = {1, 2, 3};
diff --git a/src/tint/utils/containers/vector.h b/src/tint/utils/containers/vector.h
index deae6fe..663e310 100644
--- a/src/tint/utils/containers/vector.h
+++ b/src/tint/utils/containers/vector.h
@@ -343,7 +343,7 @@
/// Move constructor
/// @param other the vector to move
- Vector(Vector&& other) { MoveOrCopy(VectorRef<T>(std::move(other))); }
+ Vector(Vector&& other) { Move(std::move(other)); }
/// Copy constructor (differing N length)
/// @param other the vector to copy
@@ -356,7 +356,7 @@
/// @param other the vector to move
template <size_t N2>
Vector(Vector<T, N2>&& other) {
- MoveOrCopy(VectorRef<T>(std::move(other)));
+ Move(std::move(other));
}
/// Copy constructor with covariance / const conversion
@@ -378,7 +378,7 @@
ReinterpretMode MODE,
typename = std::enable_if_t<CanReinterpretSlice<MODE, T, U>>>
Vector(Vector<U, N2>&& other) { // NOLINT(runtime/explicit)
- MoveOrCopy(VectorRef<T>(std::move(other)));
+ Move(std::move(other));
}
/// Move constructor from a mutable vector reference
@@ -391,7 +391,24 @@
/// Copy constructor from an immutable slice
/// @param other the slice to copy
- Vector(const Slice<T>& other) { Copy(other); } // NOLINT(runtime/explicit)
+ Vector(const Slice<T>& other) { // NOLINT(runtime/explicit)
+ Copy(other);
+ }
+
+ /// Copy constructor from an immutable slice
+ /// @param other the slice to copy
+ /// @note This overload only exists to keep MSVC happy. The compiler should be able to match
+ /// `Slice<U>`.
+ Vector(const Slice<const T>& other) { // NOLINT(runtime/explicit)
+ Copy(other);
+ }
+
+ /// Copy constructor from an immutable slice
+ /// @param other the slice to copy
+ template <typename U>
+ Vector(const Slice<U>& other) { // NOLINT(runtime/explicit)
+ Copy(other);
+ }
/// Destructor
~Vector() { ClearAndFree(); }
@@ -411,7 +428,7 @@
/// @returns this vector so calls can be chained
Vector& operator=(Vector&& other) {
if (&other != this) {
- MoveOrCopy(VectorRef<T>(std::move(other)));
+ Move(std::move(other));
}
return *this;
}
@@ -430,7 +447,7 @@
/// @returns this vector so calls can be chained
template <size_t N2>
Vector& operator=(Vector<T, N2>&& other) {
- MoveOrCopy(VectorRef<T>(std::move(other)));
+ Move(std::move(other));
return *this;
}
@@ -824,6 +841,7 @@
/// Moves 'other' to this vector, if possible, otherwise performs a copy.
void MoveOrCopy(VectorRef<T>&& other) {
if (other.can_move_) {
+ // Just steal the slice.
ClearAndFree();
impl_.slice = other.slice_;
other.slice_ = {};
@@ -833,8 +851,9 @@
}
/// Copies all the elements from `other` to this vector, replacing the content of this vector.
- /// @param other the
- void Copy(const tint::Slice<T>& other) {
+ /// @param other the slice to copy
+ template <typename U>
+ void Copy(const tint::Slice<U>& other) {
if (impl_.slice.cap < other.len) {
ClearAndFree();
impl_.Allocate(other.len);
@@ -848,6 +867,41 @@
}
}
+ /// Moves all the elements from `other` to this vector, replacing the content of this vector.
+ /// @param other the vector to move
+ template <typename U, size_t N2>
+ void Move(Vector<U, N2>&& other) {
+ auto& other_slice = other.impl_.slice;
+ if constexpr (std::is_same_v<T, U>) {
+ if (other.impl_.CanMove()) {
+ // Just steal the slice.
+ ClearAndFree();
+ impl_.slice = other_slice;
+ other_slice = {};
+ return;
+ }
+ }
+
+ // Can't steal the slice, so we have to move the elements instead.
+
+ // Ensure we have capacity for all the elements
+ if (impl_.slice.cap < other_slice.len) {
+ ClearAndFree();
+ impl_.Allocate(other_slice.len);
+ } else {
+ Clear();
+ }
+
+ // Move each of the elements.
+ impl_.slice.len = other_slice.len;
+ for (size_t i = 0; i < impl_.slice.len; i++) {
+ new (&impl_.slice.data[i]) T{std::move(other_slice.data[i])};
+ }
+
+ // Clear other
+ other.Clear();
+ }
+
/// Clears the vector, then frees the slice data.
void ClearAndFree() {
Clear();
@@ -1049,8 +1103,8 @@
template <typename U,
size_t N,
typename = std::enable_if_t<CanReinterpretSlice<ReinterpretMode::kSafe, T, U>>>
- VectorRef(Vector<U, N>& vector) // NOLINT(runtime/explicit)
- : slice_(vector.impl_.slice.template Reinterpret<T>()) {}
+ VectorRef(const Vector<U, N>& vector) // NOLINT(runtime/explicit)
+ : slice_(const_cast<tint::Slice<U>&>(vector.impl_.slice).template Reinterpret<T>()) {}
/// Constructor from a moved Vector with covariance / const conversion
/// @param vector the vector to create a reference of
diff --git a/src/tint/utils/diagnostic/BUILD.bazel b/src/tint/utils/diagnostic/BUILD.bazel
index b9e46fb..5cd5f48 100644
--- a/src/tint/utils/diagnostic/BUILD.bazel
+++ b/src/tint/utils/diagnostic/BUILD.bazel
@@ -44,17 +44,17 @@
"printer.cc",
"source.cc",
] + select({
- ":_not_is_linux__and__not_is_mac__and__not_is_win_": [
+ ":_not_tint_build_is_linux__and__not_tint_build_is_mac__and__not_tint_build_is_win_": [
"printer_other.cc",
],
"//conditions:default": [],
}) + select({
- ":is_linux_or_is_mac": [
+ ":tint_build_is_linux_or_tint_build_is_mac": [
"printer_posix.cc",
],
"//conditions:default": [],
}) + select({
- ":is_win": [
+ ":tint_build_is_win": [
"printer_windows.cc",
],
"//conditions:default": [],
@@ -104,49 +104,49 @@
)
alias(
- name = "is_linux",
- actual = "//src/tint:is_linux_true",
+ name = "tint_build_is_linux",
+ actual = "//src/tint:tint_build_is_linux_true",
)
alias(
- name = "_not_is_linux_",
- actual = "//src/tint:is_linux_false",
+ name = "_not_tint_build_is_linux_",
+ actual = "//src/tint:tint_build_is_linux_false",
)
alias(
- name = "is_mac",
- actual = "//src/tint:is_mac_true",
+ name = "tint_build_is_mac",
+ actual = "//src/tint:tint_build_is_mac_true",
)
alias(
- name = "_not_is_mac_",
- actual = "//src/tint:is_mac_false",
+ name = "_not_tint_build_is_mac_",
+ actual = "//src/tint:tint_build_is_mac_false",
)
alias(
- name = "is_win",
- actual = "//src/tint:is_win_true",
+ name = "tint_build_is_win",
+ actual = "//src/tint:tint_build_is_win_true",
)
alias(
- name = "_not_is_win_",
- actual = "//src/tint:is_win_false",
+ name = "_not_tint_build_is_win_",
+ actual = "//src/tint:tint_build_is_win_false",
)
selects.config_setting_group(
- name = "is_linux_or_is_mac",
+ name = "tint_build_is_linux_or_tint_build_is_mac",
match_any = [
- "is_linux",
- "is_mac",
+ "tint_build_is_linux",
+ "tint_build_is_mac",
],
)
selects.config_setting_group(
- name = "_not_is_linux__and__not_is_mac__and__not_is_win_",
+ name = "_not_tint_build_is_linux__and__not_tint_build_is_mac__and__not_tint_build_is_win_",
match_all = [
- ":_not_is_linux_",
- ":_not_is_mac_",
- ":_not_is_win_",
+ ":_not_tint_build_is_linux_",
+ ":_not_tint_build_is_mac_",
+ ":_not_tint_build_is_win_",
],
)
diff --git a/src/tint/utils/diagnostic/BUILD.cmake b/src/tint/utils/diagnostic/BUILD.cmake
index c11c314..37b0742 100644
--- a/src/tint/utils/diagnostic/BUILD.cmake
+++ b/src/tint/utils/diagnostic/BUILD.cmake
@@ -60,23 +60,23 @@
tint_utils_traits
)
-if((NOT IS_LINUX) AND (NOT IS_MAC) AND (NOT IS_WIN))
+if((NOT TINT_BUILD_IS_LINUX) AND (NOT TINT_BUILD_IS_MAC) AND (NOT TINT_BUILD_IS_WIN))
tint_target_add_sources(tint_utils_diagnostic lib
"utils/diagnostic/printer_other.cc"
)
-endif((NOT IS_LINUX) AND (NOT IS_MAC) AND (NOT IS_WIN))
+endif((NOT TINT_BUILD_IS_LINUX) AND (NOT TINT_BUILD_IS_MAC) AND (NOT TINT_BUILD_IS_WIN))
-if(IS_LINUX OR IS_MAC)
+if(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
tint_target_add_sources(tint_utils_diagnostic lib
"utils/diagnostic/printer_posix.cc"
)
-endif(IS_LINUX OR IS_MAC)
+endif(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
-if(IS_WIN)
+if(TINT_BUILD_IS_WIN)
tint_target_add_sources(tint_utils_diagnostic lib
"utils/diagnostic/printer_windows.cc"
)
-endif(IS_WIN)
+endif(TINT_BUILD_IS_WIN)
################################################################################
# Target: tint_utils_diagnostic_test
diff --git a/src/tint/utils/diagnostic/BUILD.gn b/src/tint/utils/diagnostic/BUILD.gn
index 637dc85..4bc6b72 100644
--- a/src/tint/utils/diagnostic/BUILD.gn
+++ b/src/tint/utils/diagnostic/BUILD.gn
@@ -64,15 +64,15 @@
"${tint_src_dir}/utils/traits",
]
- if (!is_linux && !is_mac && !is_win) {
+ if (!tint_build_is_linux && !tint_build_is_mac && !tint_build_is_win) {
sources += [ "printer_other.cc" ]
}
- if (is_linux || is_mac) {
+ if (tint_build_is_linux || tint_build_is_mac) {
sources += [ "printer_posix.cc" ]
}
- if (is_win) {
+ if (tint_build_is_win) {
sources += [ "printer_windows.cc" ]
}
}
diff --git a/src/tint/utils/diagnostic/diagnostic.cc b/src/tint/utils/diagnostic/diagnostic.cc
index 8a51ac9..ff0170c 100644
--- a/src/tint/utils/diagnostic/diagnostic.cc
+++ b/src/tint/utils/diagnostic/diagnostic.cc
@@ -33,13 +33,29 @@
namespace tint::diag {
+namespace {
+size_t CountErrors(VectorRef<Diagnostic> diags) {
+ size_t count = 0;
+ for (auto& diag : diags) {
+ if (diag.severity >= Severity::Error) {
+ count++;
+ }
+ }
+ return count;
+}
+} // namespace
+
Diagnostic::Diagnostic() = default;
Diagnostic::Diagnostic(const Diagnostic&) = default;
Diagnostic::~Diagnostic() = default;
Diagnostic& Diagnostic::operator=(const Diagnostic&) = default;
List::List() = default;
-List::List(std::initializer_list<Diagnostic> list) : entries_(list) {}
+List::List(std::initializer_list<Diagnostic> list)
+ : entries_(list), error_count_(CountErrors(entries_)) {}
+List::List(VectorRef<Diagnostic> list)
+ : entries_(std::move(list)), error_count_(CountErrors(entries_)) {}
+
List::List(const List& rhs) = default;
List::List(List&& rhs) = default;
diff --git a/src/tint/utils/diagnostic/diagnostic.h b/src/tint/utils/diagnostic/diagnostic.h
index 36d6c15..a077f47 100644
--- a/src/tint/utils/diagnostic/diagnostic.h
+++ b/src/tint/utils/diagnostic/diagnostic.h
@@ -108,39 +108,45 @@
/// Constructs the list with no elements.
List();
- /// Copy constructor. Copies the diagnostics from `list` into this list.
+ /// Constructor. Copies the diagnostics from @p list into this list.
/// @param list the list of diagnostics to copy into this list.
List(std::initializer_list<Diagnostic> list);
- /// Copy constructor. Copies the diagnostics from `list` into this list.
+ /// Constructor. Copies the diagnostics from @p list into this list.
+ /// @param list the list of diagnostics to copy into this list.
+ explicit List(VectorRef<Diagnostic> list);
+
+ /// Copy constructor. Copies the diagnostics from @p list into this list.
/// @param list the list of diagnostics to copy into this list.
List(const List& list);
- /// Move constructor. Moves the diagnostics from `list` into this list.
+ /// Move constructor. Moves the diagnostics from @p list into this list.
/// @param list the list of diagnostics to move into this list.
List(List&& list);
/// Destructor
~List();
- /// Assignment operator. Copies the diagnostics from `list` into this list.
+ /// Assignment operator. Copies the diagnostics from @p list into this list.
/// @param list the list to copy into this list.
/// @return this list.
List& operator=(const List& list);
- /// Assignment move operator. Moves the diagnostics from `list` into this
- /// list.
+ /// Assignment move operator. Moves the diagnostics from @p list into this list.
/// @param list the list to move into this list.
/// @return this list.
List& operator=(List&& list);
/// adds a diagnostic to the end of this list.
/// @param diag the diagnostic to append to this list.
- void add(Diagnostic&& diag) {
+ /// @returns a reference to the new diagnostic.
+ /// @note The returned reference must not be used after the list is mutated again.
+ diag::Diagnostic& add(Diagnostic&& diag) {
if (diag.severity >= Severity::Error) {
error_count_++;
}
entries_.Push(std::move(diag));
+ return entries_.Back();
}
/// adds a list of diagnostics to the end of this list.
@@ -155,50 +161,60 @@
/// @param system the system raising the note message
/// @param note_msg the note message
/// @param source the source of the note diagnostic
- void add_note(System system, std::string_view note_msg, const Source& source) {
+ /// @returns a reference to the new diagnostic.
+ /// @note The returned reference must not be used after the list is mutated again.
+ diag::Diagnostic& add_note(System system, std::string_view note_msg, const Source& source) {
diag::Diagnostic note{};
note.severity = diag::Severity::Note;
note.system = system;
note.source = source;
note.message = note_msg;
- add(std::move(note));
+ return add(std::move(note));
}
/// adds the warning message with the given Source to the end of this list.
/// @param system the system raising the warning message
/// @param warning_msg the warning message
/// @param source the source of the warning diagnostic
- void add_warning(System system, std::string_view warning_msg, const Source& source) {
+ /// @returns a reference to the new diagnostic.
+ /// @note The returned reference must not be used after the list is mutated again.
+ diag::Diagnostic& add_warning(System system,
+ std::string_view warning_msg,
+ const Source& source) {
diag::Diagnostic warning{};
warning.severity = diag::Severity::Warning;
warning.system = system;
warning.source = source;
warning.message = warning_msg;
- add(std::move(warning));
+ return add(std::move(warning));
}
/// adds the error message without a source to the end of this list.
/// @param system the system raising the error message
/// @param err_msg the error message
- void add_error(System system, std::string_view err_msg) {
+ /// @returns a reference to the new diagnostic.
+ /// @note The returned reference must not be used after the list is mutated again.
+ diag::Diagnostic& add_error(System system, std::string_view err_msg) {
diag::Diagnostic error{};
error.severity = diag::Severity::Error;
error.system = system;
error.message = err_msg;
- add(std::move(error));
+ return add(std::move(error));
}
/// adds the error message with the given Source to the end of this list.
/// @param system the system raising the error message
/// @param err_msg the error message
/// @param source the source of the error diagnostic
- void add_error(System system, std::string_view err_msg, const Source& source) {
+ /// @returns a reference to the new diagnostic.
+ /// @note The returned reference must not be used after the list is mutated again.
+ diag::Diagnostic& add_error(System system, std::string_view err_msg, const Source& source) {
diag::Diagnostic error{};
error.severity = diag::Severity::Error;
error.system = system;
error.source = source;
error.message = err_msg;
- add(std::move(error));
+ return add(std::move(error));
}
/// adds an internal compiler error message to the end of this list.
@@ -206,17 +222,19 @@
/// @param err_msg the error message
/// @param source the source of the internal compiler error
/// @param file the Source::File owned by this diagnostic
- void add_ice(System system,
- std::string_view err_msg,
- const Source& source,
- std::shared_ptr<Source::File> file) {
+ /// @returns a reference to the new diagnostic.
+ /// @note The returned reference must not be used after the list is mutated again.
+ diag::Diagnostic& add_ice(System system,
+ std::string_view err_msg,
+ const Source& source,
+ std::shared_ptr<Source::File> file) {
diag::Diagnostic ice{};
ice.severity = diag::Severity::InternalCompilerError;
ice.system = system;
ice.source = source;
ice.message = err_msg;
ice.owned_file = std::move(file);
- add(std::move(ice));
+ return add(std::move(ice));
}
/// @returns true iff the diagnostic list contains errors diagnostics (or of
diff --git a/src/tint/utils/diagnostic/diagnostic_test.cc b/src/tint/utils/diagnostic/diagnostic_test.cc
index a27798e..f947b62 100644
--- a/src/tint/utils/diagnostic/diagnostic_test.cc
+++ b/src/tint/utils/diagnostic/diagnostic_test.cc
@@ -33,12 +33,28 @@
namespace tint::diag {
namespace {
+TEST(DiagListTest, CtorInitializerList) {
+ Diagnostic err_a, err_b;
+ err_a.severity = Severity::Error;
+ err_b.severity = Severity::Fatal;
+ List list{err_a, err_b};
+ EXPECT_EQ(list.count(), 2u);
+}
+
+TEST(DiagListTest, CtorVectorRef) {
+ Diagnostic err_a, err_b;
+ err_a.severity = Severity::Error;
+ err_b.severity = Severity::Fatal;
+ List list(Vector{err_a, err_b});
+ EXPECT_EQ(list.count(), 2u);
+}
+
TEST(DiagListTest, OwnedFilesShared) {
auto file = std::make_shared<Source::File>("path", "content");
- diag::List list_a, list_b;
+ List list_a, list_b;
{
- diag::Diagnostic diag{};
+ Diagnostic diag{};
diag.source = Source{Source::Range{{0, 0}}, file.get()};
list_a.add(std::move(diag));
}
diff --git a/src/tint/utils/diagnostic/printer_other.cc b/src/tint/utils/diagnostic/printer_other.cc
index c7d438f..2f93fa7 100644
--- a/src/tint/utils/diagnostic/printer_other.cc
+++ b/src/tint/utils/diagnostic/printer_other.cc
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// GEN_BUILD:CONDITION((!is_linux) && (!is_mac) && (!is_win))
+// GEN_BUILD:CONDITION((!tint_build_is_linux) && (!tint_build_is_mac) && (!tint_build_is_win))
#include <cstring>
diff --git a/src/tint/utils/diagnostic/printer_posix.cc b/src/tint/utils/diagnostic/printer_posix.cc
index 5094681..3c7ba22 100644
--- a/src/tint/utils/diagnostic/printer_posix.cc
+++ b/src/tint/utils/diagnostic/printer_posix.cc
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// GEN_BUILD:CONDITION(is_linux || is_mac)
+// GEN_BUILD:CONDITION(tint_build_is_linux || tint_build_is_mac)
#include <unistd.h>
diff --git a/src/tint/utils/diagnostic/printer_windows.cc b/src/tint/utils/diagnostic/printer_windows.cc
index 5b1e68a..52d3790 100644
--- a/src/tint/utils/diagnostic/printer_windows.cc
+++ b/src/tint/utils/diagnostic/printer_windows.cc
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// GEN_BUILD:CONDITION(is_win)
+// GEN_BUILD:CONDITION(tint_build_is_win)
#include <cstring>
diff --git a/src/tint/utils/file/BUILD.bazel b/src/tint/utils/file/BUILD.bazel
index e5c4357..d74bc23 100644
--- a/src/tint/utils/file/BUILD.bazel
+++ b/src/tint/utils/file/BUILD.bazel
@@ -40,17 +40,17 @@
name = "file",
srcs = [
] + select({
- ":_not_is_linux__and__not_is_mac__and__not_is_win_": [
+ ":_not_tint_build_is_linux__and__not_tint_build_is_mac__and__not_tint_build_is_win_": [
"tmpfile_other.cc",
],
"//conditions:default": [],
}) + select({
- ":is_linux_or_is_mac": [
+ ":tint_build_is_linux_or_tint_build_is_mac": [
"tmpfile_posix.cc",
],
"//conditions:default": [],
}) + select({
- ":is_win": [
+ ":tint_build_is_win": [
"tmpfile_windows.cc",
],
"//conditions:default": [],
@@ -82,49 +82,49 @@
)
alias(
- name = "is_linux",
- actual = "//src/tint:is_linux_true",
+ name = "tint_build_is_linux",
+ actual = "//src/tint:tint_build_is_linux_true",
)
alias(
- name = "_not_is_linux_",
- actual = "//src/tint:is_linux_false",
+ name = "_not_tint_build_is_linux_",
+ actual = "//src/tint:tint_build_is_linux_false",
)
alias(
- name = "is_mac",
- actual = "//src/tint:is_mac_true",
+ name = "tint_build_is_mac",
+ actual = "//src/tint:tint_build_is_mac_true",
)
alias(
- name = "_not_is_mac_",
- actual = "//src/tint:is_mac_false",
+ name = "_not_tint_build_is_mac_",
+ actual = "//src/tint:tint_build_is_mac_false",
)
alias(
- name = "is_win",
- actual = "//src/tint:is_win_true",
+ name = "tint_build_is_win",
+ actual = "//src/tint:tint_build_is_win_true",
)
alias(
- name = "_not_is_win_",
- actual = "//src/tint:is_win_false",
+ name = "_not_tint_build_is_win_",
+ actual = "//src/tint:tint_build_is_win_false",
)
selects.config_setting_group(
- name = "is_linux_or_is_mac",
+ name = "tint_build_is_linux_or_tint_build_is_mac",
match_any = [
- "is_linux",
- "is_mac",
+ "tint_build_is_linux",
+ "tint_build_is_mac",
],
)
selects.config_setting_group(
- name = "_not_is_linux__and__not_is_mac__and__not_is_win_",
+ name = "_not_tint_build_is_linux__and__not_tint_build_is_mac__and__not_tint_build_is_win_",
match_all = [
- ":_not_is_linux_",
- ":_not_is_mac_",
- ":_not_is_win_",
+ ":_not_tint_build_is_linux_",
+ ":_not_tint_build_is_mac_",
+ ":_not_tint_build_is_win_",
],
)
diff --git a/src/tint/utils/file/BUILD.cmake b/src/tint/utils/file/BUILD.cmake
index 93eedbe..0dc6cb8 100644
--- a/src/tint/utils/file/BUILD.cmake
+++ b/src/tint/utils/file/BUILD.cmake
@@ -48,23 +48,23 @@
tint_utils_text
)
-if((NOT IS_LINUX) AND (NOT IS_MAC) AND (NOT IS_WIN))
+if((NOT TINT_BUILD_IS_LINUX) AND (NOT TINT_BUILD_IS_MAC) AND (NOT TINT_BUILD_IS_WIN))
tint_target_add_sources(tint_utils_file lib
"utils/file/tmpfile_other.cc"
)
-endif((NOT IS_LINUX) AND (NOT IS_MAC) AND (NOT IS_WIN))
+endif((NOT TINT_BUILD_IS_LINUX) AND (NOT TINT_BUILD_IS_MAC) AND (NOT TINT_BUILD_IS_WIN))
-if(IS_LINUX OR IS_MAC)
+if(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
tint_target_add_sources(tint_utils_file lib
"utils/file/tmpfile_posix.cc"
)
-endif(IS_LINUX OR IS_MAC)
+endif(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
-if(IS_WIN)
+if(TINT_BUILD_IS_WIN)
tint_target_add_sources(tint_utils_file lib
"utils/file/tmpfile_windows.cc"
)
-endif(IS_WIN)
+endif(TINT_BUILD_IS_WIN)
################################################################################
# Target: tint_utils_file_test
diff --git a/src/tint/utils/file/BUILD.gn b/src/tint/utils/file/BUILD.gn
index 612646c..62e1cdc 100644
--- a/src/tint/utils/file/BUILD.gn
+++ b/src/tint/utils/file/BUILD.gn
@@ -50,15 +50,15 @@
"${tint_src_dir}/utils/text",
]
- if (!is_linux && !is_mac && !is_win) {
+ if (!tint_build_is_linux && !tint_build_is_mac && !tint_build_is_win) {
sources += [ "tmpfile_other.cc" ]
}
- if (is_linux || is_mac) {
+ if (tint_build_is_linux || tint_build_is_mac) {
sources += [ "tmpfile_posix.cc" ]
}
- if (is_win) {
+ if (tint_build_is_win) {
sources += [ "tmpfile_windows.cc" ]
}
}
diff --git a/src/tint/utils/file/tmpfile_other.cc b/src/tint/utils/file/tmpfile_other.cc
index 1fcad3f..d8ecad2 100644
--- a/src/tint/utils/file/tmpfile_other.cc
+++ b/src/tint/utils/file/tmpfile_other.cc
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// GEN_BUILD:CONDITION((!is_linux) && (!is_mac) && (!is_win))
+// GEN_BUILD:CONDITION((!tint_build_is_linux) && (!tint_build_is_mac) && (!tint_build_is_win))
#include "src/tint/utils/file/tmpfile.h"
diff --git a/src/tint/utils/file/tmpfile_posix.cc b/src/tint/utils/file/tmpfile_posix.cc
index 9114ae0..c7b7178 100644
--- a/src/tint/utils/file/tmpfile_posix.cc
+++ b/src/tint/utils/file/tmpfile_posix.cc
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// GEN_BUILD:CONDITION(is_linux || is_mac)
+// GEN_BUILD:CONDITION(tint_build_is_linux || tint_build_is_mac)
#include "src/tint/utils/file/tmpfile.h"
diff --git a/src/tint/utils/file/tmpfile_windows.cc b/src/tint/utils/file/tmpfile_windows.cc
index c6ddc33..486c2ea 100644
--- a/src/tint/utils/file/tmpfile_windows.cc
+++ b/src/tint/utils/file/tmpfile_windows.cc
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// GEN_BUILD:CONDITION(is_win)
+// GEN_BUILD:CONDITION(tint_build_is_win)
#include "src/tint/utils/file/tmpfile.h"
diff --git a/src/tint/utils/ice/ice.cc b/src/tint/utils/ice/ice.cc
index 9a4f981..f40d49e 100644
--- a/src/tint/utils/ice/ice.cc
+++ b/src/tint/utils/ice/ice.cc
@@ -54,7 +54,7 @@
}
std::string InternalCompilerError::Error() const {
- return std::string(File()) + +":" + std::to_string(Line()) +
+ return std::string(File()) + ":" + std::to_string(Line()) +
" internal compiler error: " + Message();
}
diff --git a/src/tint/utils/macros/foreach.h b/src/tint/utils/macros/foreach.h
index d889dc8..9ec27cc 100644
--- a/src/tint/utils/macros/foreach.h
+++ b/src/tint/utils/macros/foreach.h
@@ -92,13 +92,13 @@
TINT_FOREACH_11(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
CB(_12)
#define TINT_FOREACH_13(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
- TINT_FOREACH_11(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
+ TINT_FOREACH_12(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
CB(_13)
#define TINT_FOREACH_14(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
- TINT_FOREACH_11(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
+ TINT_FOREACH_13(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
CB(_14)
#define TINT_FOREACH_15(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
- TINT_FOREACH_11(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
+ TINT_FOREACH_14(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
CB(_15)
#endif // SRC_TINT_UTILS_MACROS_FOREACH_H_
diff --git a/src/tint/utils/socket/BUILD.bazel b/src/tint/utils/socket/BUILD.bazel
index 4c1fb71..c236531 100644
--- a/src/tint/utils/socket/BUILD.bazel
+++ b/src/tint/utils/socket/BUILD.bazel
@@ -48,7 +48,7 @@
deps = [
"//src/tint/utils/macros",
] + select({
- ":is_win": [
+ ":tint_build_is_win": [
],
"//conditions:default": [],
@@ -58,7 +58,7 @@
)
alias(
- name = "is_win",
- actual = "//src/tint:is_win_true",
+ name = "tint_build_is_win",
+ actual = "//src/tint:tint_build_is_win_true",
)
diff --git a/src/tint/utils/socket/BUILD.cmake b/src/tint/utils/socket/BUILD.cmake
index 2b9b312..6c69f4c 100644
--- a/src/tint/utils/socket/BUILD.cmake
+++ b/src/tint/utils/socket/BUILD.cmake
@@ -48,8 +48,8 @@
tint_utils_macros
)
-if(IS_WIN)
+if(TINT_BUILD_IS_WIN)
tint_target_add_external_dependencies(tint_utils_socket lib
"winsock"
)
-endif(IS_WIN)
+endif(TINT_BUILD_IS_WIN)
diff --git a/src/tint/utils/socket/BUILD.gn b/src/tint/utils/socket/BUILD.gn
index 0a0ff70..746a415 100644
--- a/src/tint/utils/socket/BUILD.gn
+++ b/src/tint/utils/socket/BUILD.gn
@@ -46,7 +46,7 @@
]
deps = [ "${tint_src_dir}/utils/macros" ]
- if (is_win) {
+ if (tint_build_is_win) {
deps += [ "${tint_src_dir}:winsock" ]
}
}
diff --git a/src/tint/utils/socket/rwmutex.h b/src/tint/utils/socket/rwmutex.h
index 099018a..e43b4e7 100644
--- a/src/tint/utils/socket/rwmutex.h
+++ b/src/tint/utils/socket/rwmutex.h
@@ -35,6 +35,8 @@
// RWMutex
////////////////////////////////////////////////////////////////////////////////
+namespace tint::socket {
+
/// A RWMutex is a reader/writer mutual exclusion lock.
/// The lock can be held by an arbitrary number of readers or a single writer.
/// Also known as a shared mutex.
@@ -200,4 +202,6 @@
return *this;
}
+} // namespace tint::socket
+
#endif // SRC_TINT_UTILS_SOCKET_RWMUTEX_H_
diff --git a/src/tint/utils/socket/socket.cc b/src/tint/utils/socket/socket.cc
index a3bf0bc..bab68f2 100644
--- a/src/tint/utils/socket/socket.cc
+++ b/src/tint/utils/socket/socket.cc
@@ -30,7 +30,7 @@
#include "src/tint/utils/macros/compiler.h"
#include "src/tint/utils/socket/rwmutex.h"
-#if defined(_WIN32)
+#if TINT_BUILD_IS_WIN
#include <winsock2.h>
#include <ws2tcpip.h>
#else
@@ -44,7 +44,7 @@
#include <cstdio>
#endif
-#if defined(_WIN32)
+#if TINT_BUILD_IS_WIN
#include <atomic>
namespace {
std::atomic<int> wsa_init_count = {0};
@@ -56,10 +56,11 @@
} // anonymous namespace
#endif
+namespace tint::socket {
namespace {
constexpr SOCKET InvalidSocket = static_cast<SOCKET>(-1);
void Init() {
-#if defined(_WIN32)
+#if TINT_BUILD_IS_WIN
if (wsa_init_count++ == 0) {
WSADATA winsock_data;
(void)WSAStartup(MAKEWORD(2, 2), &winsock_data);
@@ -68,7 +69,7 @@
}
void Term() {
-#if defined(_WIN32)
+#if TINT_BUILD_IS_WIN
if (--wsa_init_count == 0) {
WSACleanup();
}
@@ -76,7 +77,7 @@
}
bool SetBlocking(SOCKET s, bool blocking) {
-#if defined(_WIN32)
+#if TINT_BUILD_IS_WIN
u_long mode = blocking ? 0 : 1;
return ioctlsocket(s, FIONBIO, &mode) == NO_ERROR;
#else
@@ -112,7 +113,7 @@
addrinfo* info = nullptr;
auto err = getaddrinfo(address, port, &hints, &info);
-#if !defined(_WIN32)
+#if !TINT_BUILD_IS_WIN
if (err) {
printf("getaddrinfo(%s, %s) error: %s\n", address, port, gai_strerror(err));
}
@@ -157,7 +158,7 @@
int enable = 1;
-#if !defined(_WIN32)
+#if !TINT_BUILD_IS_WIN
// Prevent sockets lingering after process termination, causing
// reconnection issues on the same port.
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&enable), sizeof(enable));
@@ -167,7 +168,7 @@
int l_linger; /* how many seconds to linger for */
} linger = {false, 0};
setsockopt(s, SOL_SOCKET, SO_LINGER, reinterpret_cast<char*>(&linger), sizeof(linger));
-#endif // !defined(_WIN32)
+#endif // !TINT_BUILD_IS_WIN
// Enable TCP_NODELAY.
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&enable), sizeof(enable));
@@ -189,7 +190,7 @@
{
RLock l(mutex);
if (s != InvalidSocket) {
-#if defined(_WIN32)
+#if TINT_BUILD_IS_WIN
closesocket(s);
#else
::shutdown(s, SHUT_RDWR);
@@ -199,7 +200,7 @@
WLock l(mutex);
if (s != InvalidSocket) {
-#if !defined(_WIN32)
+#if !TINT_BUILD_IS_WIN
::close(s);
#endif
s = InvalidSocket;
@@ -333,3 +334,5 @@
return out->IsOpen() ? out : nullptr;
}
+
+} // namespace tint::socket
diff --git a/src/tint/utils/socket/socket.h b/src/tint/utils/socket/socket.h
index e22204e..36aa4b3 100644
--- a/src/tint/utils/socket/socket.h
+++ b/src/tint/utils/socket/socket.h
@@ -28,9 +28,10 @@
#ifndef SRC_TINT_UTILS_SOCKET_SOCKET_H_
#define SRC_TINT_UTILS_SOCKET_SOCKET_H_
-#include <atomic>
#include <memory>
+namespace tint::socket {
+
/// Socket provides an OS abstraction to a TCP socket.
class Socket {
public:
@@ -81,4 +82,6 @@
virtual std::shared_ptr<Socket> Accept() = 0;
};
+} // namespace tint::socket
+
#endif // SRC_TINT_UTILS_SOCKET_SOCKET_H_
diff --git a/src/tint/utils/strconv/float_to_string.cc b/src/tint/utils/strconv/float_to_string.cc
index ea54abc..ee48a88 100644
--- a/src/tint/utils/strconv/float_to_string.cc
+++ b/src/tint/utils/strconv/float_to_string.cc
@@ -29,14 +29,12 @@
#include <cmath>
#include <cstring>
-#include <functional>
#include <iomanip>
-#include <limits>
#include "src/tint/utils/ice/ice.h"
#include "src/tint/utils/text/string_stream.h"
-namespace tint::writer {
+namespace tint::strconv {
namespace {
@@ -187,4 +185,4 @@
return ToBitPreservingString(f);
}
-} // namespace tint::writer
+} // namespace tint::strconv
diff --git a/src/tint/utils/strconv/float_to_string.h b/src/tint/utils/strconv/float_to_string.h
index b97d74a..c272523 100644
--- a/src/tint/utils/strconv/float_to_string.h
+++ b/src/tint/utils/strconv/float_to_string.h
@@ -30,7 +30,7 @@
#include <string>
-namespace tint::writer {
+namespace tint::strconv {
/// Converts the float `f` to a string using fixed-point notation (not
/// scientific). The float will be printed with the full precision required to
@@ -58,6 +58,6 @@
/// @return the double f formatted to a string
std::string DoubleToBitPreservingString(double f);
-} // namespace tint::writer
+} // namespace tint::strconv
#endif // SRC_TINT_UTILS_STRCONV_FLOAT_TO_STRING_H_
diff --git a/src/tint/utils/strconv/float_to_string_test.cc b/src/tint/utils/strconv/float_to_string_test.cc
index 043b5f9..d0a0ce5 100644
--- a/src/tint/utils/strconv/float_to_string_test.cc
+++ b/src/tint/utils/strconv/float_to_string_test.cc
@@ -34,7 +34,7 @@
#include "gtest/gtest.h"
#include "src/tint/utils/memory/bitcast.h"
-namespace tint::writer {
+namespace tint::strconv {
namespace {
////////////////////////////////////////////////////////////////////////////////
@@ -345,4 +345,4 @@
}
} // namespace
-} // namespace tint::writer
+} // namespace tint::strconv
diff --git a/src/tint/utils/strconv/parse_num.cc b/src/tint/utils/strconv/parse_num.cc
index 09fcc3d..c1cbf85 100644
--- a/src/tint/utils/strconv/parse_num.cc
+++ b/src/tint/utils/strconv/parse_num.cc
@@ -31,7 +31,7 @@
#include "absl/strings/charconv.h"
-namespace tint {
+namespace tint::strconv {
namespace {
@@ -108,4 +108,4 @@
return Parse<uint8_t>(str);
}
-} // namespace tint
+} // namespace tint::strconv
diff --git a/src/tint/utils/strconv/parse_num.h b/src/tint/utils/strconv/parse_num.h
index 7eab873..704bd47 100644
--- a/src/tint/utils/strconv/parse_num.h
+++ b/src/tint/utils/strconv/parse_num.h
@@ -28,16 +28,13 @@
#ifndef SRC_TINT_UTILS_STRCONV_PARSE_NUM_H_
#define SRC_TINT_UTILS_STRCONV_PARSE_NUM_H_
-#include <optional>
-#include <string>
-
#include "src/tint/utils/macros/compiler.h"
#include "src/tint/utils/result/result.h"
-namespace tint {
+namespace tint::strconv {
/// Error returned by the number parsing functions
-enum class ParseNumberError {
+enum class ParseNumberError : uint8_t {
/// The number was unparsable
kUnparsable,
/// The parsed number is not representable by the target datatype
@@ -141,6 +138,6 @@
/// Re-enables the unreachable-code compiler warnings
TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
-} // namespace tint
+} // namespace tint::strconv
#endif // SRC_TINT_UTILS_STRCONV_PARSE_NUM_H_
diff --git a/src/tint/utils/symbol/symbol_table.h b/src/tint/utils/symbol/symbol_table.h
index 9e2c455..7c39512 100644
--- a/src/tint/utils/symbol/symbol_table.h
+++ b/src/tint/utils/symbol/symbol_table.h
@@ -53,17 +53,19 @@
/// @returns the symbol table
SymbolTable& operator=(SymbolTable&& other);
- /// Wrap sets this symbol table to hold symbols which point to the allocated names in @p o.
- /// The symbol table after Wrap is intended to temporarily extend the objects
- /// of an existing immutable SymbolTable
- /// As the copied objects are owned by @p o, @p o must not be destructed
- /// or assigned while using this symbol table.
+ /// @returns a symbol table to hold symbols which point to the allocated names in @p o.
+ /// The symbol table after Wrap is intended to temporarily extend the objects of an existing
+ /// immutable SymbolTable.
+ /// @warning As the copied objects are owned by @p o, @p o must not be destructed or assigned
+ /// while using this symbol table.
/// @param o the immutable SymbolTable to extend
- void Wrap(const SymbolTable& o) {
- next_symbol_ = o.next_symbol_;
- name_to_symbol_ = o.name_to_symbol_;
- last_prefix_to_index_ = o.last_prefix_to_index_;
- generation_id_ = o.generation_id_;
+ static SymbolTable Wrap(const SymbolTable& o) {
+ SymbolTable out(o.generation_id_);
+ out.next_symbol_ = o.next_symbol_;
+ out.name_to_symbol_ = o.name_to_symbol_;
+ out.last_prefix_to_index_ = o.last_prefix_to_index_;
+ out.generation_id_ = o.generation_id_;
+ return out;
}
/// Registers a name into the symbol table, returning the Symbol.
diff --git a/src/tint/utils/templates/enums.tmpl.inc b/src/tint/utils/templates/enums.tmpl.inc
index dd848a3..23dc6d3 100644
--- a/src/tint/utils/templates/enums.tmpl.inc
+++ b/src/tint/utils/templates/enums.tmpl.inc
@@ -38,34 +38,47 @@
{{- /* ------------------------------------------------------------------ */ -}}
{{- define "DeclareEnum" -}}
{{- /* Declares the 'enum class' for the provided sem.Enum argument. */ -}}
+{{- /* The argument can also be a key-value pair with the following keys: */ -}}
+{{- /* "Enum" - the sem.Enum argument */ -}}
+{{- /* "EmitOStream" - (default: true) should operator<< be emitted? */ -}}
{{- /* ------------------------------------------------------------------ */ -}}
-{{- $enum := Eval "EnumName" $ -}}
-enum class {{$enum}} : uint8_t {
+{{- $enum := $ -}}
+{{- $emit_ostream := true -}}
+{{- if Is $ "Map" -}}
+{{- $enum = $.Enum -}}
+{{- $emit_ostream = $.EmitOStream -}}
+{{- end }}
+
+{{- $name := Eval "EnumName" $enum -}}
+enum class {{$name}} : uint8_t {
kUndefined,
-{{- range $entry := $.Entries }}
+{{- range $entry := $enum.Entries }}
k{{PascalCase $entry.Name}},{{if $entry.IsInternal}} // Tint-internal enum entry - not parsed{{end}}
{{- end }}
};
/// @param value the enum value
/// @returns the string for the given enum value
-std::string_view ToString({{$enum}} value);
+std::string_view ToString({{$name}} value);
+
+{{- if $emit_ostream}}
/// @param out the stream to write to
-/// @param value the {{$enum}}
+/// @param value the {{$name}}
/// @returns @p out so calls can be chained
template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
-auto& operator<<(STREAM& out, {{$enum}} value) {
+auto& operator<<(STREAM& out, {{$name}} value) {
return out << ToString(value);
}
+{{- end}}
-/// Parse{{$enum}} parses a {{$enum}} from a string.
+/// Parse{{$name}} parses a {{$name}} from a string.
/// @param str the string to parse
-/// @returns the parsed enum, or {{$enum}}::kUndefined if the string could not be parsed.
-{{$enum}} Parse{{$enum}}(std::string_view str);
+/// @returns the parsed enum, or {{$name}}::kUndefined if the string could not be parsed.
+{{$name}} Parse{{$name}}(std::string_view str);
-constexpr std::string_view k{{$enum}}Strings[] = {
-{{- range $entry := $.Entries }}
+constexpr std::string_view k{{$name}}Strings[] = {
+{{- range $entry := $enum.Entries }}
{{- if not $entry.IsInternal}}
"{{$entry.Name}}",
{{- end }}
@@ -163,7 +176,7 @@
TEST_P({{$enum}}PrintTest, Print) {
{{$enum}} value = GetParam().value;
const char* expect = GetParam().string;
- EXPECT_EQ(expect, tint::ToString(value));
+ EXPECT_EQ(expect, ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, {{$enum}}PrintTest, testing::ValuesIn(kValidCases));
diff --git a/src/tint/utils/templates/intrinsic_table_data.tmpl.inc b/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
index 9da4e6c..7ef997c 100644
--- a/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
+++ b/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
@@ -66,14 +66,18 @@
{{- with $I.Table -}}
{{- template "Matchers" $I }}
+{{- if .TypeMatcherIndices}}
+
constexpr TypeMatcherIndex kTypeMatcherIndices[] = {
-{{- range $i, $idx := .TypeMatcherIndices }}
+{{- range $i, $idx := .TypeMatcherIndices }}
/* [{{$i}}] */ TypeMatcherIndex({{$idx}}),
-{{- end }}
+{{- end }}
};
static_assert(TypeMatcherIndex::CanIndex(kTypeMatcherIndices),
"TypeMatcherIndex is not large enough to index kTypeMatcherIndices");
+{{- end}}
+{{- if .NumberMatcherIndices}}
constexpr NumberMatcherIndex kNumberMatcherIndices[] = {
{{- range $i, $idx := .NumberMatcherIndices }}
@@ -83,6 +87,8 @@
static_assert(NumberMatcherIndex::CanIndex(kNumberMatcherIndices),
"NumberMatcherIndex is not large enough to index kNumberMatcherIndices");
+{{- end}}
+{{- if .Parameters}}
constexpr ParameterInfo kParameters[] = {
{{- range $i, $p := .Parameters }}
@@ -92,7 +98,10 @@
{{- if $p.Usage }}k{{PascalCase $p.Usage}}
{{- else }}kNone
{{- end }},
- /* type_matcher_indices */ TypeMatcherIndicesIndex({{$p.TypeMatcherIndicesOffset}}),
+ /* type_matcher_indices */
+{{- if ge $p.TypeMatcherIndicesOffset 0 }} TypeMatcherIndicesIndex({{$p.TypeMatcherIndicesOffset}})
+{{- else }} TypeMatcherIndicesIndex(/* invalid */)
+{{- end }},
/* number_matcher_indices */
{{- if ge $p.NumberMatcherIndicesOffset 0 }} NumberMatcherIndicesIndex({{$p.NumberMatcherIndicesOffset}})
{{- else }} NumberMatcherIndicesIndex(/* invalid */)
@@ -103,6 +112,8 @@
static_assert(ParameterIndex::CanIndex(kParameters),
"ParameterIndex is not large enough to index kParameters");
+{{- end}}
+{{- if .TemplateTypes}}
constexpr TemplateTypeInfo kTemplateTypes[] = {
{{- range $i, $o := .TemplateTypes }}
@@ -119,6 +130,8 @@
static_assert(TemplateTypeIndex::CanIndex(kTemplateTypes),
"TemplateTypeIndex is not large enough to index kTemplateTypes");
+{{- end }}
+{{- if .TemplateNumbers}}
constexpr TemplateNumberInfo kTemplateNumbers[] = {
{{- range $i, $o := .TemplateNumbers }}
@@ -135,6 +148,7 @@
static_assert(TemplateNumberIndex::CanIndex(kTemplateNumbers),
"TemplateNumberIndex is not large enough to index kTemplateNumbers");
+{{- end }}
{{- if .ConstEvalFunctions}}
{{/* newline */}}
@@ -271,12 +285,12 @@
} // anonymous namespace
const core::intrinsic::TableData {{$.Name}}{
- /* template_types */ kTemplateTypes,
- /* template_numbers */ kTemplateNumbers,
- /* type_matcher_indices */ kTypeMatcherIndices,
- /* number_matcher_indices */ kNumberMatcherIndices,
- /* type_matchers */ kTypeMatchers,
- /* number_matchers */ kNumberMatchers,
+ /* template_types */ {{if .TemplateTypes}}kTemplateTypes{{else}}Empty{{end}},
+ /* template_numbers */ {{if .TemplateNumbers}}kTemplateNumbers{{else}}Empty{{end}},
+ /* type_matcher_indices */ {{if .TypeMatcherIndices}}kTypeMatcherIndices{{else}}Empty{{end}},
+ /* number_matcher_indices */ {{if .NumberMatcherIndices}}kNumberMatcherIndices{{else}}Empty{{end}},
+ /* type_matchers */ {{if .TMatchers}}kTypeMatchers{{else}}Empty{{end}},
+ /* number_matchers */ {{if .NMatchers}}kNumberMatchers{{else}}Empty{{end}},
/* parameters */ kParameters,
/* overloads */ kOverloads,
/* const_eval_functions */ {{if .ConstEvalFunctions}}kConstEvalFunctions{{else}}Empty{{end}},
@@ -436,25 +450,30 @@
{{- $n_names.Put . $name }}
{{- end }}
+{{- if $.Table.TMatchers}}
+
/// The template types, types, and type matchers
constexpr TypeMatcher kTypeMatchers[] = {
-{{- range $i, $m := $.Table.TMatchers }}
+{{- range $i, $m := $.Table.TMatchers }}
/* [{{$i}}] */
-{{- if $m }} {{$t_names.Get $m}},
-{{- else }} {{$t_names.Get $i}},
-{{- end }}
-{{- end }}
+{{- if $m }} {{$t_names.Get $m}},
+{{- else }} {{$t_names.Get $i}},
+{{- end }}
+{{- end }}
};
+{{- end}}
+{{- if $.Table.NMatchers}}
/// The template numbers, and number matchers
constexpr NumberMatcher kNumberMatchers[] = {
-{{- range $i, $m := $.Table.NMatchers }}
+{{- range $i, $m := $.Table.NMatchers }}
/* [{{$i}}] */
-{{- if $m }} {{$n_names.Get $m}},
-{{- else }} {{$n_names.Get $i}},
-{{- end }}
-{{- end }}
+{{- if $m }} {{$n_names.Get $m}},
+{{- else }} {{$n_names.Get $i}},
+{{- end }}
+{{- end }}
};
+{{- end}}
{{- end -}}
diff --git a/src/tint/utils/text/BUILD.bazel b/src/tint/utils/text/BUILD.bazel
index 384af8e..21ae073 100644
--- a/src/tint/utils/text/BUILD.bazel
+++ b/src/tint/utils/text/BUILD.bazel
@@ -39,11 +39,13 @@
cc_library(
name = "text",
srcs = [
+ "base64.cc",
"string.cc",
"string_stream.cc",
"unicode.cc",
],
hdrs = [
+ "base64.h",
"string.h",
"string_stream.h",
"unicode.h",
@@ -64,6 +66,7 @@
name = "test",
alwayslink = True,
srcs = [
+ "base64_test.cc",
"string_stream_test.cc",
"string_test.cc",
"unicode_test.cc",
diff --git a/src/tint/utils/text/BUILD.cmake b/src/tint/utils/text/BUILD.cmake
index cd7e6b8..f5f8c10 100644
--- a/src/tint/utils/text/BUILD.cmake
+++ b/src/tint/utils/text/BUILD.cmake
@@ -39,6 +39,8 @@
# Kind: lib
################################################################################
tint_add_target(tint_utils_text lib
+ utils/text/base64.cc
+ utils/text/base64.h
utils/text/string.cc
utils/text/string.h
utils/text/string_stream.cc
@@ -62,6 +64,7 @@
# Kind: test
################################################################################
tint_add_target(tint_utils_text_test test
+ utils/text/base64_test.cc
utils/text/string_stream_test.cc
utils/text/string_test.cc
utils/text/unicode_test.cc
diff --git a/src/tint/utils/text/BUILD.gn b/src/tint/utils/text/BUILD.gn
index df4c510..c13c8c0 100644
--- a/src/tint/utils/text/BUILD.gn
+++ b/src/tint/utils/text/BUILD.gn
@@ -44,6 +44,8 @@
libtint_source_set("text") {
sources = [
+ "base64.cc",
+ "base64.h",
"string.cc",
"string.h",
"string_stream.cc",
@@ -64,6 +66,7 @@
if (tint_build_unittests) {
tint_unittests_source_set("unittests") {
sources = [
+ "base64_test.cc",
"string_stream_test.cc",
"string_test.cc",
"unicode_test.cc",
diff --git a/src/tint/utils/text/base64.cc b/src/tint/utils/text/base64.cc
new file mode 100644
index 0000000..7ae85cc
--- /dev/null
+++ b/src/tint/utils/text/base64.cc
@@ -0,0 +1,71 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <string>
+
+#include "src/tint/utils/text/base64.h"
+
+namespace tint {
+
+Vector<std::byte, 0> DecodeBase64FromComments(std::string_view wgsl) {
+ Vector<std::byte, 0> out;
+ size_t block_nesting = 0;
+ bool line_comment = false;
+ for (size_t i = 0, n = wgsl.length(); i < n; i++) {
+ char curr = wgsl[i];
+ if (curr == '\n') {
+ line_comment = false;
+ continue;
+ }
+
+ char next = (i + 1) < n ? wgsl[i + 1] : 0;
+ if (curr == '/' && next == '*') {
+ block_nesting++;
+ i++; // skip '*'
+ continue;
+ }
+ if (block_nesting > 0 && curr == '*' && next == '/') {
+ block_nesting--;
+ i++; // skip '/'
+ continue;
+ }
+ if (block_nesting == 0 && curr == '/' && next == '/') {
+ line_comment = true;
+ i++; // skip '/'
+ continue;
+ }
+
+ if (block_nesting > 0 || line_comment) {
+ if (auto v = DecodeBase64(curr)) {
+ out.Push(std::byte{*v});
+ }
+ }
+ }
+ return out;
+}
+
+} // namespace tint
diff --git a/src/tint/utils/text/base64.h b/src/tint/utils/text/base64.h
new file mode 100644
index 0000000..1047c33
--- /dev/null
+++ b/src/tint/utils/text/base64.h
@@ -0,0 +1,68 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_UTILS_TEXT_BASE64_H_
+#define SRC_TINT_UTILS_TEXT_BASE64_H_
+
+#include <cstdint>
+#include <optional>
+
+#include "src/tint/utils/containers/vector.h"
+
+namespace tint {
+
+/// Decodes a byte from a base64 encoded character
+/// @param c the character to decode
+/// @return the decoded value, or std::nullopt if the character is padding ('=') or an invalid
+/// character.
+inline std::optional<uint8_t> DecodeBase64(char c) {
+ if (c >= 'A' && c <= 'Z') {
+ return static_cast<uint8_t>(c - 'A');
+ }
+ if (c >= 'a' && c <= 'z') {
+ return static_cast<uint8_t>(26 + c - 'a');
+ }
+ if (c >= '0' && c <= '9') {
+ return static_cast<uint8_t>(52 + c - '0');
+ }
+ if (c == '+') {
+ return 62;
+ }
+ if (c == '/') {
+ return 63;
+ }
+ return std::nullopt;
+}
+/// DecodeBase64FromComments parses all the comments from the WGSL source string as a base64 byte
+/// stream. Non-base64 characters are skipped
+/// @param wgsl the WGSL source
+/// @return the base64 decoded bytes
+Vector<std::byte, 0> DecodeBase64FromComments(std::string_view wgsl);
+
+} // namespace tint
+
+#endif // SRC_TINT_UTILS_TEXT_BASE64_H_
diff --git a/src/tint/utils/text/base64_test.cc b/src/tint/utils/text/base64_test.cc
new file mode 100644
index 0000000..3eb282f
--- /dev/null
+++ b/src/tint/utils/text/base64_test.cc
@@ -0,0 +1,222 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/utils/text/base64.h"
+
+#include <optional>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+#include "src/tint/utils/containers/transform.h"
+#include "src/tint/utils/text/string.h"
+
+namespace tint::utils {
+namespace {
+
+struct DecodeBase64Case {
+ char in;
+ std::optional<uint8_t> out;
+};
+
+using DecodeBase64Test = testing::TestWithParam<DecodeBase64Case>;
+
+TEST_P(DecodeBase64Test, Char) {
+ EXPECT_EQ(DecodeBase64(GetParam().in), GetParam().out);
+}
+
+INSTANTIATE_TEST_SUITE_P(Valid,
+ DecodeBase64Test,
+ testing::Values(DecodeBase64Case{'A', 0},
+ DecodeBase64Case{'B', 1},
+ DecodeBase64Case{'C', 2},
+ DecodeBase64Case{'D', 3},
+ DecodeBase64Case{'E', 4},
+ DecodeBase64Case{'F', 5},
+ DecodeBase64Case{'G', 6},
+ DecodeBase64Case{'H', 7},
+ DecodeBase64Case{'I', 8},
+ DecodeBase64Case{'J', 9},
+ DecodeBase64Case{'K', 10},
+ DecodeBase64Case{'L', 11},
+ DecodeBase64Case{'M', 12},
+ DecodeBase64Case{'N', 13},
+ DecodeBase64Case{'O', 14},
+ DecodeBase64Case{'P', 15},
+ DecodeBase64Case{'Q', 16},
+ DecodeBase64Case{'R', 17},
+ DecodeBase64Case{'S', 18},
+ DecodeBase64Case{'T', 19},
+ DecodeBase64Case{'U', 20},
+ DecodeBase64Case{'V', 21},
+ DecodeBase64Case{'W', 22},
+ DecodeBase64Case{'X', 23},
+ DecodeBase64Case{'Y', 24},
+ DecodeBase64Case{'Z', 25},
+ DecodeBase64Case{'a', 26},
+ DecodeBase64Case{'b', 27},
+ DecodeBase64Case{'c', 28},
+ DecodeBase64Case{'d', 29},
+ DecodeBase64Case{'e', 30},
+ DecodeBase64Case{'f', 31},
+ DecodeBase64Case{'g', 32},
+ DecodeBase64Case{'h', 33},
+ DecodeBase64Case{'i', 34},
+ DecodeBase64Case{'j', 35},
+ DecodeBase64Case{'k', 36},
+ DecodeBase64Case{'l', 37},
+ DecodeBase64Case{'m', 38},
+ DecodeBase64Case{'n', 39},
+ DecodeBase64Case{'o', 40},
+ DecodeBase64Case{'p', 41},
+ DecodeBase64Case{'q', 42},
+ DecodeBase64Case{'r', 43},
+ DecodeBase64Case{'s', 44},
+ DecodeBase64Case{'t', 45},
+ DecodeBase64Case{'u', 46},
+ DecodeBase64Case{'v', 47},
+ DecodeBase64Case{'w', 48},
+ DecodeBase64Case{'x', 49},
+ DecodeBase64Case{'y', 50},
+ DecodeBase64Case{'z', 51},
+ DecodeBase64Case{'0', 52},
+ DecodeBase64Case{'1', 53},
+ DecodeBase64Case{'2', 54},
+ DecodeBase64Case{'3', 55},
+ DecodeBase64Case{'4', 56},
+ DecodeBase64Case{'5', 57},
+ DecodeBase64Case{'6', 58},
+ DecodeBase64Case{'7', 59},
+ DecodeBase64Case{'8', 60},
+ DecodeBase64Case{'9', 61},
+ DecodeBase64Case{'+', 62},
+ DecodeBase64Case{'/', 63}));
+
+INSTANTIATE_TEST_SUITE_P(Invalid,
+ DecodeBase64Test,
+ testing::Values(DecodeBase64Case{'@', std::nullopt},
+ DecodeBase64Case{'#', std::nullopt},
+ DecodeBase64Case{'^', std::nullopt},
+ DecodeBase64Case{'&', std::nullopt},
+ DecodeBase64Case{'!', std::nullopt},
+ DecodeBase64Case{'*', std::nullopt},
+ DecodeBase64Case{'(', std::nullopt},
+ DecodeBase64Case{')', std::nullopt},
+ DecodeBase64Case{'-', std::nullopt},
+ DecodeBase64Case{'.', std::nullopt},
+ DecodeBase64Case{'\0', std::nullopt},
+ DecodeBase64Case{'\n', std::nullopt}));
+
+INSTANTIATE_TEST_SUITE_P(Padding,
+ DecodeBase64Test,
+ testing::Values(DecodeBase64Case{'=', std::nullopt}));
+
+struct DecodeBase64FromCommentsCase {
+ std::string_view wgsl;
+ Vector<int, 0> expected;
+};
+
+static std::ostream& operator<<(std::ostream& o, const DecodeBase64FromCommentsCase& c) {
+ return o << "'" << ReplaceAll(c.wgsl, "\n", "") << "'";
+}
+
+using DecodeBase64FromCommentsTest = ::testing::TestWithParam<DecodeBase64FromCommentsCase>;
+
+TEST_P(DecodeBase64FromCommentsTest, None) {
+ auto got_bytes = DecodeBase64FromComments(GetParam().wgsl);
+ auto got = Transform(got_bytes, [](std::byte byte) { return static_cast<int>(byte); });
+ EXPECT_EQ(got, GetParam().expected);
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+ DecodeBase64FromCommentsTest,
+ testing::ValuesIn(std::vector<DecodeBase64FromCommentsCase>{
+ {"", Empty},
+ {"//", Empty},
+ {"abc", Empty},
+ {"abc//", Empty},
+ {
+ R"(a
+b
+c)",
+ Empty,
+ },
+ {"// abc", {26, 27, 28}},
+ {"a // bc", {27, 28}},
+ {"ab // c", {28}},
+ {"// a.b.c", {26, 27, 28}},
+ {
+ R"(a
+b
+c)",
+ Empty,
+ },
+ {
+ R"(a
+// b
+c)",
+ {27},
+ },
+ {
+ R"(// a
+// b
+// c)",
+ {26, 27, 28},
+ },
+ {
+ R"(/* a
+b
+c
+*/)",
+ {26, 27, 28},
+ },
+ {
+ R"(/* a
+b
+*/
+c)",
+ {26, 27},
+ },
+ {
+ R"(a/*
+b
+*/
+c)",
+ {27},
+ },
+ {
+ "x/*a*/b/*c*/y",
+ {26, 28},
+ },
+ {
+ "x/*a/*b*/c*/z",
+ {26, 27, 28},
+ },
+ }));
+
+} // namespace
+} // namespace tint::utils