[hlsl] Remove the AST backend.
Removes the HLSL AST backend.
Bug: 421916945
Change-Id: I7dfe0128678099a9ab6161c870d5dbd4f29010eb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/248354
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/cmd/test/BUILD.bazel b/src/tint/cmd/test/BUILD.bazel
index facb4fe..c84d5ef 100644
--- a/src/tint/cmd/test/BUILD.bazel
+++ b/src/tint/cmd/test/BUILD.bazel
@@ -102,16 +102,10 @@
"//conditions:default": [],
}) + select({
":tint_build_hlsl_writer": [
- "//src/tint/lang/hlsl/writer/ast_printer:test",
"//src/tint/lang/hlsl/writer:test",
],
"//conditions:default": [],
}) + select({
- ":tint_build_hlsl_writer_and_tint_build_wgsl_reader_and_tint_build_wgsl_writer": [
- "//src/tint/lang/hlsl/writer/ast_raise:test",
- ],
- "//conditions:default": [],
- }) + select({
":tint_build_ir_binary": [
"//src/tint/lang/core/ir/binary:test",
],
@@ -247,14 +241,6 @@
],
)
selects.config_setting_group(
- name = "tint_build_hlsl_writer_and_tint_build_wgsl_reader_and_tint_build_wgsl_writer",
- match_all = [
- ":tint_build_hlsl_writer",
- ":tint_build_wgsl_reader",
- ":tint_build_wgsl_writer",
- ],
-)
-selects.config_setting_group(
name = "tint_build_spv_reader_and_tint_build_wgsl_reader_and_tint_build_wgsl_writer",
match_all = [
":tint_build_spv_reader",
diff --git a/src/tint/cmd/test/BUILD.cmake b/src/tint/cmd/test/BUILD.cmake
index 1365282..042cbdb 100644
--- a/src/tint/cmd/test/BUILD.cmake
+++ b/src/tint/cmd/test/BUILD.cmake
@@ -110,17 +110,10 @@
if(TINT_BUILD_HLSL_WRITER)
tint_target_add_dependencies(tint_cmd_test_test_cmd test_cmd
- tint_lang_hlsl_writer_ast_printer_test
tint_lang_hlsl_writer_test
)
endif(TINT_BUILD_HLSL_WRITER)
-if(TINT_BUILD_HLSL_WRITER AND TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
- tint_target_add_dependencies(tint_cmd_test_test_cmd test_cmd
- tint_lang_hlsl_writer_ast_raise_test
- )
-endif(TINT_BUILD_HLSL_WRITER AND TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
-
if(TINT_BUILD_IR_BINARY)
tint_target_add_dependencies(tint_cmd_test_test_cmd test_cmd
tint_lang_core_ir_binary_test
diff --git a/src/tint/cmd/test/BUILD.gn b/src/tint/cmd/test/BUILD.gn
index 64aff8a..9f9c343 100644
--- a/src/tint/cmd/test/BUILD.gn
+++ b/src/tint/cmd/test/BUILD.gn
@@ -109,15 +109,7 @@
}
if (tint_build_hlsl_writer) {
- deps += [
- "${tint_src_dir}/lang/hlsl/writer:unittests",
- "${tint_src_dir}/lang/hlsl/writer/ast_printer:unittests",
- ]
- }
-
- if (tint_build_hlsl_writer && tint_build_wgsl_reader &&
- tint_build_wgsl_writer) {
- deps += [ "${tint_src_dir}/lang/hlsl/writer/ast_raise:unittests" ]
+ deps += [ "${tint_src_dir}/lang/hlsl/writer:unittests" ]
}
if (tint_build_ir_binary) {
diff --git a/src/tint/lang/hlsl/writer/BUILD.bazel b/src/tint/lang/hlsl/writer/BUILD.bazel
index 0e84209..8f9f85b 100644
--- a/src/tint/lang/hlsl/writer/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/BUILD.bazel
@@ -53,11 +53,7 @@
"//src/tint/lang/hlsl/writer/common",
"//src/tint/lang/hlsl/writer/printer",
"//src/tint/lang/hlsl/writer/raise",
- "//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
- "//src/tint/lang/wgsl/ast/transform",
- "//src/tint/lang/wgsl/program",
- "//src/tint/lang/wgsl/sem",
"//src/tint/utils",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
@@ -68,15 +64,8 @@
"//src/tint/utils/rtti",
"//src/tint/utils/symbol",
"//src/tint/utils/text",
- "//src/tint/utils/text_generator",
"//src/utils",
- ] + select({
- ":tint_build_hlsl_writer": [
- "//src/tint/lang/hlsl/writer/ast_printer",
- "//src/tint/lang/hlsl/writer/ast_raise",
- ],
- "//conditions:default": [],
- }),
+ ],
copts = COPTS,
visibility = ["//visibility:public"],
)
@@ -139,8 +128,3 @@
actual = "//src/tint:tint_build_hlsl_writer_true",
)
-alias(
- name = "tint_build_wgsl_reader",
- actual = "//src/tint:tint_build_wgsl_reader_true",
-)
-
diff --git a/src/tint/lang/hlsl/writer/BUILD.cmake b/src/tint/lang/hlsl/writer/BUILD.cmake
index 6ee58ca..b0766e7 100644
--- a/src/tint/lang/hlsl/writer/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/BUILD.cmake
@@ -34,8 +34,6 @@
# Do not modify this file directly
################################################################################
-include(lang/hlsl/writer/ast_printer/BUILD.cmake)
-include(lang/hlsl/writer/ast_raise/BUILD.cmake)
include(lang/hlsl/writer/common/BUILD.cmake)
include(lang/hlsl/writer/helpers/BUILD.cmake)
include(lang/hlsl/writer/printer/BUILD.cmake)
@@ -61,11 +59,7 @@
tint_lang_hlsl_writer_common
tint_lang_hlsl_writer_printer
tint_lang_hlsl_writer_raise
- tint_lang_wgsl
tint_lang_wgsl_ast
- tint_lang_wgsl_ast_transform
- tint_lang_wgsl_program
- tint_lang_wgsl_sem
tint_utils
tint_utils_containers
tint_utils_diagnostic
@@ -76,20 +70,12 @@
tint_utils_rtti
tint_utils_symbol
tint_utils_text
- tint_utils_text_generator
)
tint_target_add_external_dependencies(tint_lang_hlsl_writer lib
"src_utils"
)
-if(TINT_BUILD_HLSL_WRITER)
- tint_target_add_dependencies(tint_lang_hlsl_writer lib
- tint_lang_hlsl_writer_ast_printer
- tint_lang_hlsl_writer_ast_raise
- )
-endif(TINT_BUILD_HLSL_WRITER)
-
endif(TINT_BUILD_HLSL_WRITER)
if(TINT_BUILD_HLSL_WRITER)
################################################################################
@@ -170,11 +156,7 @@
tint_lang_core_type
tint_lang_hlsl_writer_common
tint_lang_hlsl_writer_helpers
- tint_lang_wgsl
tint_lang_wgsl_ast
- tint_lang_wgsl_ast_transform
- tint_lang_wgsl_program
- tint_lang_wgsl_sem
tint_utils
tint_utils_bytes
tint_utils_command
@@ -200,13 +182,4 @@
)
endif(TINT_BUILD_HLSL_WRITER)
-if(TINT_BUILD_WGSL_READER)
- tint_target_add_sources(tint_lang_hlsl_writer_fuzz fuzz
- "lang/hlsl/writer/writer_ast_fuzz.cc"
- )
- tint_target_add_dependencies(tint_lang_hlsl_writer_fuzz fuzz
- tint_cmd_fuzz_wgsl_fuzz
- )
-endif(TINT_BUILD_WGSL_READER)
-
endif(TINT_BUILD_HLSL_WRITER)
\ No newline at end of file
diff --git a/src/tint/lang/hlsl/writer/BUILD.gn b/src/tint/lang/hlsl/writer/BUILD.gn
index b2a8e49..328b2ea 100644
--- a/src/tint/lang/hlsl/writer/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/BUILD.gn
@@ -58,11 +58,7 @@
"${tint_src_dir}/lang/hlsl/writer/common",
"${tint_src_dir}/lang/hlsl/writer/printer",
"${tint_src_dir}/lang/hlsl/writer/raise",
- "${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
- "${tint_src_dir}/lang/wgsl/ast/transform",
- "${tint_src_dir}/lang/wgsl/program",
- "${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
@@ -73,15 +69,7 @@
"${tint_src_dir}/utils/rtti",
"${tint_src_dir}/utils/symbol",
"${tint_src_dir}/utils/text",
- "${tint_src_dir}/utils/text_generator",
]
-
- if (tint_build_hlsl_writer) {
- deps += [
- "${tint_src_dir}/lang/hlsl/writer/ast_printer",
- "${tint_src_dir}/lang/hlsl/writer/ast_raise",
- ]
- }
}
}
if (tint_build_unittests) {
@@ -151,11 +139,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/hlsl/writer/common",
"${tint_src_dir}/lang/hlsl/writer/helpers",
- "${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
- "${tint_src_dir}/lang/wgsl/ast/transform",
- "${tint_src_dir}/lang/wgsl/program",
- "${tint_src_dir}/lang/wgsl/sem",
"${tint_src_dir}/utils",
"${tint_src_dir}/utils/bytes",
"${tint_src_dir}/utils/command",
@@ -176,10 +160,5 @@
"${tint_src_dir}/lang/hlsl/writer",
]
}
-
- if (tint_build_wgsl_reader) {
- sources += [ "writer_ast_fuzz.cc" ]
- deps += [ "${tint_src_dir}/cmd/fuzz/wgsl:fuzz" ]
- }
}
}
diff --git a/src/tint/lang/hlsl/writer/ast_printer/BUILD.bazel b/src/tint/lang/hlsl/writer/ast_printer/BUILD.bazel
deleted file mode 100644
index 7da657b..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/BUILD.bazel
+++ /dev/null
@@ -1,159 +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.
-
-################################################################################
-# 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 = "ast_printer",
- srcs = [
- "ast_printer.cc",
- ],
- hdrs = [
- "ast_printer.h",
- ],
- deps = [
- "//src/tint/api/common",
- "//src/tint/lang/core",
- "//src/tint/lang/core/constant",
- "//src/tint/lang/core/ir/transform",
- "//src/tint/lang/core/type",
- "//src/tint/lang/hlsl/writer/common",
- "//src/tint/lang/wgsl",
- "//src/tint/lang/wgsl/ast",
- "//src/tint/lang/wgsl/ast/transform",
- "//src/tint/lang/wgsl/program",
- "//src/tint/lang/wgsl/sem",
- "//src/tint/utils",
- "//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/rtti",
- "//src/tint/utils/strconv",
- "//src/tint/utils/symbol",
- "//src/tint/utils/text",
- "//src/tint/utils/text_generator",
- "//src/utils",
- ] + select({
- ":tint_build_hlsl_writer": [
- "//src/tint/lang/hlsl/writer/ast_raise",
- ],
- "//conditions:default": [],
- }),
- copts = COPTS,
- visibility = ["//visibility:public"],
-)
-cc_library(
- name = "test",
- alwayslink = True,
- srcs = [
- "array_accessor_test.cc",
- "assign_test.cc",
- "ast_printer_test.cc",
- "binary_test.cc",
- "bitcast_test.cc",
- "block_test.cc",
- "break_test.cc",
- "builtin_test.cc",
- "builtin_texture_test.cc",
- "call_test.cc",
- "case_test.cc",
- "cast_test.cc",
- "const_assert_test.cc",
- "constructor_test.cc",
- "continue_test.cc",
- "discard_test.cc",
- "function_test.cc",
- "helper_test.h",
- "identifier_test.cc",
- "if_test.cc",
- "import_test.cc",
- "loop_test.cc",
- "member_accessor_test.cc",
- "module_constant_test.cc",
- "return_test.cc",
- "sanitizer_test.cc",
- "switch_test.cc",
- "type_test.cc",
- "unary_op_test.cc",
- "variable_decl_statement_test.cc",
- "workgroup_var_test.cc",
- ],
- deps = [
- "//src/tint/api/common",
- "//src/tint/lang/core",
- "//src/tint/lang/core/constant",
- "//src/tint/lang/core/type",
- "//src/tint/lang/hlsl/writer/common",
- "//src/tint/lang/wgsl",
- "//src/tint/lang/wgsl/ast",
- "//src/tint/lang/wgsl/ast/transform",
- "//src/tint/lang/wgsl/ast:test",
- "//src/tint/lang/wgsl/program",
- "//src/tint/lang/wgsl/resolver",
- "//src/tint/lang/wgsl/sem",
- "//src/tint/utils",
- "//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/rtti",
- "//src/tint/utils/symbol",
- "//src/tint/utils/text",
- "//src/tint/utils/text_generator",
- "@gtest",
- "//src/utils",
- ] + select({
- ":tint_build_hlsl_writer": [
- "//src/tint/lang/hlsl/writer",
- "//src/tint/lang/hlsl/writer/ast_printer",
- "//src/tint/lang/hlsl/writer/ast_raise",
- ],
- "//conditions:default": [],
- }),
- copts = COPTS,
- visibility = ["//visibility:public"],
-)
-
-alias(
- name = "tint_build_hlsl_writer",
- actual = "//src/tint:tint_build_hlsl_writer_true",
-)
-
diff --git a/src/tint/lang/hlsl/writer/ast_printer/BUILD.cfg b/src/tint/lang/hlsl/writer/ast_printer/BUILD.cfg
deleted file mode 100644
index 31b4636..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/BUILD.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "condition": "tint_build_hlsl_writer"
-}
diff --git a/src/tint/lang/hlsl/writer/ast_printer/BUILD.cmake b/src/tint/lang/hlsl/writer/ast_printer/BUILD.cmake
deleted file mode 100644
index 4b09f81..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/BUILD.cmake
+++ /dev/null
@@ -1,164 +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.
-
-################################################################################
-# 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_HLSL_WRITER)
-################################################################################
-# Target: tint_lang_hlsl_writer_ast_printer
-# Kind: lib
-# Condition: TINT_BUILD_HLSL_WRITER
-################################################################################
-tint_add_target(tint_lang_hlsl_writer_ast_printer lib
- lang/hlsl/writer/ast_printer/ast_printer.cc
- lang/hlsl/writer/ast_printer/ast_printer.h
-)
-
-tint_target_add_dependencies(tint_lang_hlsl_writer_ast_printer lib
- tint_api_common
- tint_lang_core
- tint_lang_core_constant
- tint_lang_core_ir_transform
- tint_lang_core_type
- tint_lang_hlsl_writer_common
- tint_lang_wgsl
- tint_lang_wgsl_ast
- tint_lang_wgsl_ast_transform
- tint_lang_wgsl_program
- tint_lang_wgsl_sem
- tint_utils
- tint_utils_containers
- tint_utils_diagnostic
- tint_utils_ice
- tint_utils_macros
- tint_utils_math
- tint_utils_memory
- tint_utils_rtti
- tint_utils_strconv
- tint_utils_symbol
- tint_utils_text
- tint_utils_text_generator
-)
-
-tint_target_add_external_dependencies(tint_lang_hlsl_writer_ast_printer lib
- "src_utils"
-)
-
-if(TINT_BUILD_HLSL_WRITER)
- tint_target_add_dependencies(tint_lang_hlsl_writer_ast_printer lib
- tint_lang_hlsl_writer_ast_raise
- )
-endif(TINT_BUILD_HLSL_WRITER)
-
-endif(TINT_BUILD_HLSL_WRITER)
-if(TINT_BUILD_HLSL_WRITER)
-################################################################################
-# Target: tint_lang_hlsl_writer_ast_printer_test
-# Kind: test
-# Condition: TINT_BUILD_HLSL_WRITER
-################################################################################
-tint_add_target(tint_lang_hlsl_writer_ast_printer_test test
- lang/hlsl/writer/ast_printer/array_accessor_test.cc
- lang/hlsl/writer/ast_printer/assign_test.cc
- lang/hlsl/writer/ast_printer/ast_printer_test.cc
- lang/hlsl/writer/ast_printer/binary_test.cc
- lang/hlsl/writer/ast_printer/bitcast_test.cc
- lang/hlsl/writer/ast_printer/block_test.cc
- lang/hlsl/writer/ast_printer/break_test.cc
- lang/hlsl/writer/ast_printer/builtin_test.cc
- lang/hlsl/writer/ast_printer/builtin_texture_test.cc
- lang/hlsl/writer/ast_printer/call_test.cc
- lang/hlsl/writer/ast_printer/case_test.cc
- lang/hlsl/writer/ast_printer/cast_test.cc
- lang/hlsl/writer/ast_printer/const_assert_test.cc
- lang/hlsl/writer/ast_printer/constructor_test.cc
- lang/hlsl/writer/ast_printer/continue_test.cc
- lang/hlsl/writer/ast_printer/discard_test.cc
- lang/hlsl/writer/ast_printer/function_test.cc
- lang/hlsl/writer/ast_printer/helper_test.h
- lang/hlsl/writer/ast_printer/identifier_test.cc
- lang/hlsl/writer/ast_printer/if_test.cc
- lang/hlsl/writer/ast_printer/import_test.cc
- lang/hlsl/writer/ast_printer/loop_test.cc
- lang/hlsl/writer/ast_printer/member_accessor_test.cc
- lang/hlsl/writer/ast_printer/module_constant_test.cc
- lang/hlsl/writer/ast_printer/return_test.cc
- lang/hlsl/writer/ast_printer/sanitizer_test.cc
- lang/hlsl/writer/ast_printer/switch_test.cc
- lang/hlsl/writer/ast_printer/type_test.cc
- lang/hlsl/writer/ast_printer/unary_op_test.cc
- lang/hlsl/writer/ast_printer/variable_decl_statement_test.cc
- lang/hlsl/writer/ast_printer/workgroup_var_test.cc
-)
-
-tint_target_add_dependencies(tint_lang_hlsl_writer_ast_printer_test test
- tint_api_common
- tint_lang_core
- tint_lang_core_constant
- tint_lang_core_type
- tint_lang_hlsl_writer_common
- tint_lang_wgsl
- tint_lang_wgsl_ast
- tint_lang_wgsl_ast_transform
- tint_lang_wgsl_ast_test
- tint_lang_wgsl_program
- tint_lang_wgsl_resolver
- tint_lang_wgsl_sem
- tint_utils
- tint_utils_containers
- tint_utils_diagnostic
- tint_utils_ice
- tint_utils_macros
- tint_utils_math
- tint_utils_memory
- tint_utils_rtti
- tint_utils_symbol
- tint_utils_text
- tint_utils_text_generator
-)
-
-tint_target_add_external_dependencies(tint_lang_hlsl_writer_ast_printer_test test
- "gtest"
- "src_utils"
-)
-
-if(TINT_BUILD_HLSL_WRITER)
- tint_target_add_dependencies(tint_lang_hlsl_writer_ast_printer_test test
- tint_lang_hlsl_writer
- tint_lang_hlsl_writer_ast_printer
- tint_lang_hlsl_writer_ast_raise
- )
-endif(TINT_BUILD_HLSL_WRITER)
-
-endif(TINT_BUILD_HLSL_WRITER)
\ No newline at end of file
diff --git a/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn b/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn
deleted file mode 100644
index f637dfd..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn
+++ /dev/null
@@ -1,156 +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.
-
-################################################################################
-# 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/dawn_overrides_with_defaults.gni")
-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_hlsl_writer) {
- libtint_source_set("ast_printer") {
- sources = [
- "ast_printer.cc",
- "ast_printer.h",
- ]
- deps = [
- "${dawn_root}/src/utils:utils",
- "${tint_src_dir}/api/common",
- "${tint_src_dir}/lang/core",
- "${tint_src_dir}/lang/core/constant",
- "${tint_src_dir}/lang/core/ir/transform",
- "${tint_src_dir}/lang/core/type",
- "${tint_src_dir}/lang/hlsl/writer/common",
- "${tint_src_dir}/lang/wgsl",
- "${tint_src_dir}/lang/wgsl/ast",
- "${tint_src_dir}/lang/wgsl/ast/transform",
- "${tint_src_dir}/lang/wgsl/program",
- "${tint_src_dir}/lang/wgsl/sem",
- "${tint_src_dir}/utils",
- "${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/rtti",
- "${tint_src_dir}/utils/strconv",
- "${tint_src_dir}/utils/symbol",
- "${tint_src_dir}/utils/text",
- "${tint_src_dir}/utils/text_generator",
- ]
-
- if (tint_build_hlsl_writer) {
- deps += [ "${tint_src_dir}/lang/hlsl/writer/ast_raise" ]
- }
- }
-}
-if (tint_build_unittests) {
- if (tint_build_hlsl_writer) {
- tint_unittests_source_set("unittests") {
- sources = [
- "array_accessor_test.cc",
- "assign_test.cc",
- "ast_printer_test.cc",
- "binary_test.cc",
- "bitcast_test.cc",
- "block_test.cc",
- "break_test.cc",
- "builtin_test.cc",
- "builtin_texture_test.cc",
- "call_test.cc",
- "case_test.cc",
- "cast_test.cc",
- "const_assert_test.cc",
- "constructor_test.cc",
- "continue_test.cc",
- "discard_test.cc",
- "function_test.cc",
- "helper_test.h",
- "identifier_test.cc",
- "if_test.cc",
- "import_test.cc",
- "loop_test.cc",
- "member_accessor_test.cc",
- "module_constant_test.cc",
- "return_test.cc",
- "sanitizer_test.cc",
- "switch_test.cc",
- "type_test.cc",
- "unary_op_test.cc",
- "variable_decl_statement_test.cc",
- "workgroup_var_test.cc",
- ]
- deps = [
- "${dawn_root}/src/utils:utils",
- "${tint_src_dir}:gmock_and_gtest",
- "${tint_src_dir}/api/common",
- "${tint_src_dir}/lang/core",
- "${tint_src_dir}/lang/core/constant",
- "${tint_src_dir}/lang/core/type",
- "${tint_src_dir}/lang/hlsl/writer/common",
- "${tint_src_dir}/lang/wgsl",
- "${tint_src_dir}/lang/wgsl/ast",
- "${tint_src_dir}/lang/wgsl/ast:unittests",
- "${tint_src_dir}/lang/wgsl/ast/transform",
- "${tint_src_dir}/lang/wgsl/program",
- "${tint_src_dir}/lang/wgsl/resolver",
- "${tint_src_dir}/lang/wgsl/sem",
- "${tint_src_dir}/utils",
- "${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/rtti",
- "${tint_src_dir}/utils/symbol",
- "${tint_src_dir}/utils/text",
- "${tint_src_dir}/utils/text_generator",
- ]
-
- if (tint_build_hlsl_writer) {
- deps += [
- "${tint_src_dir}/lang/hlsl/writer",
- "${tint_src_dir}/lang/hlsl/writer/ast_printer",
- "${tint_src_dir}/lang/hlsl/writer/ast_raise",
- ]
- }
- }
- }
-}
diff --git a/src/tint/lang/hlsl/writer/ast_printer/array_accessor_test.cc b/src/tint/lang/hlsl/writer/ast_printer/array_accessor_test.cc
deleted file mode 100644
index fb7626d..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/array_accessor_test.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2020 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-// list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "src/tint/lang/core/fluent_types.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/utils/text/string_stream.h"
-
-using namespace tint::core::number_suffixes; // NOLINT
-using namespace tint::core::fluent_types; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Expression = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Expression, IndexAccessor) {
- GlobalVar("ary", ty.array<i32, 10>(), core::AddressSpace::kPrivate);
- auto* expr = IndexAccessor("ary", 5_i);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "ary[5]");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/assign_test.cc b/src/tint/lang/hlsl/writer/ast_printer/assign_test.cc
deleted file mode 100644
index f2734ca..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/assign_test.cc
+++ /dev/null
@@ -1,438 +0,0 @@
-// Copyright 2020 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-// list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "src/tint/lang/core/fluent_types.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/helper_test.h"
-
-using namespace tint::core::number_suffixes; // NOLINT
-using namespace tint::core::fluent_types; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Assign = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Assign) {
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.i32())),
- Decl(Var("rhs", ty.i32())),
- Assign("lhs", "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(gen.Result(),
- R"(void fn() {
- int lhs = 0;
- int rhs = 0;
- lhs = rhs;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Vector_Assign_LetIndex) {
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.vec3<f32>())),
- Decl(Var("rhs", ty.f32())),
- Decl(Let("index", ty.u32(), Expr(0_u))),
- Assign(IndexAccessor("lhs", "index"), "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(gen.Result(),
- R"(void set_vector_element(inout float3 vec, int idx, float val) {
- vec = (idx.xxx == int3(0, 1, 2)) ? val.xxx : vec;
-}
-
-void fn() {
- float3 lhs = float3(0.0f, 0.0f, 0.0f);
- float rhs = 0.0f;
- uint index = 0u;
- set_vector_element(lhs, index, rhs);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Vector_Assign_ConstIndex) {
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.vec3<f32>())),
- Decl(Var("rhs", ty.f32())),
- Decl(Const("index", ty.u32(), Expr(0_u))),
- Assign(IndexAccessor("lhs", "index"), "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(gen.Result(),
- R"(void fn() {
- float3 lhs = float3(0.0f, 0.0f, 0.0f);
- float rhs = 0.0f;
- lhs[0u] = rhs;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Vector_Assign_DynamicIndex) {
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.vec3<f32>())),
- Decl(Var("rhs", ty.f32())),
- Decl(Var("index", ty.u32())),
- Assign(IndexAccessor("lhs", "index"), "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(gen.Result(),
- R"(void set_vector_element(inout float3 vec, int idx, float val) {
- vec = (idx.xxx == int3(0, 1, 2)) ? val.xxx : vec;
-}
-
-void fn() {
- float3 lhs = float3(0.0f, 0.0f, 0.0f);
- float rhs = 0.0f;
- uint index = 0u;
- set_vector_element(lhs, index, rhs);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Matrix_Assign_Vector_LetIndex) {
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.mat4x2<f32>())),
- Decl(Var("rhs", ty.vec2<f32>())),
- Decl(Let("index", ty.u32(), Expr(0_u))),
- Assign(IndexAccessor("lhs", "index"), "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(gen.Result(),
- R"(void set_matrix_column(inout float4x2 mat, int col, float2 val) {
- switch (col) {
- case 0: mat[0] = val; break;
- case 1: mat[1] = val; break;
- case 2: mat[2] = val; break;
- case 3: mat[3] = val; break;
- }
-}
-
-void fn() {
- float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
- float2 rhs = float2(0.0f, 0.0f);
- uint index = 0u;
- set_matrix_column(lhs, index, rhs);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Matrix_Assign_Vector_ConstIndex) {
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.mat4x2<f32>())),
- Decl(Var("rhs", ty.vec2<f32>())),
- Decl(Const("index", ty.u32(), Expr(0_u))),
- Assign(IndexAccessor("lhs", "index"), "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(gen.Result(),
- R"(void fn() {
- float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
- float2 rhs = float2(0.0f, 0.0f);
- lhs[0u] = rhs;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Matrix_Assign_Vector_DynamicIndex) {
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.mat4x2<f32>())),
- Decl(Var("rhs", ty.vec2<f32>())),
- Decl(Var("index", ty.u32())),
- Assign(IndexAccessor("lhs", "index"), "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(gen.Result(),
- R"(void set_matrix_column(inout float4x2 mat, int col, float2 val) {
- switch (col) {
- case 0: mat[0] = val; break;
- case 1: mat[1] = val; break;
- case 2: mat[2] = val; break;
- case 3: mat[3] = val; break;
- }
-}
-
-void fn() {
- float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
- float2 rhs = float2(0.0f, 0.0f);
- uint index = 0u;
- set_matrix_column(lhs, index, rhs);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Matrix_Assign_Scalar_LetIndices) {
- auto* col = IndexAccessor("lhs", "col");
- auto* el = IndexAccessor(col, "row");
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.mat4x2<f32>())),
- Decl(Var("rhs", ty.f32())),
- Decl(Let("col", ty.u32(), Expr(0_u))),
- Decl(Let("row", ty.u32(), Expr(1_u))),
- Assign(el, "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(gen.Result(),
- R"(void set_matrix_scalar(inout float4x2 mat, int col, int row, float val) {
- switch (col) {
- case 0:
- mat[0] = (row.xx == int2(0, 1)) ? val.xx : mat[0];
- break;
- case 1:
- mat[1] = (row.xx == int2(0, 1)) ? val.xx : mat[1];
- break;
- case 2:
- mat[2] = (row.xx == int2(0, 1)) ? val.xx : mat[2];
- break;
- case 3:
- mat[3] = (row.xx == int2(0, 1)) ? val.xx : mat[3];
- break;
- }
-}
-
-void fn() {
- float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
- float rhs = 0.0f;
- uint col = 0u;
- uint row = 1u;
- set_matrix_scalar(lhs, col, row, rhs);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Matrix_Assign_Scalar_ConstIndices) {
- auto* col = IndexAccessor("lhs", "col");
- auto* el = IndexAccessor(col, "row");
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.mat4x2<f32>())),
- Decl(Var("rhs", ty.f32())),
- Decl(Const("col", ty.u32(), Expr(0_u))),
- Decl(Const("row", ty.u32(), Expr(1_u))),
- Assign(el, "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(gen.Result(),
- R"(void fn() {
- float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
- float rhs = 0.0f;
- lhs[0u][1u] = rhs;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Matrix_Assign_Scalar_DynamicIndices) {
- auto* col = IndexAccessor("lhs", "col");
- auto* el = IndexAccessor(col, "row");
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.mat4x2<f32>())),
- Decl(Var("rhs", ty.f32())),
- Decl(Var("col", ty.u32())),
- Decl(Var("row", ty.u32())),
- Assign(el, "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(gen.Result(),
- R"(void set_matrix_scalar(inout float4x2 mat, int col, int row, float val) {
- switch (col) {
- case 0:
- mat[0] = (row.xx == int2(0, 1)) ? val.xx : mat[0];
- break;
- case 1:
- mat[1] = (row.xx == int2(0, 1)) ? val.xx : mat[1];
- break;
- case 2:
- mat[2] = (row.xx == int2(0, 1)) ? val.xx : mat[2];
- break;
- case 3:
- mat[3] = (row.xx == int2(0, 1)) ? val.xx : mat[3];
- break;
- }
-}
-
-void fn() {
- float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
- float rhs = 0.0f;
- uint col = 0u;
- uint row = 0u;
- set_matrix_scalar(lhs, col, row, rhs);
-}
-)");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Assignment to composites of f16
-// See crbug.com/tint/2146
-////////////////////////////////////////////////////////////////////////////////
-TEST_F(HlslASTPrinterTest_Assign, Emit_Vector_f16_Assign) {
- Enable(wgsl::Extension::kF16);
-
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.vec3<f16>())),
- Decl(Var("rhs", ty.f16())),
- Decl(Let("index", ty.u32(), Expr(0_u))),
- Assign(IndexAccessor("lhs", "index"), "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(gen.Result(),
- R"(void set_vector_element(inout vector<float16_t, 3> vec, int idx, float16_t val) {
- vec = (idx.xxx == int3(0, 1, 2)) ? val.xxx : vec;
-}
-
-void fn() {
- vector<float16_t, 3> lhs = vector<float16_t, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
- float16_t rhs = float16_t(0.0h);
- uint index = 0u;
- set_vector_element(lhs, index, rhs);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Matrix_f16_Assign_Vector) {
- Enable(wgsl::Extension::kF16);
-
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.mat4x2<f16>())),
- Decl(Var("rhs", ty.vec2<f16>())),
- Decl(Let("index", ty.u32(), Expr(0_u))),
- Assign(IndexAccessor("lhs", "index"), "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(
- gen.Result(),
- R"(void set_matrix_column(inout matrix<float16_t, 4, 2> mat, int col, vector<float16_t, 2> val) {
- switch (col) {
- case 0: mat[0] = val; break;
- case 1: mat[1] = val; break;
- case 2: mat[2] = val; break;
- case 3: mat[3] = val; break;
- }
-}
-
-void fn() {
- matrix<float16_t, 4, 2> lhs = matrix<float16_t, 4, 2>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
- vector<float16_t, 2> rhs = vector<float16_t, 2>(float16_t(0.0h), float16_t(0.0h));
- uint index = 0u;
- set_matrix_column(lhs, index, rhs);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Assign, Emit_Matrix_f16_Assign_Scalar) {
- Enable(wgsl::Extension::kF16);
-
- auto* col = IndexAccessor("lhs", "col");
- auto* el = IndexAccessor(col, "row");
- Func("fn", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("lhs", ty.mat4x2<f16>())),
- Decl(Var("rhs", ty.f16())),
- Decl(Let("col", ty.u32(), Expr(0_u))),
- Decl(Let("row", ty.u32(), Expr(1_u))),
- Assign(el, "rhs"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate());
- EXPECT_EQ(
- gen.Result(),
- R"(void set_matrix_scalar(inout matrix<float16_t, 4, 2> mat, int col, int row, float16_t val) {
- switch (col) {
- case 0:
- mat[0] = (row.xx == int2(0, 1)) ? val.xx : mat[0];
- break;
- case 1:
- mat[1] = (row.xx == int2(0, 1)) ? val.xx : mat[1];
- break;
- case 2:
- mat[2] = (row.xx == int2(0, 1)) ? val.xx : mat[2];
- break;
- case 3:
- mat[3] = (row.xx == int2(0, 1)) ? val.xx : mat[3];
- break;
- }
-}
-
-void fn() {
- matrix<float16_t, 4, 2> lhs = matrix<float16_t, 4, 2>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
- float16_t rhs = float16_t(0.0h);
- uint col = 0u;
- uint row = 1u;
- set_matrix_scalar(lhs, col, row, rhs);
-}
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
deleted file mode 100644
index 453b544..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ /dev/null
@@ -1,5058 +0,0 @@
-/// Copyright 2020 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/hlsl/writer/ast_printer/ast_printer.h"
-
-#include <cmath>
-#include <functional>
-#include <iomanip>
-#include <utility>
-#include <vector>
-
-#include "src/tint/api/common/binding_point.h"
-#include "src/tint/lang/core/constant/splat.h"
-#include "src/tint/lang/core/constant/value.h"
-#include "src/tint/lang/core/fluent_types.h"
-#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/multisampled_texture.h"
-#include "src/tint/lang/core/type/sampled_texture.h"
-#include "src/tint/lang/core/type/storage_texture.h"
-#include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.h"
-#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/truncate_interstage_variables.h"
-#include "src/tint/lang/hlsl/writer/common/option_helpers.h"
-#include "src/tint/lang/wgsl/ast/call_statement.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"
-#include "src/tint/lang/wgsl/ast/transform/array_length_from_uniform.h"
-#include "src/tint/lang/wgsl/ast/transform/binding_remapper.h"
-#include "src/tint/lang/wgsl/ast/transform/builtin_polyfill.h"
-#include "src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.h"
-#include "src/tint/lang/wgsl/ast/transform/demote_to_helper.h"
-#include "src/tint/lang/wgsl/ast/transform/direct_variable_access.h"
-#include "src/tint/lang/wgsl/ast/transform/disable_uniformity_analysis.h"
-#include "src/tint/lang/wgsl/ast/transform/expand_compound_assignment.h"
-#include "src/tint/lang/wgsl/ast/transform/fold_constants.h"
-#include "src/tint/lang/wgsl/ast/transform/manager.h"
-#include "src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.h"
-#include "src/tint/lang/wgsl/ast/transform/promote_initializers_to_let.h"
-#include "src/tint/lang/wgsl/ast/transform/promote_side_effects_to_decl.h"
-#include "src/tint/lang/wgsl/ast/transform/remove_continue_in_switch.h"
-#include "src/tint/lang/wgsl/ast/transform/remove_phonies.h"
-#include "src/tint/lang/wgsl/ast/transform/robustness.h"
-#include "src/tint/lang/wgsl/ast/transform/simplify_pointers.h"
-#include "src/tint/lang/wgsl/ast/transform/unshadow.h"
-#include "src/tint/lang/wgsl/ast/transform/vectorize_scalar_matrix_initializers.h"
-#include "src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.h"
-#include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
-#include "src/tint/lang/wgsl/sem/block_statement.h"
-#include "src/tint/lang/wgsl/sem/call.h"
-#include "src/tint/lang/wgsl/sem/function.h"
-#include "src/tint/lang/wgsl/sem/member_accessor_expression.h"
-#include "src/tint/lang/wgsl/sem/module.h"
-#include "src/tint/lang/wgsl/sem/statement.h"
-#include "src/tint/lang/wgsl/sem/struct.h"
-#include "src/tint/lang/wgsl/sem/switch_statement.h"
-#include "src/tint/lang/wgsl/sem/value_constructor.h"
-#include "src/tint/lang/wgsl/sem/value_conversion.h"
-#include "src/tint/lang/wgsl/sem/variable.h"
-#include "src/tint/utils/containers/map.h"
-#include "src/tint/utils/containers/transform.h"
-#include "src/tint/utils/ice/ice.h"
-#include "src/tint/utils/macros/compiler.h"
-#include "src/tint/utils/macros/defer.h"
-#include "src/tint/utils/macros/scoped_assignment.h"
-#include "src/tint/utils/rtti/switch.h"
-#include "src/tint/utils/strconv/float_to_string.h"
-#include "src/tint/utils/text/string.h"
-#include "src/tint/utils/text/string_stream.h"
-
-using namespace tint::core::number_suffixes; // NOLINT
-using namespace tint::core::fluent_types; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-const char kTempNamePrefix[] = "tint_tmp";
-
-static constexpr std::array<char, 4> kSwizzle = {'x', 'y', 'z', 'w'};
-
-const char* ImageFormatToRWtextureType(core::TexelFormat image_format) {
- switch (image_format) {
- case core::TexelFormat::kR8Unorm:
- case core::TexelFormat::kBgra8Unorm:
- case core::TexelFormat::kRgba8Unorm:
- case core::TexelFormat::kRgba8Snorm:
- case core::TexelFormat::kRgba16Float:
- case core::TexelFormat::kR32Float:
- case core::TexelFormat::kRg32Float:
- case core::TexelFormat::kRgba32Float:
- return "float4";
- case core::TexelFormat::kRgba8Uint:
- case core::TexelFormat::kRgba16Uint:
- case core::TexelFormat::kR32Uint:
- case core::TexelFormat::kRg32Uint:
- case core::TexelFormat::kRgba32Uint:
- return "uint4";
- case core::TexelFormat::kRgba8Sint:
- case core::TexelFormat::kRgba16Sint:
- case core::TexelFormat::kR32Sint:
- case core::TexelFormat::kRg32Sint:
- case core::TexelFormat::kRgba32Sint:
- return "int4";
- default:
- return nullptr;
- }
-}
-
-void PrintF32(StringStream& out, float value) {
- if (std::isinf(value)) {
- out << "0.0f " << (value >= 0 ? "/* inf */" : "/* -inf */");
- } else if (std::isnan(value)) {
- out << "0.0f /* nan */";
- } else {
- out << tint::strconv::FloatToString(value) << "f";
- }
-}
-
-void PrintF16(StringStream& out, float value) {
- if (std::isinf(value)) {
- out << "0.0h " << (value >= 0 ? "/* inf */" : "/* -inf */");
- } else if (std::isnan(value)) {
- out << "0.0h /* nan */";
- } else {
- out << tint::strconv::FloatToString(value) << "h";
- }
-}
-
-// Helper for writing " : register(RX, spaceY)", where R is the register, X is
-// the binding point binding value, and Y is the binding point group value.
-struct RegisterAndSpace {
- RegisterAndSpace(char r, BindingPoint bp) : reg(r), binding_point(bp) {}
-
- const char reg;
- BindingPoint const binding_point;
-};
-
-StringStream& operator<<(StringStream& s, const RegisterAndSpace& rs) {
- s << " : register(" << rs.reg << rs.binding_point.binding;
- // Omit the space if it's 0, as it's the default.
- // SM 5.0 doesn't support spaces, so we don't emit them if group is 0 for better compatibility.
- if (rs.binding_point.group == 0) {
- s << ")";
- } else {
- s << ", space" << rs.binding_point.group << ")";
- }
- return s;
-}
-
-struct VectorConstructorInfo {
- const sem::Call* call = nullptr;
- const sem::ValueConstructor* ctor = nullptr;
- explicit operator bool() const { return call != nullptr; }
-};
-VectorConstructorInfo AsVectorConstructor(const sem::ValueExpression* expr) {
- if (auto* call = expr->As<sem::Call>()) {
- if (auto* ctor = call->Target()->As<sem::ValueConstructor>()) {
- if (ctor->ReturnType()->Is<core::type::Vector>()) {
- return {call, ctor};
- }
- }
- }
- return {};
-}
-
-const sem::ValueExpression* Zero(ProgramBuilder& b,
- const core::type::Type* ty,
- const sem::Statement* stmt) {
- const ast::Expression* expr = nullptr;
- if (ty->Is<core::type::I32>()) {
- expr = b.Expr(0_i);
- } else if (ty->Is<core::type::U32>()) {
- expr = b.Expr(0_u);
- } else if (ty->Is<core::type::F32>()) {
- expr = b.Expr(0_f);
- } else if (ty->Is<core::type::Bool>()) {
- expr = b.Expr(false);
- } else {
- TINT_UNREACHABLE() << "unsupported vector element type: " << ty->TypeInfo().name;
- }
- auto* sem = b.create<sem::ValueExpression>(expr, ty, core::EvaluationStage::kRuntime, stmt,
- /* constant_value */ nullptr,
- /* has_side_effects */ false);
- b.Sem().Add(expr, sem);
- return sem;
-}
-
-const sem::Call* AppendVector(ProgramBuilder* b,
- const ast::Expression* vector_ast,
- const ast::Expression* scalar_ast) {
- uint32_t packed_size;
- const core::type::Type* packed_el_sem_ty;
- auto* vector_sem = b->Sem().GetVal(vector_ast);
- auto* scalar_sem = b->Sem().GetVal(scalar_ast);
- auto* vector_ty = vector_sem->Type()->UnwrapRef();
- if (auto* vec = vector_ty->As<core::type::Vector>()) {
- packed_size = vec->Width() + 1;
- packed_el_sem_ty = vec->Type();
- } else {
- packed_size = 2;
- packed_el_sem_ty = vector_ty;
- }
-
- auto packed_el_ast_ty = Switch(
- packed_el_sem_ty, //
- [&](const core::type::I32*) { return b->ty.i32(); },
- [&](const core::type::U32*) { return b->ty.u32(); },
- [&](const core::type::F32*) { return b->ty.f32(); },
- [&](const core::type::Bool*) { return b->ty.bool_(); }, //
- TINT_ICE_ON_NO_MATCH);
-
- auto* statement = vector_sem->Stmt();
-
- auto packed_ast_ty = b->ty.vec(packed_el_ast_ty, packed_size);
- auto* packed_sem_ty = b->create<core::type::Vector>(packed_el_sem_ty, packed_size);
-
- // If the coordinates are already passed in a vector constructor, with only
- // scalar components supplied, extract the elements into the new vector
- // instead of nesting a vector-in-vector.
- // If the coordinates are a zero-constructor of the vector, then expand that
- // to scalar zeros.
- // The other cases for a nested vector constructor are when it is used
- // to convert a vector of a different type, e.g. vec2<i32>(vec2<u32>()).
- // In that case, preserve the original argument, or you'll get a type error.
-
- Vector<const sem::ValueExpression*, 4> packed;
- if (auto vc = AsVectorConstructor(vector_sem)) {
- const auto num_supplied = vc.call->Arguments().Length();
- if (num_supplied == 0) {
- // Zero-value vector constructor. Populate with zeros
- for (uint32_t i = 0; i < packed_size - 1; i++) {
- auto* zero = Zero(*b, packed_el_sem_ty, statement);
- packed.Push(zero);
- }
- } else if (num_supplied + 1 == packed_size) {
- // All vector components were supplied as scalars. Pass them through.
- packed = vc.call->Arguments();
- }
- }
- if (packed.IsEmpty()) {
- // The special cases didn't occur. Use the vector argument as-is.
- packed.Push(vector_sem);
- }
-
- if (packed_el_sem_ty != scalar_sem->Type()->UnwrapRef()) {
- // Cast scalar to the vector element type
- auto* scalar_cast_ast = b->Call(packed_el_ast_ty, scalar_ast);
- auto* param = b->create<sem::Parameter>(nullptr, 0u, scalar_sem->Type()->UnwrapRef());
- auto* scalar_cast_target = b->create<sem::ValueConversion>(packed_el_sem_ty, param,
- core::EvaluationStage::kRuntime);
- auto* scalar_cast_sem = b->create<sem::Call>(
- scalar_cast_ast, scalar_cast_target, core::EvaluationStage::kRuntime,
- Vector<const sem::ValueExpression*, 1>{scalar_sem}, statement,
- /* constant_value */ nullptr, /* has_side_effects */ false);
- b->Sem().Add(scalar_cast_ast, scalar_cast_sem);
- packed.Push(scalar_cast_sem);
- } else {
- packed.Push(scalar_sem);
- }
-
- auto* ctor_ast =
- b->Call(packed_ast_ty, tint::Transform(packed, [&](const sem::ValueExpression* expr) {
- return expr->Declaration();
- }));
- auto* ctor_target = b->create<sem::ValueConstructor>(
- packed_sem_ty,
- tint::Transform(packed,
- [&](const tint::sem::ValueExpression* arg, size_t i) {
- return b->create<sem::Parameter>(nullptr, static_cast<uint32_t>(i),
- arg->Type()->UnwrapRef());
- }),
- core::EvaluationStage::kRuntime);
- auto* ctor_sem = b->create<sem::Call>(ctor_ast, ctor_target, core::EvaluationStage::kRuntime,
- std::move(packed), statement,
- /* constant_value */ nullptr,
- /* has_side_effects */ false);
- b->Sem().Add(ctor_ast, ctor_sem);
- return ctor_sem;
-}
-
-bool CheckSupportedExtensions(std::string_view writer_name,
- const ast::Module& module,
- diag::List& diags,
- VectorRef<wgsl::Extension> supported) {
- Hashset<wgsl::Extension, 32> set;
- for (auto ext : supported) {
- set.Add(ext);
- }
-
- for (auto* enable : module.Enables()) {
- for (auto* ext : enable->extensions) {
- if (!set.Contains(ext->name)) {
- diags.AddError(ext->source) << writer_name << " backend does not support extension "
- << style::Code(ext->name);
- return false;
- }
- }
- }
- return true;
-}
-
-} // namespace
-
-SanitizedResult::SanitizedResult() = default;
-SanitizedResult::~SanitizedResult() = default;
-SanitizedResult::SanitizedResult(SanitizedResult&&) = default;
-
-SanitizedResult Sanitize(const Program& in, const Options& options) {
- ast::transform::Manager manager;
- ast::transform::DataMap data;
-
- manager.Add<ast::transform::FoldConstants>();
-
- manager.Add<ast::transform::DisableUniformityAnalysis>();
-
- // ExpandCompoundAssignment must come before BuiltinPolyfill
- manager.Add<ast::transform::ExpandCompoundAssignment>();
-
- manager.Add<ast::transform::Unshadow>(); // Must come before DirectVariableAccess
-
- // LocalizeStructArrayAssignment must come after:
- // * SimplifyPointers, because it assumes assignment to arrays in structs are
- // done directly, not indirectly.
- // TODO(crbug.com/tint/1340): See if we can get rid of the duplicate
- // SimplifyPointers transform. Can't do it right now because
- // LocalizeStructArrayAssignment introduces pointers.
- manager.Add<ast::transform::SimplifyPointers>();
- manager.Add<LocalizeStructArrayAssignment>();
-
- manager.Add<ast::transform::PromoteSideEffectsToDecl>();
-
- if (!options.disable_robustness) {
- // Robustness must come after PromoteSideEffectsToDecl
- // Robustness must come before BuiltinPolyfill and CanonicalizeEntryPointIO
- manager.Add<ast::transform::Robustness>();
-
- ast::transform::Robustness::Config config = {};
- config.bindings_ignored = std::unordered_set<BindingPoint>(
- options.bindings.ignored_by_robustness_transform.cbegin(),
- options.bindings.ignored_by_robustness_transform.cend());
-
- // Direct3D guarantees to return zero for any resource that is accessed out of bounds, and
- // according to the description of the assembly store_uav_typed, out of bounds addressing
- // means nothing gets written to memory.
- config.texture_action = ast::transform::Robustness::Action::kIgnore;
-
- data.Add<ast::transform::Robustness::Config>(config);
- }
-
- tint::transform::multiplanar::BindingsMap multiplanar_map{};
- RemapperData remapper_data{};
- ArrayLengthFromUniformOptions array_length_from_uniform_options{};
- PopulateBindingRelatedOptions(options, remapper_data, multiplanar_map,
- array_length_from_uniform_options);
-
- manager.Add<ast::transform::BindingRemapper>();
- // D3D11 and 12 registers like `t3` and `c3` have the same bindingOffset number in
- // the remapping but should not be considered a collision because they have
- // different types.
- data.Add<ast::transform::BindingRemapper::Remappings>(
- remapper_data, options.bindings.access_controls, /* allow_collisions */ true);
-
- // Note: it is more efficient for MultiplanarExternalTexture to come after Robustness
- // MultiplanarExternalTexture must come after BindingRemapper
- data.Add<ast::transform::MultiplanarExternalTexture::NewBindingPoints>(multiplanar_map,
- /* may_collide */ true);
- manager.Add<ast::transform::MultiplanarExternalTexture>();
-
- { // Builtin polyfills
- ast::transform::BuiltinPolyfill::Builtins polyfills;
- polyfills.acosh = ast::transform::BuiltinPolyfill::Level::kFull;
- polyfills.asinh = true;
- polyfills.atanh = ast::transform::BuiltinPolyfill::Level::kFull;
- polyfills.bitshift_modulo = true;
- polyfills.clamp_int = true;
- // TODO(crbug.com/tint/1449): Some of these can map to HLSL's `firstbitlow`
- // and `firstbithigh`.
- polyfills.conv_f32_to_iu32 = true;
- polyfills.count_leading_zeros = true;
- polyfills.count_trailing_zeros = true;
- polyfills.extract_bits = ast::transform::BuiltinPolyfill::Level::kFull;
- polyfills.first_leading_bit = true;
- polyfills.first_trailing_bit = true;
- polyfills.fwidth_fine = true;
- polyfills.insert_bits = ast::transform::BuiltinPolyfill::Level::kFull;
- polyfills.int_div_mod = !options.disable_polyfill_integer_div_mod;
- polyfills.precise_float_mod = true;
- polyfills.reflect_vec2_f32 = options.polyfill_reflect_vec2_f32;
- polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
- polyfills.workgroup_uniform_load = true;
- polyfills.dot_4x8_packed = options.polyfill_dot_4x8_packed;
- polyfills.pack_unpack_4x8 = options.polyfill_pack_unpack_4x8;
- // Currently Pack4xU8Clamp() must be polyfilled because on latest DXC pack_clamp_u8()
- // receives an int32_t4 as its input.
- // See https://github.com/microsoft/DirectXShaderCompiler/issues/5091 for more details.
- polyfills.pack_4xu8_clamp = true;
- data.Add<ast::transform::BuiltinPolyfill::Config>(polyfills);
- manager.Add<ast::transform::BuiltinPolyfill>(); // Must come before DirectVariableAccess
- }
-
- manager.Add<ast::transform::DirectVariableAccess>();
-
- if (!options.disable_workgroup_init) {
- // ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
- // ZeroInitWorkgroupMemory may inject new builtin parameters.
- manager.Add<ast::transform::ZeroInitWorkgroupMemory>();
- }
-
- {
- PixelLocal::Config cfg;
- for (auto it : options.pixel_local.attachments) {
- uint32_t member_index = it.first;
- auto& attachment = it.second;
-
- cfg.pls_member_to_rov_reg.Add(member_index, attachment.index);
-
- core::TexelFormat format = core::TexelFormat::kUndefined;
- switch (attachment.format) {
- case PixelLocalAttachment::TexelFormat::kR32Sint:
- format = core::TexelFormat::kR32Sint;
- break;
- case PixelLocalAttachment::TexelFormat::kR32Uint:
- format = core::TexelFormat::kR32Uint;
- break;
- case PixelLocalAttachment::TexelFormat::kR32Float:
- format = core::TexelFormat::kR32Float;
- break;
- default:
- TINT_ICE() << "missing texel format for pixel local storage attachment";
- }
- cfg.pls_member_to_rov_format.Add(member_index, format);
- }
- cfg.rov_group_index = options.pixel_local.group_index;
- data.Add<PixelLocal::Config>(cfg);
- manager.Add<PixelLocal>();
- }
-
- // CanonicalizeEntryPointIO must come after Robustness
- manager.Add<ast::transform::CanonicalizeEntryPointIO>();
-
- if (options.truncate_interstage_variables) {
- // When interstage_locations is empty, it means there's no user-defined interstage variables
- // being used in the next stage. Still, HLSL compiler register mismatch could happen, if
- // there's builtin inputs used in the next stage. So we still run
- // TruncateInterstageVariables transform.
-
- // TruncateInterstageVariables itself will skip when interstage_locations matches exactly
- // with the current stage output.
-
- // Build the config for internal TruncateInterstageVariables transform.
- TruncateInterstageVariables::Config truncate_interstage_variables_cfg;
- truncate_interstage_variables_cfg.interstage_locations =
- std::move(options.interstage_locations);
- manager.Add<TruncateInterstageVariables>();
- data.Add<TruncateInterstageVariables::Config>(std::move(truncate_interstage_variables_cfg));
- }
-
- // NumWorkgroupsFromUniform must come after CanonicalizeEntryPointIO, as it
- // assumes that num_workgroups builtins only appear as struct members and are
- // only accessed directly via member accessors.
- manager.Add<NumWorkgroupsFromUniform>();
- manager.Add<ast::transform::VectorizeScalarMatrixInitializers>();
- manager.Add<ast::transform::SimplifyPointers>();
- manager.Add<ast::transform::RemovePhonies>();
-
- // DemoteToHelper must come after CanonicalizeEntryPointIO, PromoteSideEffectsToDecl, and
- // ExpandCompoundAssignment.
- // TODO(crbug.com/42250787): This is only necessary when FXC is being used.
- if (options.compiler == tint::hlsl::writer::Options::Compiler::kFXC) {
- manager.Add<ast::transform::DemoteToHelper>();
- }
-
- // ArrayLengthFromUniform must come after SimplifyPointers as it assumes that the form of the
- // array length argument is &var.array.
- manager.Add<ast::transform::ArrayLengthFromUniform>();
- // Build the config for the internal ArrayLengthFromUniform transform.
- ast::transform::ArrayLengthFromUniform::Config array_length_from_uniform_cfg(
- BindingPoint{array_length_from_uniform_options.ubo_binding.group,
- array_length_from_uniform_options.ubo_binding.binding});
- array_length_from_uniform_cfg.bindpoint_to_size_index =
- std::move(array_length_from_uniform_options.bindpoint_to_size_index);
- data.Add<ast::transform::ArrayLengthFromUniform::Config>(
- std::move(array_length_from_uniform_cfg));
- // DecomposeMemoryAccess must come after:
- // * SimplifyPointers, as we cannot take the address of calls to
- // DecomposeMemoryAccess::Intrinsic and we need to fold away the address-of and dereferences
- // of `*(&(intrinsic_load()))` expressions.
- // * RemovePhonies, as phonies can be assigned a pointer to a
- // non-constructible buffer, or dynamic array, which DMA cannot cope with.
- manager.Add<DecomposeMemoryAccess>();
- // CalculateArrayLength must come after DecomposeMemoryAccess, as
- // DecomposeMemoryAccess special-cases the arrayLength() intrinsic, which
- // will be transformed by CalculateArrayLength
- manager.Add<CalculateArrayLength>();
- manager.Add<ast::transform::PromoteInitializersToLet>();
-
- manager.Add<ast::transform::RemoveContinueInSwitch>();
-
- manager.Add<ast::transform::AddEmptyEntryPoint>();
-
- data.Add<NumWorkgroupsFromUniform::Config>(options.root_constant_binding_point);
-
- SanitizedResult result;
- ast::transform::DataMap outputs;
- result.program = manager.Run(in, data, outputs);
- if (auto* res = outputs.Get<ast::transform::ArrayLengthFromUniform::Result>()) {
- result.used_array_length_from_uniform_indices = std::move(res->used_size_indices);
- }
- return result;
-}
-
-ASTPrinter::ASTPrinter(const Program& program) : builder_(ProgramBuilder::Wrap(program)) {}
-
-ASTPrinter::~ASTPrinter() = default;
-
-bool ASTPrinter::Generate() {
- if (!CheckSupportedExtensions("HLSL", builder_.AST(), diagnostics_,
- Vector{
- wgsl::Extension::kChromiumDisableUniformityAnalysis,
- wgsl::Extension::kChromiumExperimentalPixelLocal,
- wgsl::Extension::kChromiumExperimentalImmediate,
- wgsl::Extension::kChromiumInternalGraphite,
- wgsl::Extension::kClipDistances,
- wgsl::Extension::kF16,
- wgsl::Extension::kDualSourceBlending,
- wgsl::Extension::kSubgroups,
- })) {
- return false;
- }
-
- // Goldilocks logic to add lines between top level declarations
- const tint::TypeInfo* last_kind = nullptr;
- size_t last_padding_line = 0;
- auto EmitPaddingLine = [&](const tint::TypeInfo* kind, bool is_function) {
- // Don't emit double line breaks
- if (current_buffer_->lines.size() == last_padding_line) {
- last_kind = kind;
- return;
- }
-
- if (is_function || (last_kind && last_kind != kind)) {
- Line();
- last_padding_line = current_buffer_->lines.size();
- last_kind = kind;
- global_insertion_point_ = current_buffer_->lines.size();
- }
- };
-
- auto* mod = builder_.Sem().Module();
- for (auto* decl : mod->DependencyOrderedDeclarations()) {
- if (decl->IsAnyOf<ast::Alias, ast::DiagnosticDirective, ast::Enable, ast::Requires,
- ast::ConstAssert>()) {
- continue; // These are not emitted.
- }
-
- global_insertion_point_ = current_buffer_->lines.size();
-
- bool ok = Switch(
- decl,
- [&](const ast::Variable* global) {
- EmitPaddingLine(&decl->TypeInfo(), false);
- return EmitGlobalVariable(global);
- },
- [&](const ast::Struct* str) {
- auto* ty = builder_.Sem().Get(str);
- auto address_space_uses = ty->AddressSpaceUsage();
- if (address_space_uses.Count() !=
- ((address_space_uses.Contains(core::AddressSpace::kStorage) ? 1u : 0u) +
- (address_space_uses.Contains(core::AddressSpace::kUniform) ? 1u : 0u))) {
- // The structure is used as something other than a storage buffer or
- // uniform buffer, so it needs to be emitted.
- // Storage buffer are read and written to via a ByteAddressBuffer
- // instead of true structure.
- // Structures used as uniform buffer are read from an array of
- // vectors instead of true structure.
- EmitPaddingLine(&decl->TypeInfo(), false);
- return EmitStructType(current_buffer_, ty, str->members);
- }
- return true;
- },
- [&](const ast::Function* func) {
- EmitPaddingLine(&decl->TypeInfo(), true);
- if (func->IsEntryPoint()) {
- return EmitEntryPointFunction(func);
- }
- return EmitFunction(func);
- }, //
- TINT_ICE_ON_NO_MATCH);
-
- if (!ok) {
- return false;
- }
- }
-
- if (!helpers_.lines.empty()) {
- current_buffer_->Insert(helpers_, 0, 0);
- }
-
- return true;
-}
-
-bool ASTPrinter::EmitDynamicVectorAssignment(const ast::AssignmentStatement* stmt,
- const core::type::Vector* vec) {
- auto name = tint::GetOrAdd(dynamic_vector_write_, vec, [&]() -> std::string {
- std::string fn = UniqueIdentifier("set_vector_element");
- {
- auto out = Line(&helpers_);
- out << "void " << fn << "(inout ";
- if (!EmitTypeAndName(out, vec, core::AddressSpace::kUndefined, core::Access::kUndefined,
- "vec")) {
- return "";
- }
- out << ", int idx, ";
- if (!EmitTypeAndName(out, vec->Type(), core::AddressSpace::kUndefined,
- core::Access::kUndefined, "val")) {
- return "";
- }
- out << ") {";
- }
- {
- ScopedIndent si(&helpers_);
- auto out = Line(&helpers_);
- switch (vec->Width()) {
- case 2:
- out << "vec = (idx.xx == int2(0, 1)) ? val.xx : vec;";
- break;
- case 3:
- out << "vec = (idx.xxx == int3(0, 1, 2)) ? val.xxx : vec;";
- break;
- case 4:
- out << "vec = (idx.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : vec;";
- break;
- default:
- TINT_UNREACHABLE() << "invalid vector size " << vec->Width();
- }
- }
- Line(&helpers_) << "}";
- Line(&helpers_);
- return fn;
- });
-
- if (name.empty()) {
- return false;
- }
-
- auto* ast_access_expr = stmt->lhs->As<ast::IndexAccessorExpression>();
-
- auto out = Line();
- out << name << "(";
- if (!EmitExpression(out, ast_access_expr->object)) {
- return false;
- }
- out << ", ";
- if (!EmitExpression(out, ast_access_expr->index)) {
- return false;
- }
- out << ", ";
- if (!EmitExpression(out, stmt->rhs)) {
- return false;
- }
- out << ");";
-
- return true;
-}
-
-bool ASTPrinter::EmitDynamicMatrixVectorAssignment(const ast::AssignmentStatement* stmt,
- const core::type::Matrix* mat) {
- auto name = tint::GetOrAdd(dynamic_matrix_vector_write_, mat, [&]() -> std::string {
- std::string fn = UniqueIdentifier("set_matrix_column");
- {
- auto out = Line(&helpers_);
- out << "void " << fn << "(inout ";
- if (!EmitTypeAndName(out, mat, core::AddressSpace::kUndefined, core::Access::kUndefined,
- "mat")) {
- return "";
- }
- out << ", int col, ";
- if (!EmitTypeAndName(out, mat->ColumnType(), core::AddressSpace::kUndefined,
- core::Access::kUndefined, "val")) {
- return "";
- }
- out << ") {";
- }
- {
- ScopedIndent si(&helpers_);
- Line(&helpers_) << "switch (col) {";
- {
- ScopedIndent si2(&helpers_);
- for (uint32_t i = 0; i < mat->Columns(); ++i) {
- Line(&helpers_) << "case " << i << ": mat[" << i << "] = val; break;";
- }
- }
- Line(&helpers_) << "}";
- }
- Line(&helpers_) << "}";
- Line(&helpers_);
- return fn;
- });
-
- if (name.empty()) {
- return false;
- }
-
- auto* ast_access_expr = stmt->lhs->As<ast::IndexAccessorExpression>();
-
- auto out = Line();
- out << name << "(";
- if (!EmitExpression(out, ast_access_expr->object)) {
- return false;
- }
- out << ", ";
- if (!EmitExpression(out, ast_access_expr->index)) {
- return false;
- }
- out << ", ";
- if (!EmitExpression(out, stmt->rhs)) {
- return false;
- }
- out << ");";
-
- return true;
-}
-
-bool ASTPrinter::EmitDynamicMatrixScalarAssignment(const ast::AssignmentStatement* stmt,
- const core::type::Matrix* mat) {
- auto* lhs_row_access = stmt->lhs->As<ast::IndexAccessorExpression>();
- auto* lhs_col_access = lhs_row_access->object->As<ast::IndexAccessorExpression>();
-
- auto name = tint::GetOrAdd(dynamic_matrix_scalar_write_, mat, [&]() -> std::string {
- std::string fn = UniqueIdentifier("set_matrix_scalar");
- {
- auto out = Line(&helpers_);
- out << "void " << fn << "(inout ";
- if (!EmitTypeAndName(out, mat, core::AddressSpace::kUndefined, core::Access::kUndefined,
- "mat")) {
- return "";
- }
- out << ", int col, int row, ";
- if (!EmitTypeAndName(out, mat->Type(), core::AddressSpace::kUndefined,
- core::Access::kUndefined, "val")) {
- return "";
- }
- out << ") {";
- }
- {
- ScopedIndent si(&helpers_);
- Line(&helpers_) << "switch (col) {";
- {
- ScopedIndent si2(&helpers_);
- for (uint32_t i = 0; i < mat->Columns(); ++i) {
- Line(&helpers_) << "case " << i << ":";
- {
- auto vec_name = "mat[" + std::to_string(i) + "]";
- ScopedIndent si3(&helpers_);
- {
- auto out = Line(&helpers_);
- switch (mat->Rows()) {
- case 2:
- out << vec_name
- << " = (row.xx == int2(0, 1)) ? val.xx : " << vec_name
- << ";";
- break;
- case 3:
- out << vec_name
- << " = (row.xxx == int3(0, 1, 2)) ? val.xxx : " << vec_name
- << ";";
- break;
- case 4:
- out << vec_name
- << " = (row.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : "
- << vec_name << ";";
- break;
- default: {
- auto* vec = TypeOf(lhs_row_access->object)
- ->UnwrapPtrOrRef()
- ->As<core::type::Vector>();
- TINT_UNREACHABLE() << "invalid vector size " << vec->Width();
- }
- }
- }
- Line(&helpers_) << "break;";
- }
- }
- }
- Line(&helpers_) << "}";
- }
- Line(&helpers_) << "}";
- Line(&helpers_);
- return fn;
- });
-
- if (name.empty()) {
- return false;
- }
-
- auto out = Line();
- out << name << "(";
- if (!EmitExpression(out, lhs_col_access->object)) {
- return false;
- }
- out << ", ";
- if (!EmitExpression(out, lhs_col_access->index)) {
- return false;
- }
- out << ", ";
- if (!EmitExpression(out, lhs_row_access->index)) {
- return false;
- }
- out << ", ";
- if (!EmitExpression(out, stmt->rhs)) {
- return false;
- }
- out << ");";
-
- return true;
-}
-
-bool ASTPrinter::EmitIndexAccessor(StringStream& out, const ast::IndexAccessorExpression* expr) {
- if (!EmitExpression(out, expr->object)) {
- return false;
- }
- out << "[";
-
- if (!EmitExpression(out, expr->index)) {
- return false;
- }
- out << "]";
-
- return true;
-}
-
-bool ASTPrinter::EmitBitcastCall(StringStream& out, const ast::CallExpression* call) {
- auto* arg = call->args[0];
- auto* src_type = TypeOf(arg)->UnwrapRef();
- auto* dst_type = TypeOf(call);
-
- auto* src_el_type = src_type->DeepestElement();
- auto* dst_el_type = dst_type->DeepestElement();
-
- if (!dst_el_type->IsIntegerScalar() && !dst_el_type->IsFloatScalar()) {
- diagnostics_.AddError(Source{})
- << "Unable to do bitcast to type " << dst_el_type->FriendlyName();
- return false;
- }
-
- // Handle identity bitcast.
- if (src_type == dst_type) {
- return EmitExpression(out, arg);
- }
-
- // Handle the f16 types using polyfill functions
- if (src_el_type->Is<core::type::F16>() || dst_el_type->Is<core::type::F16>()) {
- auto f16_bitcast_polyfill = [&]() {
- if (src_el_type->Is<core::type::F16>()) {
- // Source type must be vec2<f16> or vec4<f16>, since type f16 and vec3<f16> can only
- // have identity bitcast.
- auto* src_vec = src_type->As<core::type::Vector>();
- TINT_ASSERT(src_vec);
- TINT_ASSERT(((src_vec->Width() == 2u) || (src_vec->Width() == 4u)));
-
- // Bitcast f16 types to others by converting the given f16 value to f32 and call
- // f32tof16 to get the bits. This should be safe, because the convertion is precise
- // for finite and infinite f16 value as they are exactly representable by f32, and
- // WGSL spec allow any result if f16 value is NaN.
- return tint::GetOrAdd(
- bitcast_funcs_, BinaryType{{src_type, dst_type}}, [&]() -> std::string {
- TextBuffer b;
- TINT_DEFER(helpers_.Append(b));
-
- auto fn_name = UniqueIdentifier(std::string("tint_bitcast_from_f16"));
- {
- auto decl = Line(&b);
- if (!EmitTypeAndName(decl, dst_type, core::AddressSpace::kUndefined,
- core::Access::kUndefined, fn_name)) {
- return "";
- }
- {
- ScopedParen sp(decl);
- if (!EmitTypeAndName(decl, src_type, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "src")) {
- return "";
- }
- }
- decl << " {";
- }
- {
- ScopedIndent si(&b);
- {
- Line(&b) << "uint" << src_vec->Width() << " r = f32tof16(float"
- << src_vec->Width() << "(src));";
-
- {
- auto s = Line(&b);
- s << "return as";
- if (!EmitType(s, dst_el_type, core::AddressSpace::kUndefined,
- core::Access::kReadWrite, "")) {
- return "";
- }
- s << "(";
- switch (src_vec->Width()) {
- case 2: {
- s << "uint((r.x & 0xffff) | ((r.y & 0xffff) << 16))";
- break;
- }
- case 4: {
- s << "uint2((r.x & 0xffff) | ((r.y & 0xffff) << 16), "
- "(r.z & 0xffff) | ((r.w & 0xffff) << 16))";
- break;
- }
- }
- s << ");";
- }
- }
- }
- Line(&b) << "}";
- Line(&b);
- return fn_name;
- });
- } else {
- // Destination type must be vec2<f16> or vec4<f16>.
- auto* dst_vec = dst_type->As<core::type::Vector>();
- TINT_ASSERT((dst_vec && ((dst_vec->Width() == 2u) || (dst_vec->Width() == 4u)) &&
- dst_el_type->Is<core::type::F16>()));
- // Source type must be f32/i32/u32 or vec2<f32/i32/u32>.
- auto* src_vec = src_type->As<core::type::Vector>();
- TINT_ASSERT(
- (src_type->IsAnyOf<core::type::I32, core::type::U32, core::type::F32>() ||
- (src_vec && src_vec->Width() == 2u &&
- src_el_type->IsAnyOf<core::type::I32, core::type::U32, core::type::F32>())));
- std::string src_type_suffix = (src_vec ? "2" : "");
-
- // Bitcast other types to f16 types by reinterpreting their bits as f16 using
- // f16tof32, and convert the result f32 to f16. This should be safe, because the
- // convertion is precise for finite and infinite f16 result value as they are
- // exactly representable by f32, and WGSL spec allow any result if f16 result value
- // would be NaN.
- return tint::GetOrAdd(
- bitcast_funcs_, BinaryType{{src_type, dst_type}}, [&]() -> std::string {
- TextBuffer b;
- TINT_DEFER(helpers_.Append(b));
-
- auto fn_name = UniqueIdentifier(std::string("tint_bitcast_to_f16"));
- {
- auto decl = Line(&b);
- if (!EmitTypeAndName(decl, dst_type, core::AddressSpace::kUndefined,
- core::Access::kUndefined, fn_name)) {
- return "";
- }
- {
- ScopedParen sp(decl);
- if (!EmitTypeAndName(decl, src_type, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "src")) {
- return "";
- }
- }
- decl << " {";
- }
- {
- ScopedIndent si(&b);
- {
- // Convert the source to uint for f16tof32.
- Line(&b) << "uint" << src_type_suffix << " v = asuint(src);";
- // Reinterprete the low 16 bits and high 16 bits
- Line(&b) << "float" << src_type_suffix
- << " t_low = f16tof32(v & 0xffff);";
- Line(&b) << "float" << src_type_suffix
- << " t_high = f16tof32((v >> 16) & 0xffff);";
- // Construct the result f16 vector
- {
- auto s = Line(&b);
- s << "return ";
- if (!EmitType(s, dst_type, core::AddressSpace::kUndefined,
- core::Access::kReadWrite, "")) {
- return "";
- }
- s << "(";
- switch (dst_vec->Width()) {
- case 2: {
- s << "t_low.x, t_high.x";
- break;
- }
- case 4: {
- s << "t_low.x, t_high.x, t_low.y, t_high.y";
- break;
- }
- }
- s << ");";
- }
- }
- }
- Line(&b) << "}";
- Line(&b);
- return fn_name;
- });
- }
- };
-
- // Get or create the polyfill
- auto fn = f16_bitcast_polyfill();
- if (fn.empty()) {
- return false;
- }
- // Call the polyfill
- out << fn;
- {
- ScopedParen sp(out);
- if (!EmitExpression(out, arg)) {
- return false;
- }
- }
-
- return true;
- }
-
- // Otherwise, bitcasting between non-f16 types.
- TINT_ASSERT((!src_el_type->Is<core::type::F16>() && !dst_el_type->Is<core::type::F16>()));
- out << "as";
- if (!EmitType(out, dst_el_type, core::AddressSpace::kUndefined, core::Access::kReadWrite, "")) {
- return false;
- }
- out << "(";
- if (!EmitExpression(out, arg)) {
- return false;
- }
- out << ")";
- return true;
-}
-
-bool ASTPrinter::EmitAssign(const ast::AssignmentStatement* stmt) {
- if (auto* lhs_access = stmt->lhs->As<ast::IndexAccessorExpression>()) {
- auto validate_obj_not_pointer = [&](const core::type::Type* object_ty) {
- if (DAWN_UNLIKELY(object_ty->Is<core::type::Pointer>())) {
- TINT_ICE() << "lhs of index accessor should not be a pointer. These should have "
- "been removed by transforms such as SimplifyPointers, "
- "DecomposeMemoryAccess, and DirectVariableAccess";
- }
- return true;
- };
-
- // BUG(crbug.com/tint/1333): work around assignment of scalar to matrices
- // with at least one dynamic index
- if (auto* lhs_sub_access = lhs_access->object->As<ast::IndexAccessorExpression>()) {
- const auto* lhs_sub_access_type = TypeOf(lhs_sub_access->object);
- if (!validate_obj_not_pointer(lhs_sub_access_type)) {
- return false;
- }
- if (auto* mat = lhs_sub_access_type->UnwrapRef()->As<core::type::Matrix>()) {
- auto* rhs_row_idx_sem = builder_.Sem().GetVal(lhs_access->index);
- auto* rhs_col_idx_sem = builder_.Sem().GetVal(lhs_sub_access->index);
- if (!rhs_row_idx_sem->ConstantValue() || !rhs_col_idx_sem->ConstantValue()) {
- return EmitDynamicMatrixScalarAssignment(stmt, mat);
- }
- }
- }
- // BUG(crbug.com/tint/1333): work around assignment of vector to matrices
- // with dynamic indices
- const auto* lhs_access_type = TypeOf(lhs_access->object);
- if (!validate_obj_not_pointer(lhs_access_type)) {
- return false;
- }
- if (auto* mat = lhs_access_type->UnwrapRef()->As<core::type::Matrix>()) {
- auto* lhs_index_sem = builder_.Sem().GetVal(lhs_access->index);
- if (!lhs_index_sem->ConstantValue()) {
- return EmitDynamicMatrixVectorAssignment(stmt, mat);
- }
- }
- // BUG(crbug.com/tint/534): work around assignment to vectors with dynamic
- // indices
- if (auto* vec = lhs_access_type->UnwrapRef()->As<core::type::Vector>()) {
- auto* rhs_sem = builder_.Sem().GetVal(lhs_access->index);
- if (!rhs_sem->ConstantValue()) {
- return EmitDynamicVectorAssignment(stmt, vec);
- }
- }
- }
-
- auto out = Line();
- if (!EmitExpression(out, stmt->lhs)) {
- return false;
- }
- out << " = ";
- if (!EmitExpression(out, stmt->rhs)) {
- return false;
- }
- out << ";";
- return true;
-}
-
-bool ASTPrinter::EmitBinary(StringStream& out, const ast::BinaryExpression* expr) {
- if (expr->op == core::BinaryOp::kLogicalAnd || expr->op == core::BinaryOp::kLogicalOr) {
- auto name = UniqueIdentifier(kTempNamePrefix);
-
- {
- auto pre = Line();
- pre << "bool " << name << " = ";
- if (!EmitExpression(pre, expr->lhs)) {
- return false;
- }
- pre << ";";
- }
-
- if (expr->op == core::BinaryOp::kLogicalOr) {
- Line() << "if (!" << name << ") {";
- } else {
- Line() << "if (" << name << ") {";
- }
-
- {
- ScopedIndent si(this);
- auto pre = Line();
- pre << name << " = ";
- if (!EmitExpression(pre, expr->rhs)) {
- return false;
- }
- pre << ";";
- }
-
- Line() << "}";
-
- out << "(" << name << ")";
- return true;
- }
-
- auto* lhs_type = TypeOf(expr->lhs)->UnwrapRef();
- auto* rhs_type = TypeOf(expr->rhs)->UnwrapRef();
- // Multiplying by a matrix requires the use of `mul` in order to get the
- // type of multiply we desire.
- if (expr->op == core::BinaryOp::kMultiply &&
- ((lhs_type->Is<core::type::Vector>() && rhs_type->Is<core::type::Matrix>()) ||
- (lhs_type->Is<core::type::Matrix>() && rhs_type->Is<core::type::Vector>()) ||
- (lhs_type->Is<core::type::Matrix>() && rhs_type->Is<core::type::Matrix>()))) {
- // Matrices are transposed, so swap LHS and RHS.
- out << "mul(";
- if (!EmitExpression(out, expr->rhs)) {
- return false;
- }
- out << ", ";
- if (!EmitExpression(out, expr->lhs)) {
- return false;
- }
- out << ")";
-
- return true;
- }
-
- ScopedParen sp(out);
-
- if (!EmitExpression(out, expr->lhs)) {
- return false;
- }
- out << " ";
-
- switch (expr->op) {
- case core::BinaryOp::kAnd:
- out << "&";
- break;
- case core::BinaryOp::kOr:
- out << "|";
- break;
- case core::BinaryOp::kXor:
- out << "^";
- break;
- case core::BinaryOp::kLogicalAnd:
- case core::BinaryOp::kLogicalOr: {
- // These are both handled above.
- TINT_UNREACHABLE();
- }
- case core::BinaryOp::kEqual:
- out << "==";
- break;
- case core::BinaryOp::kNotEqual:
- out << "!=";
- break;
- case core::BinaryOp::kLessThan:
- out << "<";
- break;
- case core::BinaryOp::kGreaterThan:
- out << ">";
- break;
- case core::BinaryOp::kLessThanEqual:
- out << "<=";
- break;
- case core::BinaryOp::kGreaterThanEqual:
- out << ">=";
- break;
- case core::BinaryOp::kShiftLeft:
- out << "<<";
- break;
- case core::BinaryOp::kShiftRight:
- // TODO(dsinclair): MSL is based on C++14, and >> in C++14 has
- // implementation-defined behaviour for negative LHS. We may have to
- // generate extra code to implement WGSL-specified behaviour for negative
- // LHS.
- out << R"(>>)";
- break;
-
- case core::BinaryOp::kAdd:
- out << "+";
- break;
- case core::BinaryOp::kSubtract:
- out << "-";
- break;
- case core::BinaryOp::kMultiply:
- out << "*";
- break;
- case core::BinaryOp::kDivide:
- out << "/";
- break;
- case core::BinaryOp::kModulo:
- out << "%";
- break;
- }
- out << " ";
-
- if (!EmitExpression(out, expr->rhs)) {
- return false;
- }
-
- return true;
-}
-
-bool ASTPrinter::EmitStatements(VectorRef<const ast::Statement*> stmts) {
- for (auto* s : stmts) {
- if (!EmitStatement(s)) {
- return false;
- }
- }
- return true;
-}
-
-bool ASTPrinter::EmitStatementsWithIndent(VectorRef<const ast::Statement*> stmts) {
- ScopedIndent si(this);
- return EmitStatements(stmts);
-}
-
-bool ASTPrinter::EmitBlock(const ast::BlockStatement* stmt) {
- Line() << "{";
- if (!EmitStatementsWithIndent(stmt->statements)) {
- return false;
- }
- Line() << "}";
- return true;
-}
-
-bool ASTPrinter::EmitBreak(const ast::BreakStatement*) {
- Line() << "break;";
- return true;
-}
-
-bool ASTPrinter::EmitBreakIf(const ast::BreakIfStatement* b) {
- auto out = Line();
- out << "if (";
- if (!EmitExpression(out, b->condition)) {
- return false;
- }
- out << ") { break; }";
- return true;
-}
-
-bool ASTPrinter::EmitCall(StringStream& out, const ast::CallExpression* expr) {
- auto* call = builder_.Sem().Get<sem::Call>(expr);
- auto* target = call->Target();
- return Switch(
- target, //
- [&](const sem::Function* func) { return EmitFunctionCall(out, call, func); },
- [&](const sem::BuiltinFn* builtin) { return EmitBuiltinCall(out, call, builtin); },
- [&](const sem::ValueConversion* conv) { return EmitValueConversion(out, call, conv); },
- [&](const sem::ValueConstructor* ctor) { return EmitValueConstructor(out, call, ctor); },
- TINT_ICE_ON_NO_MATCH);
-}
-
-bool ASTPrinter::EmitFunctionCall(StringStream& out,
- const sem::Call* call,
- const sem::Function* func) {
- auto* expr = call->Declaration();
-
- if (ast::HasAttribute<CalculateArrayLength::BufferSizeIntrinsic>(
- func->Declaration()->attributes)) {
- // Special function generated by the CalculateArrayLength transform for
- // calling X.GetDimensions(Y)
- if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
- return false;
- }
- out << ".GetDimensions(";
- if (!EmitExpression(out, call->Arguments()[1]->Declaration())) {
- return false;
- }
- out << ")";
- return true;
- }
-
- if (auto* intrinsic =
- ast::GetAttribute<DecomposeMemoryAccess::Intrinsic>(func->Declaration()->attributes)) {
- switch (intrinsic->address_space) {
- case core::AddressSpace::kUniform:
- return EmitUniformBufferAccess(out, expr, intrinsic);
- case core::AddressSpace::kStorage:
- if (!intrinsic->IsAtomic()) {
- return EmitStorageBufferAccess(out, expr, intrinsic);
- }
- break;
- default:
- TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic address space:"
- << intrinsic->address_space;
- }
- }
-
- if (auto* wave_intrinsic =
- ast::GetAttribute<ast::transform::CanonicalizeEntryPointIO::HLSLWaveIntrinsic>(
- func->Declaration()->attributes)) {
- switch (wave_intrinsic->op) {
- case ast::transform::CanonicalizeEntryPointIO::HLSLWaveIntrinsic::Op::kWaveGetLaneCount:
- out << "WaveGetLaneCount()";
- return true;
- case ast::transform::CanonicalizeEntryPointIO::HLSLWaveIntrinsic::Op::kWaveGetLaneIndex:
- out << "WaveGetLaneIndex()";
- return true;
- }
- }
-
- out << func->Declaration()->name->symbol.Name() << "(";
-
- bool first = true;
- for (auto* arg : call->Arguments()) {
- if (!first) {
- out << ", ";
- }
- first = false;
-
- if (!EmitExpression(out, arg->Declaration())) {
- return false;
- }
- }
-
- out << ")";
- return true;
-}
-
-bool ASTPrinter::EmitBuiltinCall(StringStream& out,
- const sem::Call* call,
- const sem::BuiltinFn* builtin) {
- const auto type = builtin->Fn();
-
- auto* expr = call->Declaration();
- if (builtin->IsTexture()) {
- return EmitTextureCall(out, call, builtin);
- }
- if (type == wgsl::BuiltinFn::kBitcast) {
- return EmitBitcastCall(out, expr);
- }
- if (type == wgsl::BuiltinFn::kSelect) {
- return EmitSelectCall(out, expr);
- }
- if (type == wgsl::BuiltinFn::kModf) {
- return EmitModfCall(out, expr, builtin);
- }
- if (type == wgsl::BuiltinFn::kFrexp) {
- return EmitFrexpCall(out, expr, builtin);
- }
- if (type == wgsl::BuiltinFn::kDegrees) {
- return EmitDegreesCall(out, expr, builtin);
- }
- if (type == wgsl::BuiltinFn::kRadians) {
- return EmitRadiansCall(out, expr, builtin);
- }
- if (type == wgsl::BuiltinFn::kSign) {
- return EmitSignCall(out, call, builtin);
- }
- if (type == wgsl::BuiltinFn::kQuantizeToF16) {
- return EmitQuantizeToF16Call(out, expr, builtin);
- }
- if (type == wgsl::BuiltinFn::kTrunc) {
- return EmitTruncCall(out, expr, builtin);
- }
- if (builtin->IsDataPacking()) {
- return EmitDataPackingCall(out, expr, builtin);
- }
- if (builtin->IsDataUnpacking()) {
- return EmitDataUnpackingCall(out, expr, builtin);
- }
- if (builtin->IsBarrier()) {
- return EmitBarrierCall(out, builtin);
- }
- if (builtin->IsAtomic()) {
- return EmitWorkgroupAtomicCall(out, expr, builtin);
- }
- if (builtin->IsPacked4x8IntegerDotProductBuiltin()) {
- return EmitPacked4x8IntegerDotProductBuiltinCall(out, expr, builtin);
- }
- if (type == wgsl::BuiltinFn::kSubgroupShuffleXor ||
- type == wgsl::BuiltinFn::kSubgroupShuffleUp ||
- type == wgsl::BuiltinFn::kSubgroupShuffleDown) {
- return EmitSubgroupShuffleBuiltinCall(out, expr, builtin);
- }
-
- if (type == wgsl::BuiltinFn::kSubgroupInclusiveAdd ||
- type == wgsl::BuiltinFn::kSubgroupInclusiveMul) {
- return EmitSubgroupInclusiveBuiltinCall(out, expr, builtin);
- }
- auto name = generate_builtin_name(builtin);
- if (name.empty()) {
- return false;
- }
-
- // Handle single argument builtins that only accept and return uint (not int overload).
- // For count bits and reverse bits, we need to explicitly cast the return value (we also cast
- // the arg for good measure). See crbug.com/tint/1550.
- // For the following subgroup builtins, the lack of support may be a bug in DXC. See
- // github.com/microsoft/DirectXShaderCompiler/issues/6850.
- if (type == wgsl::BuiltinFn::kCountOneBits || type == wgsl::BuiltinFn::kReverseBits ||
- type == wgsl::BuiltinFn::kSubgroupAnd || type == wgsl::BuiltinFn::kSubgroupOr ||
- type == wgsl::BuiltinFn::kSubgroupXor) {
- auto* arg = call->Arguments()[0];
- auto* argType = arg->Type()->UnwrapRef();
- if (argType->IsSignedIntegerScalarOrVector()) {
- // Bitcast of literal int vectors fails in DXC so extract arg to a var. See
- // github.com/microsoft/DirectXShaderCompiler/issues/6851.
- if (argType->IsSignedIntegerVector() &&
- arg->Stage() == core::EvaluationStage::kConstant) {
- auto varName = UniqueIdentifier(kTempNamePrefix);
- auto pre = Line();
- if (!EmitTypeAndName(pre, argType, core::AddressSpace::kUndefined,
- core::Access::kUndefined, varName)) {
- return false;
- }
- pre << " = ";
- if (!EmitExpression(pre, arg->Declaration())) {
- return false;
- }
- pre << ";";
- out << "asint(" << name << "(asuint(" << varName << ")))";
- return true;
- }
-
- out << "asint(" << name << "(asuint(";
- if (!EmitExpression(out, arg->Declaration())) {
- return false;
- }
- out << ")))";
- return true;
- }
- }
-
- out << name << "(";
-
- bool first = true;
- for (auto* arg : call->Arguments()) {
- if (!first) {
- out << ", ";
- }
- first = false;
-
- if (!EmitExpression(out, arg->Declaration())) {
- return false;
- }
- }
-
- out << ")";
-
- return true;
-}
-
-bool ASTPrinter::EmitValueConversion(StringStream& out,
- const sem::Call* call,
- const sem::ValueConversion* conv) {
- if (!EmitType(out, conv->Target(), core::AddressSpace::kUndefined, core::Access::kReadWrite,
- "")) {
- return false;
- }
- out << "(";
-
- if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
- return false;
- }
-
- out << ")";
- return true;
-}
-
-bool ASTPrinter::EmitValueConstructor(StringStream& out,
- const sem::Call* call,
- const sem::ValueConstructor* ctor) {
- auto* type = call->Type();
-
- // If the value constructor arguments are empty then we need to construct with the zero value
- // for all components.
- if (call->Arguments().IsEmpty()) {
- return EmitZeroValue(out, type);
- }
-
- // Single parameter matrix initializers must be identity initializer.
- // It could also be conversions between f16 and f32 matrix when f16 is properly supported.
- if (type->Is<core::type::Matrix>() && call->Arguments().Length() == 1) {
- if (!ctor->Parameters()[0]->Type()->UnwrapRef()->IsFloatMatrix()) {
- TINT_UNREACHABLE()
- << "found a single-parameter matrix initializer that is not identity initializer";
- }
- }
-
- bool brackets = type->IsAnyOf<core::type::Array, core::type::Struct>();
-
- // For single-value vector initializers, swizzle the scalar to the right
- // vector dimension using .x
- const bool is_single_value_vector_init =
- type->Is<core::type::Vector>() && call->Arguments().Length() == 1 &&
- ctor->Parameters()[0]->Type()->Is<core::type::Scalar>();
-
- if (brackets) {
- out << "{";
- } else {
- if (!EmitType(out, type, core::AddressSpace::kUndefined, core::Access::kReadWrite, "")) {
- return false;
- }
- out << "(";
- }
-
- if (is_single_value_vector_init) {
- out << "(";
- }
-
- bool first = true;
- for (auto* e : call->Arguments()) {
- if (!first) {
- out << ", ";
- }
- first = false;
-
- if (!EmitExpression(out, e->Declaration())) {
- return false;
- }
- }
-
- if (is_single_value_vector_init) {
- out << ")." << std::string(type->As<core::type::Vector>()->Width(), 'x');
- }
-
- out << (brackets ? "}" : ")");
- return true;
-}
-
-bool ASTPrinter::EmitUniformBufferAccess(StringStream& out,
- const ast::CallExpression* expr,
- const DecomposeMemoryAccess::Intrinsic* intrinsic) {
- auto const buffer = intrinsic->Buffer()->identifier->symbol.Name();
- auto* const offset = expr->args[0];
-
- // offset in bytes
- uint32_t scalar_offset_bytes = 0;
- // offset in uint (4 bytes)
- uint32_t scalar_offset_index = 0;
- // expression to calculate offset in bytes
- std::string scalar_offset_bytes_expr;
- // expression to calculate offset in uint, by dividing scalar_offset_bytes_expr by 4
- std::string scalar_offset_index_expr;
- // expression to calculate offset in uint, independently
- std::string scalar_offset_index_unified_expr;
-
- // If true, use scalar_offset_index, otherwise use scalar_offset_index_expr
- bool scalar_offset_constant = false;
-
- if (auto* val = builder_.Sem().GetVal(offset)->ConstantValue()) {
- TINT_ASSERT(val->Type()->Is<core::type::U32>());
- scalar_offset_bytes = static_cast<uint32_t>(val->ValueAs<AInt>());
- scalar_offset_index = scalar_offset_bytes / 4; // bytes -> scalar index
- scalar_offset_constant = true;
- }
-
- // If true, scalar_offset_bytes or scalar_offset_bytes_expr should be used, otherwise only use
- // scalar_offset_index or scalar_offset_index_unified_expr. Currently only loading f16 scalar
- // require using offset in bytes.
- const bool need_offset_in_bytes =
- intrinsic->type == DecomposeMemoryAccess::Intrinsic::DataType::kF16;
-
- if (!scalar_offset_constant) {
- // UBO offset not compile-time known.
- // Calculate the scalar offset into a temporary.
- if (need_offset_in_bytes) {
- scalar_offset_bytes_expr = UniqueIdentifier("scalar_offset_bytes");
- scalar_offset_index_expr = UniqueIdentifier("scalar_offset_index");
- {
- auto pre = Line();
- pre << "const uint " << scalar_offset_bytes_expr << " = (";
- if (!EmitExpression(pre, offset)) {
- return false;
- }
- pre << ");";
- }
- Line() << "const uint " << scalar_offset_index_expr << " = " << scalar_offset_bytes_expr
- << " / 4;";
- } else {
- scalar_offset_index_unified_expr = UniqueIdentifier("scalar_offset");
- auto pre = Line();
- pre << "const uint " << scalar_offset_index_unified_expr << " = (";
- if (!EmitExpression(pre, offset)) {
- return false;
- }
- pre << ") / 4;";
- }
- }
-
- using Op = DecomposeMemoryAccess::Intrinsic::Op;
- using DataType = DecomposeMemoryAccess::Intrinsic::DataType;
- switch (intrinsic->op) {
- case Op::kLoad: {
- auto cast = [&](const char* to, auto&& load) {
- out << to << "(";
- auto result = load();
- out << ")";
- return result;
- };
- auto load_u32_to = [&](StringStream& target) {
- target << buffer;
- if (scalar_offset_constant) {
- target << "[" << (scalar_offset_index / 4) << "]."
- << kSwizzle[scalar_offset_index & 3];
- } else {
- target << "[" << scalar_offset_index_unified_expr << " / 4]["
- << scalar_offset_index_unified_expr << " % 4]";
- }
- return true;
- };
- auto load_u32 = [&] { return load_u32_to(out); };
- // Has a minimum alignment of 8 bytes, so is either .xy or .zw
- auto load_vec2_u32_to = [&](StringStream& target) {
- if (scalar_offset_constant) {
- target << buffer << "[" << (scalar_offset_index / 4) << "]"
- << ((scalar_offset_index & 2) == 0 ? ".xy" : ".zw");
- } else {
- std::string ubo_load = UniqueIdentifier("ubo_load");
- {
- auto pre = Line();
- pre << "uint4 " << ubo_load << " = " << buffer << "["
- << scalar_offset_index_unified_expr << " / 4];";
- }
- target << "((" << scalar_offset_index_unified_expr << " & 2) ? " << ubo_load
- << ".zw : " << ubo_load << ".xy)";
- }
- return true;
- };
- auto load_vec2_u32 = [&] { return load_vec2_u32_to(out); };
- // vec4 has a minimum alignment of 16 bytes, easiest case
- auto load_vec4_u32 = [&] {
- out << buffer;
- if (scalar_offset_constant) {
- out << "[" << (scalar_offset_index / 4) << "]";
- } else {
- out << "[" << scalar_offset_index_unified_expr << " / 4]";
- }
- return true;
- };
- // vec3 has a minimum alignment of 16 bytes, so is just a .xyz swizzle
- auto load_vec3_u32 = [&] {
- if (!load_vec4_u32()) {
- return false;
- }
- out << ".xyz";
- return true;
- };
- auto load_scalar_f16 = [&] {
- // offset bytes = 4k, ((buffer[index].x) & 0xFFFF)
- // offset bytes = 4k+2, ((buffer[index].x >> 16) & 0xFFFF)
- out << "float16_t(f16tof32(((" << buffer;
- if (scalar_offset_constant) {
- out << "[" << (scalar_offset_index / 4) << "]."
- << kSwizzle[scalar_offset_index & 3];
- // WGSL spec ensure little endian memory layout.
- if (scalar_offset_bytes % 4 == 0) {
- out << ") & 0xFFFF)";
- } else {
- out << " >> 16) & 0xFFFF)";
- }
- } else {
- out << "[" << scalar_offset_index_expr << " / 4][" << scalar_offset_index_expr
- << " % 4] >> (" << scalar_offset_bytes_expr
- << " % 4 == 0 ? 0 : 16)) & 0xFFFF)";
- }
- out << "))";
- return true;
- };
- auto load_vec2_f16 = [&] {
- // vec2<f16> is aligned to 4 bytes
- // Preclude code load the vec2<f16> data as a uint:
- // uint ubo_load = buffer[id0][id1];
- // Loading code convert it to vec2<f16>:
- // vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)),
- // float16_t(f16tof32(ubo_load >> 16)))
- std::string ubo_load = UniqueIdentifier("ubo_load");
- {
- auto pre = Line();
- // Load the 4 bytes f16 vector as an uint
- pre << "uint " << ubo_load << " = ";
- if (!load_u32_to(pre)) {
- return false;
- }
- pre << ";";
- }
- out << "vector<float16_t, 2>(float16_t(f16tof32(" << ubo_load
- << " & 0xFFFF)), float16_t(f16tof32(" << ubo_load << " >> 16)))";
- return true;
- };
- auto load_vec3_f16 = [&] {
- // vec3<f16> is aligned to 8 bytes
- // Preclude code load the vec3<f16> data as uint2 and convert its elements to
- // float16_t:
- // uint2 ubo_load = buffer[id0].xy;
- // /* The low 8 bits of two uint are the x and z elements of vec3<f16> */
- // vector<float16_t> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load &
- // 0xFFFF));
- // /* The high 8 bits of first uint is the y element of vec3<f16> */
- // float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
- // Loading code convert it to vec3<f16>:
- // vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1])
- std::string ubo_load = UniqueIdentifier("ubo_load");
- std::string ubo_load_xz = UniqueIdentifier(ubo_load + "_xz");
- std::string ubo_load_y = UniqueIdentifier(ubo_load + "_y");
- {
- auto pre = Line();
- // Load the 8 bytes uint2 with the f16 vector at lower 6 bytes
- pre << "uint2 " << ubo_load << " = ";
- if (!load_vec2_u32_to(pre)) {
- return false;
- }
- pre << ";";
- }
- {
- auto pre = Line();
- pre << "vector<float16_t, 2> " << ubo_load_xz
- << " = vector<float16_t, 2>(f16tof32(" << ubo_load << " & 0xFFFF));";
- }
- {
- auto pre = Line();
- pre << "float16_t " << ubo_load_y << " = f16tof32(" << ubo_load
- << "[0] >> 16);";
- }
- out << "vector<float16_t, 3>(" << ubo_load_xz << "[0], " << ubo_load_y << ", "
- << ubo_load_xz << "[1])";
- return true;
- };
- auto load_vec4_f16 = [&] {
- // vec4<f16> is aligned to 8 bytes
- // Preclude code load the vec4<f16> data as uint2 and convert its elements to
- // float16_t:
- // uint2 ubo_load = buffer[id0].xy;
- // /* The low 8 bits of two uint are the x and z elements of vec4<f16> */
- // vector<float16_t> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load &
- // 0xFFFF));
- // /* The high 8 bits of two uint are the y and w elements of vec4<f16> */
- // vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >>
- // 16));
- // Loading code convert it to vec4<f16>:
- // vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1],
- // ubo_load_yw[1])
- std::string ubo_load = UniqueIdentifier("ubo_load");
- std::string ubo_load_xz = UniqueIdentifier(ubo_load + "_xz");
- std::string ubo_load_yw = UniqueIdentifier(ubo_load + "_yw");
- {
- auto pre = Line();
- // Load the 8 bytes f16 vector as an uint2
- pre << "uint2 " << ubo_load << " = ";
- if (!load_vec2_u32_to(pre)) {
- return false;
- }
- pre << ";";
- }
- {
- auto pre = Line();
- pre << "vector<float16_t, 2> " << ubo_load_xz
- << " = vector<float16_t, 2>(f16tof32(" << ubo_load << " & 0xFFFF));";
- }
- {
- auto pre = Line();
- pre << "vector<float16_t, 2> " << ubo_load_yw
- << " = vector<float16_t, 2>(f16tof32(" << ubo_load << " >> 16));";
- }
- out << "vector<float16_t, 4>(" << ubo_load_xz << "[0], " << ubo_load_yw << "[0], "
- << ubo_load_xz << "[1], " << ubo_load_yw << "[1])";
- return true;
- };
- switch (intrinsic->type) {
- case DataType::kU32:
- return load_u32();
- case DataType::kF32:
- return cast("asfloat", load_u32);
- case DataType::kI32:
- return cast("asint", load_u32);
- case DataType::kF16:
- return load_scalar_f16();
- case DataType::kVec2U32:
- return load_vec2_u32();
- case DataType::kVec2F32:
- return cast("asfloat", load_vec2_u32);
- case DataType::kVec2I32:
- return cast("asint", load_vec2_u32);
- case DataType::kVec2F16:
- return load_vec2_f16();
- case DataType::kVec3U32:
- return load_vec3_u32();
- case DataType::kVec3F32:
- return cast("asfloat", load_vec3_u32);
- case DataType::kVec3I32:
- return cast("asint", load_vec3_u32);
- case DataType::kVec3F16:
- return load_vec3_f16();
- case DataType::kVec4U32:
- return load_vec4_u32();
- case DataType::kVec4F32:
- return cast("asfloat", load_vec4_u32);
- case DataType::kVec4I32:
- return cast("asint", load_vec4_u32);
- case DataType::kVec4F16:
- return load_vec4_f16();
- }
- TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
- << static_cast<int>(intrinsic->type);
- }
- default:
- break;
- }
- TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::Op: "
- << static_cast<int>(intrinsic->op);
-}
-
-bool ASTPrinter::EmitStorageBufferAccess(StringStream& out,
- const ast::CallExpression* expr,
- const DecomposeMemoryAccess::Intrinsic* intrinsic) {
- auto const buffer = intrinsic->Buffer()->identifier->symbol.Name();
- auto* const offset = expr->args[0];
- auto* const value = expr->args.Length() > 1 ? expr->args[1] : nullptr;
-
- using Op = DecomposeMemoryAccess::Intrinsic::Op;
- using DataType = DecomposeMemoryAccess::Intrinsic::DataType;
- switch (intrinsic->op) {
- case Op::kLoad: {
- auto load = [&](const char* cast, int n) {
- if (cast) {
- out << cast << "(";
- }
- out << buffer << ".Load";
- if (n > 1) {
- out << n;
- }
- ScopedParen sp(out);
- if (!EmitExpression(out, offset)) {
- return false;
- }
- if (cast) {
- out << ")";
- }
- return true;
- };
- // Templated load used for f16 types, requires SM6.2 or higher and DXC
- // Used by loading f16 types, e.g. for f16 type, set type parameter to "float16_t"
- // to emit `buffer.Load<float16_t>(offset)`.
- auto templated_load = [&](const char* type) {
- out << buffer << ".Load<" << type << ">"; // templated load
- ScopedParen sp(out);
- if (!EmitExpression(out, offset)) {
- return false;
- }
- return true;
- };
- switch (intrinsic->type) {
- case DataType::kU32:
- return load(nullptr, 1);
- case DataType::kF32:
- return load("asfloat", 1);
- case DataType::kI32:
- return load("asint", 1);
- case DataType::kF16:
- return templated_load("float16_t");
- case DataType::kVec2U32:
- return load(nullptr, 2);
- case DataType::kVec2F32:
- return load("asfloat", 2);
- case DataType::kVec2I32:
- return load("asint", 2);
- case DataType::kVec2F16:
- return templated_load("vector<float16_t, 2> ");
- case DataType::kVec3U32:
- return load(nullptr, 3);
- case DataType::kVec3F32:
- return load("asfloat", 3);
- case DataType::kVec3I32:
- return load("asint", 3);
- case DataType::kVec3F16:
- return templated_load("vector<float16_t, 3> ");
- case DataType::kVec4U32:
- return load(nullptr, 4);
- case DataType::kVec4F32:
- return load("asfloat", 4);
- case DataType::kVec4I32:
- return load("asint", 4);
- case DataType::kVec4F16:
- return templated_load("vector<float16_t, 4> ");
- }
- TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
- << static_cast<int>(intrinsic->type);
- }
-
- case Op::kStore: {
- auto store = [&](int n) {
- out << buffer << ".Store";
- if (n > 1) {
- out << n;
- }
- ScopedParen sp1(out);
- if (!EmitExpression(out, offset)) {
- return false;
- }
- out << ", asuint";
- ScopedParen sp2(out);
- if (!EmitTextureOrStorageBufferCallArgExpression(out, value)) {
- return false;
- }
- return true;
- };
- // Templated stored used for f16 types, requires SM6.2 or higher and DXC
- // Used by storing f16 types, e.g. for f16 type, set type parameter to "float16_t"
- // to emit `buffer.Store<float16_t>(offset)`.
- auto templated_store = [&](const char* type) {
- out << buffer << ".Store<" << type << ">"; // templated store
- ScopedParen sp1(out);
- if (!EmitExpression(out, offset)) {
- return false;
- }
- out << ", ";
- if (!EmitExpression(out, value)) {
- return false;
- }
- return true;
- };
- switch (intrinsic->type) {
- case DataType::kU32:
- return store(1);
- case DataType::kF32:
- return store(1);
- case DataType::kI32:
- return store(1);
- case DataType::kF16:
- return templated_store("float16_t");
- case DataType::kVec2U32:
- return store(2);
- case DataType::kVec2F32:
- return store(2);
- case DataType::kVec2I32:
- return store(2);
- case DataType::kVec2F16:
- return templated_store("vector<float16_t, 2> ");
- case DataType::kVec3U32:
- return store(3);
- case DataType::kVec3F32:
- return store(3);
- case DataType::kVec3I32:
- return store(3);
- case DataType::kVec3F16:
- return templated_store("vector<float16_t, 3> ");
- case DataType::kVec4U32:
- return store(4);
- case DataType::kVec4F32:
- return store(4);
- case DataType::kVec4I32:
- return store(4);
- case DataType::kVec4F16:
- return templated_store("vector<float16_t, 4> ");
- }
- TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
- << static_cast<int>(intrinsic->type);
- }
- default:
- // Break out to error case below
- // Note that atomic intrinsics are generated as functions.
- break;
- }
-
- TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::Op: "
- << static_cast<int>(intrinsic->op);
-}
-
-bool ASTPrinter::EmitStorageAtomicIntrinsic(const ast::Function* func,
- const DecomposeMemoryAccess::Intrinsic* intrinsic) {
- using Op = DecomposeMemoryAccess::Intrinsic::Op;
-
- const sem::Function* sem_func = builder_.Sem().Get(func);
- auto* result_ty = sem_func->ReturnType();
- const auto name = func->name->symbol.Name();
- auto& buf = *current_buffer_;
-
- auto const buffer = intrinsic->Buffer()->identifier->symbol.Name();
-
- auto rmw = [&](const char* hlsl) -> bool {
- {
- auto fn = Line(&buf);
- if (!EmitTypeAndName(fn, result_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, name)) {
- return false;
- }
- fn << "(uint offset, ";
- if (!EmitTypeAndName(fn, result_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "value")) {
- return false;
- }
- fn << ") {";
- }
-
- buf.IncrementIndent();
- TINT_DEFER({
- buf.DecrementIndent();
- Line(&buf) << "}";
- Line(&buf);
- });
-
- {
- auto l = Line(&buf);
- if (!EmitTypeAndName(l, result_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "original_value")) {
- return false;
- }
- l << " = 0;";
- }
- {
- auto l = Line(&buf);
- l << buffer << "." << hlsl << "(offset, ";
- if (intrinsic->op == Op::kAtomicSub) {
- l << "-";
- }
- l << "value, original_value);";
- }
- Line(&buf) << "return original_value;";
- return true;
- };
-
- switch (intrinsic->op) {
- case Op::kAtomicAdd:
- return rmw("InterlockedAdd");
-
- case Op::kAtomicSub:
- // Use add with the operand negated.
- return rmw("InterlockedAdd");
-
- case Op::kAtomicMax:
- return rmw("InterlockedMax");
-
- case Op::kAtomicMin:
- return rmw("InterlockedMin");
-
- case Op::kAtomicAnd:
- return rmw("InterlockedAnd");
-
- case Op::kAtomicOr:
- return rmw("InterlockedOr");
-
- case Op::kAtomicXor:
- return rmw("InterlockedXor");
-
- case Op::kAtomicExchange:
- return rmw("InterlockedExchange");
-
- case Op::kAtomicLoad: {
- // HLSL does not have an InterlockedLoad, so we emulate it with
- // InterlockedOr using 0 as the OR value
- {
- auto fn = Line(&buf);
- if (!EmitTypeAndName(fn, result_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, name)) {
- return false;
- }
- fn << "(uint offset) {";
- }
-
- buf.IncrementIndent();
- TINT_DEFER({
- buf.DecrementIndent();
- Line(&buf) << "}";
- Line(&buf);
- });
-
- {
- auto l = Line(&buf);
- if (!EmitTypeAndName(l, result_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "value")) {
- return false;
- }
- l << " = 0;";
- }
-
- Line(&buf) << buffer << ".InterlockedOr(offset, 0, value);";
- Line(&buf) << "return value;";
- return true;
- }
- case Op::kAtomicStore: {
- auto* const value_ty = sem_func->Parameters()[1]->Type()->UnwrapRef();
- // HLSL does not have an InterlockedStore, so we emulate it with
- // InterlockedExchange and discard the returned value
- {
- auto fn = Line(&buf);
- fn << "void " << name << "(uint offset, ";
- if (!EmitTypeAndName(fn, value_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "value")) {
- return false;
- }
- fn << ") {";
- }
-
- buf.IncrementIndent();
- TINT_DEFER({
- buf.DecrementIndent();
- Line(&buf) << "}";
- Line(&buf);
- });
-
- {
- auto l = Line(&buf);
- if (!EmitTypeAndName(l, value_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "ignored")) {
- return false;
- }
- l << ";";
- }
- Line(&buf) << buffer << ".InterlockedExchange(offset, value, ignored);";
- return true;
- }
- case Op::kAtomicCompareExchangeWeak: {
- if (!EmitStructType(&helpers_, result_ty->As<core::type::Struct>())) {
- return false;
- }
-
- auto* const value_ty = sem_func->Parameters()[1]->Type()->UnwrapRef();
- // NOTE: We don't need to emit the return type struct here as DecomposeMemoryAccess
- // already added it to the AST, and it should have already been emitted by now.
- {
- auto fn = Line(&buf);
- if (!EmitTypeAndName(fn, result_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, name)) {
- return false;
- }
- fn << "(uint offset, ";
- if (!EmitTypeAndName(fn, value_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "compare")) {
- return false;
- }
- fn << ", ";
- if (!EmitTypeAndName(fn, value_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "value")) {
- return false;
- }
- fn << ") {";
- }
-
- buf.IncrementIndent();
- TINT_DEFER({
- buf.DecrementIndent();
- Line(&buf) << "}";
- Line(&buf);
- });
-
- { // T result = {0};
- auto l = Line(&buf);
- if (!EmitTypeAndName(l, result_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "result")) {
- return false;
- }
- l << "=";
- if (!EmitZeroValue(l, result_ty)) {
- return false;
- }
- l << ";";
- }
-
- Line(&buf) << buffer
- << ".InterlockedCompareExchange(offset, compare, value, result.old_value);";
- Line(&buf) << "result.exchanged = result.old_value == compare;";
- Line(&buf) << "return result;";
-
- return true;
- }
- default:
- break;
- }
-
- TINT_UNREACHABLE() << "unsupported atomic DecomposeMemoryAccess::Intrinsic::Op: "
- << static_cast<int>(intrinsic->op);
-}
-
-bool ASTPrinter::EmitWorkgroupAtomicCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- std::string result = UniqueIdentifier("atomic_result");
-
- if (!builtin->ReturnType()->Is<core::type::Void>()) {
- auto pre = Line();
- if (!EmitTypeAndName(pre, builtin->ReturnType(), core::AddressSpace::kUndefined,
- core::Access::kUndefined, result)) {
- return false;
- }
- pre << " = ";
- if (!EmitZeroValue(pre, builtin->ReturnType())) {
- return false;
- }
- pre << ";";
- }
-
- auto call = [&](const char* name) {
- auto pre = Line();
- pre << name;
-
- {
- ScopedParen sp(pre);
- for (size_t i = 0; i < expr->args.Length(); i++) {
- auto* arg = expr->args[i];
- if (i > 0) {
- pre << ", ";
- }
- if (!EmitExpression(pre, arg)) {
- return false;
- }
- }
-
- pre << ", " << result;
- }
-
- pre << ";";
-
- out << result;
- return true;
- };
-
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kAtomicLoad: {
- // HLSL does not have an InterlockedLoad, so we emulate it with
- // InterlockedOr using 0 as the OR value
- auto pre = Line();
- pre << "InterlockedOr";
- {
- ScopedParen sp(pre);
- if (!EmitExpression(pre, expr->args[0])) {
- return false;
- }
- pre << ", 0, " << result;
- }
- pre << ";";
-
- out << result;
- return true;
- }
- case wgsl::BuiltinFn::kAtomicStore: {
- // HLSL does not have an InterlockedStore, so we emulate it with
- // InterlockedExchange and discard the returned value
- { // T result = 0;
- auto pre = Line();
- auto* value_ty = builtin->Parameters()[1]->Type()->UnwrapRef();
- if (!EmitTypeAndName(pre, value_ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, result)) {
- return false;
- }
- pre << " = ";
- if (!EmitZeroValue(pre, value_ty)) {
- return false;
- }
- pre << ";";
- }
-
- out << "InterlockedExchange";
- {
- ScopedParen sp(out);
- if (!EmitExpression(out, expr->args[0])) {
- return false;
- }
- out << ", ";
- if (!EmitExpression(out, expr->args[1])) {
- return false;
- }
- out << ", " << result;
- }
- return true;
- }
- case wgsl::BuiltinFn::kAtomicCompareExchangeWeak: {
- if (!EmitStructType(&helpers_, builtin->ReturnType()->As<core::type::Struct>())) {
- return false;
- }
-
- auto* dest = expr->args[0];
- auto* compare_value = expr->args[1];
- auto* value = expr->args[2];
-
- std::string compare = UniqueIdentifier("atomic_compare_value");
-
- { // T compare_value = <compare_value>;
- auto pre = Line();
- if (!EmitTypeAndName(pre, TypeOf(compare_value)->UnwrapRef(),
- core::AddressSpace::kUndefined, core::Access::kUndefined,
- compare)) {
- return false;
- }
- pre << " = ";
- if (!EmitExpression(pre, compare_value)) {
- return false;
- }
- pre << ";";
- }
-
- { // InterlockedCompareExchange(dst, compare, value, result.old_value);
- auto pre = Line();
- pre << "InterlockedCompareExchange";
- {
- ScopedParen sp(pre);
- if (!EmitExpression(pre, dest)) {
- return false;
- }
- pre << ", " << compare << ", ";
- if (!EmitExpression(pre, value)) {
- return false;
- }
- pre << ", " << result << ".old_value";
- }
- pre << ";";
- }
-
- // result.exchanged = result.old_value == compare;
- Line() << result << ".exchanged = " << result << ".old_value == " << compare << ";";
-
- out << result;
- return true;
- }
-
- case wgsl::BuiltinFn::kAtomicAdd:
- return call("InterlockedAdd");
-
- case wgsl::BuiltinFn::kAtomicSub: {
- auto pre = Line();
- // Sub uses InterlockedAdd with the operand negated.
- pre << "InterlockedAdd";
- {
- ScopedParen sp(pre);
- TINT_ASSERT(expr->args.Length() == 2);
-
- if (!EmitExpression(pre, expr->args[0])) {
- return false;
- }
- pre << ", -";
- {
- ScopedParen argSP(pre);
- if (!EmitExpression(pre, expr->args[1])) {
- return false;
- }
- }
-
- pre << ", " << result;
- }
-
- pre << ";";
-
- out << result;
- }
- return true;
-
- case wgsl::BuiltinFn::kAtomicMax:
- return call("InterlockedMax");
-
- case wgsl::BuiltinFn::kAtomicMin:
- return call("InterlockedMin");
-
- case wgsl::BuiltinFn::kAtomicAnd:
- return call("InterlockedAnd");
-
- case wgsl::BuiltinFn::kAtomicOr:
- return call("InterlockedOr");
-
- case wgsl::BuiltinFn::kAtomicXor:
- return call("InterlockedXor");
-
- case wgsl::BuiltinFn::kAtomicExchange:
- return call("InterlockedExchange");
-
- default:
- break;
- }
-
- TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Fn();
-}
-
-bool ASTPrinter::EmitSelectCall(StringStream& out, const ast::CallExpression* expr) {
- auto* expr_false = expr->args[0];
- auto* expr_true = expr->args[1];
- auto* expr_cond = expr->args[2];
- ScopedParen paren(out);
- if (!EmitExpression(out, expr_cond)) {
- return false;
- }
-
- out << " ? ";
-
- if (!EmitExpression(out, expr_true)) {
- return false;
- }
-
- out << " : ";
-
- if (!EmitExpression(out, expr_false)) {
- return false;
- }
-
- return true;
-}
-
-bool ASTPrinter::EmitModfCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- return CallBuiltinHelper(
- out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
- auto* ty = builtin->Parameters()[0]->Type();
- auto in = params[0];
-
- std::string width;
- if (auto* vec = ty->As<core::type::Vector>()) {
- width = std::to_string(vec->Width());
- }
-
- // Emit the builtin return type unique to this overload. This does not
- // exist in the AST, so it will not be generated in Generate().
- if (!EmitStructType(&helpers_, builtin->ReturnType()->As<core::type::Struct>())) {
- return false;
- }
-
- {
- auto l = Line(b);
- if (!EmitType(l, builtin->ReturnType(), core::AddressSpace::kUndefined,
- core::Access::kUndefined, "")) {
- return false;
- }
- l << " result;";
- }
- Line(b) << "result.fract = modf(" << params[0] << ", result.whole);";
- Line(b) << "return result;";
- return true;
- });
-}
-
-bool ASTPrinter::EmitFrexpCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- return CallBuiltinHelper(
- out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
- auto* ty = builtin->Parameters()[0]->Type();
- auto in = params[0];
-
- std::string width;
- if (auto* vec = ty->As<core::type::Vector>()) {
- width = std::to_string(vec->Width());
- }
-
- // Emit the builtin return type unique to this overload. This does not
- // exist in the AST, so it will not be generated in Generate().
- if (!EmitStructType(&helpers_, builtin->ReturnType()->As<core::type::Struct>())) {
- return false;
- }
-
- std::string member_type;
- if (Is<core::type::F16>(ty->DeepestElement())) {
- member_type = width.empty() ? "float16_t" : ("vector<float16_t, " + width + ">");
- } else {
- member_type = "float" + width;
- }
-
- Line(b) << member_type << " exp;";
- Line(b) << member_type << " fract = sign(" << in << ") * frexp(" << in << ", exp);";
- {
- auto l = Line(b);
- if (!EmitType(l, builtin->ReturnType(), core::AddressSpace::kUndefined,
- core::Access::kUndefined, "")) {
- return false;
- }
- l << " result = {fract, int" << width << "(exp)};";
- }
- Line(b) << "return result;";
- return true;
- });
-}
-
-bool ASTPrinter::EmitDegreesCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- return CallBuiltinHelper(out, expr, builtin,
- [&](TextBuffer* b, const std::vector<std::string>& params) {
- Line(b) << "return " << params[0] << " * " << std::setprecision(20)
- << sem::kRadToDeg << ";";
- return true;
- });
-}
-
-bool ASTPrinter::EmitRadiansCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- return CallBuiltinHelper(out, expr, builtin,
- [&](TextBuffer* b, const std::vector<std::string>& params) {
- Line(b) << "return " << params[0] << " * " << std::setprecision(20)
- << sem::kDegToRad << ";";
- return true;
- });
-}
-
-// The HLSL `sign` method always returns an `int` result (scalar or vector). In WGSL the result is
-// expected to be the same type as the argument. This injects a cast to the expected WGSL result
-// type after the call to `sign`.
-bool ASTPrinter::EmitSignCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn*) {
- auto* arg = call->Arguments()[0];
- if (!EmitType(out, arg->Type(), core::AddressSpace::kUndefined, core::Access::kReadWrite, "")) {
- return false;
- }
- out << "(sign(";
- if (!EmitExpression(out, arg->Declaration())) {
- return false;
- }
- out << "))";
- return true;
-}
-
-bool ASTPrinter::EmitQuantizeToF16Call(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- // Cast to f16 and back
- std::string width;
- if (auto* vec = builtin->ReturnType()->As<core::type::Vector>()) {
- width = std::to_string(vec->Width());
- }
- out << "f16tof32(f32tof16(";
- if (!EmitExpression(out, expr->args[0])) {
- return false;
- }
- out << "))";
- return true;
-}
-
-bool ASTPrinter::EmitTruncCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- // HLSL's trunc is broken for very large/small float values.
- // See crbug.com/tint/1883
- return CallBuiltinHelper( //
- out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
- // value < 0 ? ceil(value) : floor(value)
- Line(b) << "return " << params[0] << " < 0 ? ceil(" << params[0] << ") : floor("
- << params[0] << ");";
- return true;
- });
-}
-
-bool ASTPrinter::EmitDataPackingCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- return CallBuiltinHelper(
- out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
- uint32_t dims = 2;
- bool is_signed = false;
- uint32_t scale = 65535;
- if (builtin->Fn() == wgsl::BuiltinFn::kPack4X8Snorm ||
- builtin->Fn() == wgsl::BuiltinFn::kPack4X8Unorm) {
- dims = 4;
- scale = 255;
- }
- if (builtin->Fn() == wgsl::BuiltinFn::kPack4X8Snorm ||
- builtin->Fn() == wgsl::BuiltinFn::kPack2X16Snorm) {
- is_signed = true;
- scale = (scale - 1) / 2;
- }
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kPack4X8Snorm:
- case wgsl::BuiltinFn::kPack4X8Unorm:
- case wgsl::BuiltinFn::kPack2X16Snorm:
- case wgsl::BuiltinFn::kPack2X16Unorm: {
- {
- auto l = Line(b);
- l << (is_signed ? "" : "u") << "int" << dims
- << " i = " << (is_signed ? "" : "u") << "int" << dims << "(round(clamp("
- << params[0] << ", " << (is_signed ? "-1.0" : "0.0") << ", 1.0) * "
- << scale << ".0))";
- if (is_signed) {
- l << " & " << (dims == 4 ? "0xff" : "0xffff");
- }
- l << ";";
- }
- {
- auto l = Line(b);
- l << "return ";
- if (is_signed) {
- l << "asuint";
- }
- l << "(i.x | i.y << " << (32 / dims);
- if (dims == 4) {
- l << " | i.z << 16 | i.w << 24";
- }
- l << ");";
- }
- break;
- }
- case wgsl::BuiltinFn::kPack2X16Float: {
- Line(b) << "uint2 i = f32tof16(" << params[0] << ");";
- Line(b) << "return i.x | (i.y << 16);";
- break;
- }
- default:
- TINT_ICE() << " unhandled data packing builtin";
- }
-
- return true;
- });
-}
-
-bool ASTPrinter::EmitDataUnpackingCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- return CallBuiltinHelper(
- out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
- uint32_t dims = 2;
- bool is_signed = false;
- uint32_t scale = 65535;
- if (builtin->Fn() == wgsl::BuiltinFn::kUnpack4X8Snorm ||
- builtin->Fn() == wgsl::BuiltinFn::kUnpack4X8Unorm) {
- dims = 4;
- scale = 255;
- }
- if (builtin->Fn() == wgsl::BuiltinFn::kUnpack4X8Snorm ||
- builtin->Fn() == wgsl::BuiltinFn::kUnpack2X16Snorm) {
- is_signed = true;
- scale = (scale - 1) / 2;
- }
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kUnpack4X8Snorm:
- case wgsl::BuiltinFn::kUnpack2X16Snorm: {
- Line(b) << "int j = int(" << params[0] << ");";
- { // Perform sign extension on the converted values.
- auto l = Line(b);
- l << "int" << dims << " i = int" << dims << "(";
- if (dims == 2) {
- l << "j << 16, j) >> 16";
- } else {
- l << "j << 24, j << 16, j << 8, j) >> 24";
- }
- l << ";";
- }
- Line(b) << "return clamp(float" << dims << "(i) / " << scale << ".0, "
- << (is_signed ? "-1.0" : "0.0") << ", 1.0);";
- break;
- }
- case wgsl::BuiltinFn::kUnpack4X8Unorm:
- case wgsl::BuiltinFn::kUnpack2X16Unorm: {
- Line(b) << "uint j = " << params[0] << ";";
- {
- auto l = Line(b);
- l << "uint" << dims << " i = uint" << dims << "(";
- l << "j & " << (dims == 2 ? "0xffff" : "0xff") << ", ";
- if (dims == 4) {
- l << "(j >> " << (32 / dims) << ") & 0xff, (j >> 16) & 0xff, j >> 24";
- } else {
- l << "j >> " << (32 / dims);
- }
- l << ");";
- }
- Line(b) << "return float" << dims << "(i) / " << scale << ".0;";
- break;
- }
- case wgsl::BuiltinFn::kUnpack2X16Float:
- Line(b) << "uint i = " << params[0] << ";";
- Line(b) << "return f16tof32(uint2(i & 0xffff, i >> 16));";
- break;
- default:
- TINT_ICE() << "unhandled data packing builtin";
- }
-
- return true;
- });
-}
-
-bool ASTPrinter::EmitPacked4x8IntegerDotProductBuiltinCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kDot4I8Packed:
- case wgsl::BuiltinFn::kDot4U8Packed:
- break;
- case wgsl::BuiltinFn::kPack4XI8: {
- out << "uint(pack_s8(";
- if (!EmitExpression(out, expr->args[0])) {
- return false;
- }
- out << "))";
- return true;
- }
- case wgsl::BuiltinFn::kPack4XU8: {
- out << "uint(pack_u8(";
- if (!EmitExpression(out, expr->args[0])) {
- return false;
- }
- out << "))";
- return true;
- }
- case wgsl::BuiltinFn::kPack4XI8Clamp: {
- out << "uint(pack_clamp_s8(";
- if (!EmitExpression(out, expr->args[0])) {
- return false;
- }
- out << "))";
- return true;
- }
- case wgsl::BuiltinFn::kUnpack4XI8: {
- out << "unpack_s8s32(int8_t4_packed(";
- if (!EmitExpression(out, expr->args[0])) {
- return false;
- }
- out << "))";
- return true;
- }
- case wgsl::BuiltinFn::kUnpack4XU8: {
- out << "unpack_u8u32(uint8_t4_packed(";
- if (!EmitExpression(out, expr->args[0])) {
- return false;
- }
- out << "))";
- return true;
- }
- case wgsl::BuiltinFn::kPack4XU8Clamp:
- default:
- TINT_UNIMPLEMENTED() << builtin->Fn();
- }
-
- return CallBuiltinHelper(out, expr, builtin,
- [&](TextBuffer* b, const std::vector<std::string>& params) {
- std::string functionName;
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kDot4I8Packed:
- Line(b) << "int accumulator = 0;";
- functionName = "dot4add_i8packed";
- break;
- case wgsl::BuiltinFn::kDot4U8Packed:
- Line(b) << "uint accumulator = 0u;";
- functionName = "dot4add_u8packed";
- break;
- default:
- TINT_ICE() << "Internal error: unhandled DP4a builtin";
- }
- Line(b) << "return " << functionName << "(" << params[0] << ", "
- << params[1] << ", accumulator);";
-
- return true;
- });
-}
-
-bool ASTPrinter::EmitBarrierCall(StringStream& out, const sem::BuiltinFn* builtin) {
- // TODO(crbug.com/tint/661): Combine sequential barriers to a single
- // instruction.
- if (builtin->Fn() == wgsl::BuiltinFn::kWorkgroupBarrier) {
- out << "GroupMemoryBarrierWithGroupSync()";
- } else if (builtin->Fn() == wgsl::BuiltinFn::kStorageBarrier) {
- out << "DeviceMemoryBarrierWithGroupSync()";
- } else if (builtin->Fn() == wgsl::BuiltinFn::kTextureBarrier) {
- out << "DeviceMemoryBarrierWithGroupSync()";
- } else {
- TINT_UNREACHABLE() << "unexpected barrier builtin type " << builtin->Fn();
- }
- return true;
-}
-
-bool ASTPrinter::EmitTextureOrStorageBufferCallArgExpression(StringStream& out,
- const ast::Expression* expr) {
- // TODO(crbug.com/tint/1976): Workaround DXC bug that fails to compile texture/storage function
- // calls with signed integer splatted constants. DXC fails to convert the coord arg, for e.g.
- // `0.xxx`, from a vector of 64-bit ints to a vector of 32-bit ints to match the texture load
- // parameter type. We work around this for now by explicitly casting the splatted constant to
- // the right type, for e.g. `int3(0.xxx)`.
- bool emitted_cast = false;
- if (auto* sem = builder_.Sem().GetVal(expr)) {
- if (auto* constant = sem->ConstantValue()) {
- if (auto* splat = constant->As<core::constant::Splat>()) {
- if (splat->Type()->IsSignedIntegerVector()) {
- if (!EmitType(out, constant->Type(), core::AddressSpace::kUndefined,
- core::Access::kUndefined, "")) {
- return false;
- }
- out << "(";
- emitted_cast = true;
- }
- }
- }
- }
- if (!EmitExpression(out, expr)) {
- return false;
- }
- if (emitted_cast) {
- out << ")";
- }
- return true;
-}
-
-bool ASTPrinter::EmitTextureCall(StringStream& out,
- const sem::Call* call,
- const sem::BuiltinFn* builtin) {
- using Usage = core::ParameterUsage;
-
- auto& signature = builtin->Signature();
- auto* expr = call->Declaration();
- auto arguments = expr->args;
-
- // Returns the argument with the given usage
- auto arg = [&](Usage usage) {
- int idx = signature.IndexOf(usage);
- return (idx >= 0) ? arguments[static_cast<size_t>(idx)] : nullptr;
- };
-
- auto* texture = arg(Usage::kTexture);
- if (DAWN_UNLIKELY(!texture)) {
- TINT_ICE() << "missing texture argument";
- }
-
- auto* texture_type = TypeOf(texture)->UnwrapRef()->As<core::type::Texture>();
-
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kTextureDimensions:
- case wgsl::BuiltinFn::kTextureNumLayers:
- case wgsl::BuiltinFn::kTextureNumLevels:
- case wgsl::BuiltinFn::kTextureNumSamples: {
- // All of these builtins use the GetDimensions() method on the texture
- bool is_ms = texture_type->IsAnyOf<core::type::MultisampledTexture,
- core::type::DepthMultisampledTexture>();
- unsigned int num_dimensions = 0;
- std::string swizzle;
-
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kTextureDimensions:
- switch (texture_type->Dim()) {
- case core::type::TextureDimension::kNone:
- TINT_ICE() << "texture dimension is kNone";
- case core::type::TextureDimension::k1d:
- num_dimensions = 1;
- break;
- case core::type::TextureDimension::k2d:
- num_dimensions = is_ms ? 3 : 2;
- swizzle = is_ms ? ".xy" : "";
- break;
- case core::type::TextureDimension::k2dArray:
- num_dimensions = is_ms ? 4 : 3;
- swizzle = ".xy";
- break;
- case core::type::TextureDimension::k3d:
- num_dimensions = 3;
- break;
- case core::type::TextureDimension::kCube:
- num_dimensions = 2;
- break;
- case core::type::TextureDimension::kCubeArray:
- num_dimensions = 3;
- swizzle = ".xy";
- break;
- }
- break;
- case wgsl::BuiltinFn::kTextureNumLayers:
- switch (texture_type->Dim()) {
- default:
- TINT_ICE() << "texture dimension is not arrayed";
- case core::type::TextureDimension::k2dArray:
- num_dimensions = is_ms ? 4 : 3;
- swizzle = ".z";
- break;
- case core::type::TextureDimension::kCubeArray:
- num_dimensions = 3;
- swizzle = ".z";
- break;
- }
- break;
- case wgsl::BuiltinFn::kTextureNumLevels:
- switch (texture_type->Dim()) {
- default:
- TINT_ICE() << "texture dimension does not support mips";
- case core::type::TextureDimension::k1d:
- num_dimensions = 2;
- swizzle = ".y";
- break;
- case core::type::TextureDimension::k2d:
- case core::type::TextureDimension::kCube:
- num_dimensions = 3;
- swizzle = ".z";
- break;
- case core::type::TextureDimension::k2dArray:
- case core::type::TextureDimension::k3d:
- case core::type::TextureDimension::kCubeArray:
- num_dimensions = 4;
- swizzle = ".w";
- break;
- }
- break;
- case wgsl::BuiltinFn::kTextureNumSamples:
- switch (texture_type->Dim()) {
- default:
- TINT_ICE() << "texture dimension does not support multisampling";
- case core::type::TextureDimension::k2d:
- num_dimensions = 3;
- swizzle = ".z";
- break;
- case core::type::TextureDimension::k2dArray:
- num_dimensions = 4;
- swizzle = ".w";
- break;
- }
- break;
- default:
- TINT_ICE() << "unexpected builtin";
- }
-
- auto* level_arg = arg(Usage::kLevel);
-
- if (level_arg) {
- // `NumberOfLevels` is a non-optional argument if `MipLevel` was passed.
- // Increment the number of dimensions for the temporary vector to
- // accommodate this.
- num_dimensions++;
-
- // If the swizzle was empty, the expression will evaluate to the whole
- // vector. As we've grown the vector by one element, we now need to
- // swizzle to keep the result expression equivalent.
- if (swizzle.empty()) {
- static constexpr std::array<const char*, 4> swizzles = {"", ".x", ".xy",
- ".xyz"};
- swizzle = swizzles[num_dimensions - 1];
- }
- }
-
- if (DAWN_UNLIKELY(num_dimensions > 4)) {
- TINT_ICE() << "Texture query builtin temporary vector has " << num_dimensions
- << " dimensions";
- }
-
- // Declare a variable to hold the queried texture info
- auto dims = UniqueIdentifier(kTempNamePrefix);
- if (num_dimensions == 1) {
- Line() << "uint " << dims << ";";
- } else {
- Line() << "uint" << num_dimensions << " " << dims << ";";
- }
-
- { // texture.GetDimensions(...)
- auto pre = Line();
- if (!EmitExpression(pre, texture)) {
- return false;
- }
- pre << ".GetDimensions(";
-
- if (level_arg) {
- if (!EmitExpression(pre, level_arg)) {
- return false;
- }
- pre << ", ";
- } else if (builtin->Fn() == wgsl::BuiltinFn::kTextureNumLevels) {
- pre << "0, ";
- }
-
- if (num_dimensions == 1) {
- pre << dims;
- } else {
- if (DAWN_UNLIKELY(num_dimensions < 0 || num_dimensions > 4)) {
- TINT_ICE() << "vector dimensions are " << num_dimensions;
- }
- for (unsigned int i = 0; i < num_dimensions; i++) {
- if (i > 0) {
- pre << ", ";
- }
- pre << dims << "." << kSwizzle[i];
- }
- }
-
- pre << ");";
- }
-
- // The out parameters of the GetDimensions() call is now in temporary
- // `dims` variable. This may be packed with other data, so the final
- // expression may require a swizzle.
- out << dims << swizzle;
- return true;
- }
- default:
- break;
- }
-
- if (!EmitExpression(out, texture)) {
- return false;
- }
-
- // If pack_level_in_coords is true, then the mip level will be appended as the
- // last value of the coordinates argument. If the WGSL builtin overload does
- // not have a level parameter and pack_level_in_coords is true, then a zero
- // mip level will be inserted.
- bool pack_level_in_coords = false;
-
- uint32_t hlsl_ret_width = 4u;
-
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kTextureSample:
- out << ".Sample(";
- break;
- case wgsl::BuiltinFn::kTextureSampleBias:
- out << ".SampleBias(";
- break;
- case wgsl::BuiltinFn::kTextureSampleLevel:
- out << ".SampleLevel(";
- break;
- case wgsl::BuiltinFn::kTextureSampleGrad:
- out << ".SampleGrad(";
- break;
- case wgsl::BuiltinFn::kTextureSampleCompare:
- out << ".SampleCmp(";
- hlsl_ret_width = 1;
- break;
- case wgsl::BuiltinFn::kTextureSampleCompareLevel:
- out << ".SampleCmpLevelZero(";
- hlsl_ret_width = 1;
- break;
- case wgsl::BuiltinFn::kTextureLoad:
- out << ".Load(";
- // Multisampled textures and read-write storage textures do not support mip-levels.
- if (texture_type->Is<core::type::MultisampledTexture>()) {
- break;
- }
- if (auto* storage_texture_type = texture_type->As<core::type::StorageTexture>()) {
- if (storage_texture_type->Access() == core::Access::kReadWrite) {
- break;
- }
- }
- pack_level_in_coords = true;
- break;
- case wgsl::BuiltinFn::kTextureGather:
- out << ".Gather";
- if (builtin->Parameters()[0]->Usage() == core::ParameterUsage::kComponent) {
- switch (call->Arguments()[0]->ConstantValue()->ValueAs<AInt>()) {
- case 0:
- out << "Red";
- break;
- case 1:
- out << "Green";
- break;
- case 2:
- out << "Blue";
- break;
- case 3:
- out << "Alpha";
- break;
- }
- }
- out << "(";
- break;
- case wgsl::BuiltinFn::kTextureGatherCompare:
- out << ".GatherCmp(";
- break;
- case wgsl::BuiltinFn::kTextureStore:
- out << "[";
- break;
- default:
- TINT_ICE() << "Unhandled texture builtin '" << builtin << "'";
- }
-
- if (auto* sampler = arg(Usage::kSampler)) {
- if (!EmitExpression(out, sampler)) {
- return false;
- }
- out << ", ";
- }
-
- auto* param_coords = arg(Usage::kCoords);
- if (DAWN_UNLIKELY(!param_coords)) {
- TINT_ICE() << "missing coords argument";
- }
-
- auto emit_vector_appended_with_i32_zero = [&](const ast::Expression* vector) {
- auto* i32 = builder_.create<core::type::I32>();
- auto* zero = builder_.Expr(0_i);
- auto* stmt = builder_.Sem().Get(vector)->Stmt();
- builder_.Sem().Add(zero, builder_.create<sem::ValueExpression>(
- zero, i32, core::EvaluationStage::kRuntime, stmt,
- /* constant_value */ nullptr,
- /* has_side_effects */ false));
- auto* packed = AppendVector(&builder_, vector, zero);
- return EmitExpression(out, packed->Declaration());
- };
-
- auto emit_vector_appended_with_level = [&](const ast::Expression* vector) {
- if (auto* level = arg(Usage::kLevel)) {
- auto* packed = AppendVector(&builder_, vector, level);
- return EmitExpression(out, packed->Declaration());
- }
- return emit_vector_appended_with_i32_zero(vector);
- };
-
- if (auto* array_index = arg(Usage::kArrayIndex)) {
- // Array index needs to be appended to the coordinates.
- auto* packed = AppendVector(&builder_, param_coords, array_index);
- if (pack_level_in_coords) {
- // Then mip level needs to be appended to the coordinates.
- if (!emit_vector_appended_with_level(packed->Declaration())) {
- return false;
- }
- } else {
- if (!EmitExpression(out, packed->Declaration())) {
- return false;
- }
- }
- } else if (pack_level_in_coords) {
- // Mip level needs to be appended to the coordinates.
- if (!emit_vector_appended_with_level(param_coords)) {
- return false;
- }
- } else if (builtin->Fn() == wgsl::BuiltinFn::kTextureStore) {
- // param_coords is an index expression, not a function arg
- if (!EmitExpression(out, param_coords)) {
- return false;
- }
- } else if (!EmitTextureOrStorageBufferCallArgExpression(out, param_coords)) {
- return false;
- }
-
- for (auto usage : {Usage::kDepthRef, Usage::kBias, Usage::kLevel, Usage::kDdx, Usage::kDdy,
- Usage::kSampleIndex, Usage::kOffset}) {
- if (usage == Usage::kLevel && pack_level_in_coords) {
- continue; // mip level already packed in coordinates.
- }
- if (auto* e = arg(usage)) {
- out << ", ";
- if (usage == Usage::kBias) {
- out << "clamp(";
- }
- if (!EmitTextureOrStorageBufferCallArgExpression(out, e)) {
- return false;
- }
- if (usage == Usage::kBias) {
- out << ", -16.0f, 15.99f)";
- }
- }
- }
-
- if (builtin->Fn() == wgsl::BuiltinFn::kTextureStore) {
- out << "] = ";
- if (!EmitExpression(out, arg(Usage::kValue))) {
- return false;
- }
- } else {
- out << ")";
-
- // If the builtin return type does not match the number of elements of the
- // HLSL builtin, we need to swizzle the expression to generate the correct
- // number of components.
- uint32_t wgsl_ret_width = 1;
- if (auto* vec = builtin->ReturnType()->As<core::type::Vector>()) {
- wgsl_ret_width = vec->Width();
- }
- if (wgsl_ret_width < hlsl_ret_width) {
- out << ".";
- TINT_ASSERT(wgsl_ret_width < 3);
- for (uint32_t i = 0; i < wgsl_ret_width; i++) {
- out << kSwizzle[i];
- }
- }
- if (DAWN_UNLIKELY(wgsl_ret_width > hlsl_ret_width)) {
- TINT_ICE() << "WGSL return width (" << wgsl_ret_width
- << ") is wider than HLSL return width (" << hlsl_ret_width << ") for "
- << builtin->Fn();
- }
- }
-
- return true;
-}
-
-// The following subgroup builtin functions are translated to HLSL as follows:
-// +---------------------+----------------------------------------------------------------+
-// | WGSL | HLSL |
-// +---------------------+----------------------------------------------------------------+
-// | subgroupShuffleXor | WaveReadLaneAt with index equal subgroup_invocation_id ^ mask |
-// | subgroupShuffleUp | WaveReadLaneAt with index equal subgroup_invocation_id - delta |
-// | subgroupShuffleDown | WaveReadLaneAt with index equal subgroup_invocation_id + delta |
-// +---------------------+----------------------------------------------------------------+
-bool ASTPrinter::EmitSubgroupShuffleBuiltinCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- out << "WaveReadLaneAt(";
-
- if (!EmitExpression(out, expr->args[0])) {
- return false;
- }
-
- out << ", (WaveGetLaneIndex() ";
-
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kSubgroupShuffleXor:
- out << "^ ";
- break;
- case wgsl::BuiltinFn::kSubgroupShuffleUp:
- out << "- ";
- break;
- case wgsl::BuiltinFn::kSubgroupShuffleDown:
- out << "+ ";
- break;
- default:
- TINT_UNREACHABLE();
- }
-
- if (!EmitExpression(out, expr->args[1])) {
- return false;
- }
- out << "))";
-
- return true;
-}
-
-// The following subgroup builtin functions are translated to HLSL as follows:
-// +-----------------------+----------------------+
-// | WGSL | HLSL |
-// +-----------------------+----------------------+
-// | subgroupInclusiveAdd | WavePrefixSum(x) + x |
-// | subgroupInclusiveMul | WavePrefixMul(x) * x |
-// +-----------------------+----------------------+
-bool ASTPrinter::EmitSubgroupInclusiveBuiltinCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin) {
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kSubgroupInclusiveAdd:
- out << "(WavePrefixSum(";
- break;
- case wgsl::BuiltinFn::kSubgroupInclusiveMul:
- out << "(WavePrefixProduct(";
- break;
- default:
- TINT_UNREACHABLE();
- }
-
- if (!EmitExpression(out, expr->args[0])) {
- return false;
- }
-
- out << ") ";
-
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kSubgroupInclusiveAdd:
- out << "+";
- break;
- case wgsl::BuiltinFn::kSubgroupInclusiveMul:
- out << "*";
- break;
- default:
- TINT_UNREACHABLE();
- }
- // Add a space after the operand to be more consistent with IR generated code.
- out << " ";
- if (!EmitExpression(out, expr->args[0])) {
- return false;
- }
-
- out << ")";
-
- return true;
-}
-
-std::string ASTPrinter::generate_builtin_name(const sem::BuiltinFn* builtin) {
- switch (builtin->Fn()) {
- case wgsl::BuiltinFn::kAbs:
- case wgsl::BuiltinFn::kAcos:
- case wgsl::BuiltinFn::kAll:
- case wgsl::BuiltinFn::kAny:
- case wgsl::BuiltinFn::kAsin:
- case wgsl::BuiltinFn::kAtan:
- case wgsl::BuiltinFn::kAtan2:
- case wgsl::BuiltinFn::kCeil:
- case wgsl::BuiltinFn::kClamp:
- case wgsl::BuiltinFn::kCos:
- case wgsl::BuiltinFn::kCosh:
- case wgsl::BuiltinFn::kCross:
- case wgsl::BuiltinFn::kDeterminant:
- case wgsl::BuiltinFn::kDistance:
- case wgsl::BuiltinFn::kDot:
- case wgsl::BuiltinFn::kExp:
- case wgsl::BuiltinFn::kExp2:
- case wgsl::BuiltinFn::kFloor:
- case wgsl::BuiltinFn::kFrexp:
- case wgsl::BuiltinFn::kLdexp:
- case wgsl::BuiltinFn::kLength:
- case wgsl::BuiltinFn::kLog:
- case wgsl::BuiltinFn::kLog2:
- case wgsl::BuiltinFn::kMax:
- case wgsl::BuiltinFn::kMin:
- case wgsl::BuiltinFn::kModf:
- case wgsl::BuiltinFn::kNormalize:
- case wgsl::BuiltinFn::kPow:
- case wgsl::BuiltinFn::kReflect:
- case wgsl::BuiltinFn::kRefract:
- case wgsl::BuiltinFn::kRound:
- case wgsl::BuiltinFn::kSaturate:
- case wgsl::BuiltinFn::kSin:
- case wgsl::BuiltinFn::kSinh:
- case wgsl::BuiltinFn::kSqrt:
- case wgsl::BuiltinFn::kStep:
- case wgsl::BuiltinFn::kTan:
- case wgsl::BuiltinFn::kTanh:
- case wgsl::BuiltinFn::kTranspose:
- return builtin->str();
- case wgsl::BuiltinFn::kCountOneBits: // uint
- return "countbits";
- case wgsl::BuiltinFn::kDpdx:
- return "ddx";
- case wgsl::BuiltinFn::kDpdxCoarse:
- return "ddx_coarse";
- case wgsl::BuiltinFn::kDpdxFine:
- return "ddx_fine";
- case wgsl::BuiltinFn::kDpdy:
- return "ddy";
- case wgsl::BuiltinFn::kDpdyCoarse:
- return "ddy_coarse";
- case wgsl::BuiltinFn::kDpdyFine:
- return "ddy_fine";
- case wgsl::BuiltinFn::kFaceForward:
- return "faceforward";
- case wgsl::BuiltinFn::kFract:
- return "frac";
- case wgsl::BuiltinFn::kFma:
- return "mad";
- case wgsl::BuiltinFn::kFwidth:
- case wgsl::BuiltinFn::kFwidthCoarse:
- case wgsl::BuiltinFn::kFwidthFine:
- return "fwidth";
- case wgsl::BuiltinFn::kInverseSqrt:
- return "rsqrt";
- case wgsl::BuiltinFn::kMix:
- return "lerp";
- case wgsl::BuiltinFn::kReverseBits: // uint
- return "reversebits";
- case wgsl::BuiltinFn::kSmoothstep:
- return "smoothstep";
- case wgsl::BuiltinFn::kSubgroupBallot:
- return "WaveActiveBallot";
- case wgsl::BuiltinFn::kSubgroupElect:
- return "WaveIsFirstLane";
- case wgsl::BuiltinFn::kSubgroupBroadcast:
- return "WaveReadLaneAt";
- case wgsl::BuiltinFn::kSubgroupBroadcastFirst:
- return "WaveReadLaneFirst";
- case wgsl::BuiltinFn::kSubgroupShuffle:
- return "WaveReadLaneAt";
- case wgsl::BuiltinFn::kSubgroupAdd:
- return "WaveActiveSum";
- case wgsl::BuiltinFn::kSubgroupExclusiveAdd:
- return "WavePrefixSum";
- case wgsl::BuiltinFn::kSubgroupMul:
- return "WaveActiveProduct";
- case wgsl::BuiltinFn::kSubgroupExclusiveMul:
- return "WavePrefixProduct";
- case wgsl::BuiltinFn::kSubgroupAnd:
- return "WaveActiveBitAnd";
- case wgsl::BuiltinFn::kSubgroupOr:
- return "WaveActiveBitOr";
- case wgsl::BuiltinFn::kSubgroupXor:
- return "WaveActiveBitXor";
- case wgsl::BuiltinFn::kSubgroupMin:
- return "WaveActiveMin";
- case wgsl::BuiltinFn::kSubgroupMax:
- return "WaveActiveMax";
- case wgsl::BuiltinFn::kSubgroupAll:
- return "WaveActiveAllTrue";
- case wgsl::BuiltinFn::kSubgroupAny:
- return "WaveActiveAnyTrue";
- case wgsl::BuiltinFn::kQuadBroadcast:
- return "QuadReadLaneAt";
- case wgsl::BuiltinFn::kQuadSwapX:
- return "QuadReadAcrossX";
- case wgsl::BuiltinFn::kQuadSwapY:
- return "QuadReadAcrossY";
- case wgsl::BuiltinFn::kQuadSwapDiagonal:
- return "QuadReadAcrossDiagonal";
- default:
- diagnostics_.AddError(Source{}) << "Unknown builtin method: " << builtin->str();
- }
-
- return "";
-}
-
-bool ASTPrinter::EmitCase(const ast::SwitchStatement* s, size_t case_idx) {
- auto* stmt = s->body[case_idx];
- auto* sem = builder_.Sem().Get<sem::CaseStatement>(stmt);
- for (auto* selector : sem->Selectors()) {
- auto out = Line();
- if (selector->IsDefault()) {
- out << "default";
- } else {
- out << "case ";
- if (!EmitConstant(out, selector->Value(), /* is_variable_initializer */ false)) {
- return false;
- }
- }
- out << ":";
- if (selector == sem->Selectors().back()) {
- out << " {";
- }
- }
-
- IncrementIndent();
- TINT_DEFER({
- DecrementIndent();
- Line() << "}";
- });
-
- // Emit the case statement
- if (!EmitStatements(stmt->body->statements)) {
- return false;
- }
-
- if (!tint::IsAnyOf<ast::BreakStatement>(stmt->body->Last())) {
- Line() << "break;";
- }
-
- return true;
-}
-
-bool ASTPrinter::EmitContinue(const ast::ContinueStatement*) {
- if (!emit_continuing_ || !emit_continuing_()) {
- return false;
- }
- Line() << "continue;";
- return true;
-}
-
-bool ASTPrinter::EmitDiscard(const ast::DiscardStatement*) {
- // TODO(dsinclair): Verify this is correct when the discard semantics are
- // defined for WGSL (https://github.com/gpuweb/gpuweb/issues/361)
- Line() << "discard;";
- return true;
-}
-
-bool ASTPrinter::EmitExpression(StringStream& out, const ast::Expression* expr) {
- if (auto* sem = builder_.Sem().GetVal(expr)) {
- if (auto* constant = sem->ConstantValue()) {
- bool is_variable_initializer = false;
- if (auto* stmt = sem->Stmt()) {
- if (auto* decl = As<ast::VariableDeclStatement>(stmt->Declaration())) {
- is_variable_initializer = decl->variable->initializer == expr;
- }
- }
- return EmitConstant(out, constant, is_variable_initializer);
- }
- }
- return Switch(
- expr, //
- [&](const ast::IndexAccessorExpression* a) { return EmitIndexAccessor(out, a); },
- [&](const ast::BinaryExpression* b) { return EmitBinary(out, b); },
- [&](const ast::CallExpression* c) { return EmitCall(out, c); },
- [&](const ast::IdentifierExpression* i) { return EmitIdentifier(out, i); },
- [&](const ast::LiteralExpression* l) { return EmitLiteral(out, l); },
- [&](const ast::MemberAccessorExpression* m) { return EmitMemberAccessor(out, m); },
- [&](const ast::UnaryOpExpression* u) { return EmitUnaryOp(out, u); }, //
- TINT_ICE_ON_NO_MATCH);
-}
-
-bool ASTPrinter::EmitIdentifier(StringStream& out, const ast::IdentifierExpression* expr) {
- out << expr->identifier->symbol.Name();
- return true;
-}
-
-bool ASTPrinter::EmitIf(const ast::IfStatement* stmt) {
- {
- auto out = Line();
- out << "if (";
- if (!EmitExpression(out, stmt->condition)) {
- return false;
- }
- out << ") {";
- }
-
- if (!EmitStatementsWithIndent(stmt->body->statements)) {
- return false;
- }
-
- if (stmt->else_statement) {
- Line() << "} else {";
- if (auto* block = stmt->else_statement->As<ast::BlockStatement>()) {
- if (!EmitStatementsWithIndent(block->statements)) {
- return false;
- }
- } else {
- if (!EmitStatementsWithIndent(Vector{stmt->else_statement})) {
- return false;
- }
- }
- }
- Line() << "}";
-
- return true;
-}
-
-bool ASTPrinter::EmitFunction(const ast::Function* func) {
- auto* sem = builder_.Sem().Get(func);
-
- // Emit storage atomic helpers
- if (auto* intrinsic = ast::GetAttribute<DecomposeMemoryAccess::Intrinsic>(func->attributes)) {
- if (intrinsic->address_space == core::AddressSpace::kStorage && intrinsic->IsAtomic()) {
- if (!EmitStorageAtomicIntrinsic(func, intrinsic)) {
- return false;
- }
- }
- return true;
- }
-
- if (ast::HasAttribute<ast::InternalAttribute>(func->attributes)) {
- // An internal function. Do not emit.
- return true;
- }
-
- {
- auto out = Line();
- auto name = func->name->symbol.Name();
- // If the function returns an array, then we need to declare a typedef for
- // this.
- if (sem->ReturnType()->Is<core::type::Array>()) {
- auto typedef_name = UniqueIdentifier(name + "_ret");
- auto pre = Line();
- pre << "typedef ";
- if (!EmitTypeAndName(pre, sem->ReturnType(), core::AddressSpace::kUndefined,
- core::Access::kReadWrite, typedef_name)) {
- return false;
- }
- pre << ";";
- out << typedef_name;
- } else {
- if (!EmitType(out, sem->ReturnType(), core::AddressSpace::kUndefined,
- core::Access::kReadWrite, "")) {
- return false;
- }
- }
-
- out << " " << name << "(";
-
- bool first = true;
-
- for (auto* v : sem->Parameters()) {
- if (!first) {
- out << ", ";
- }
- first = false;
-
- auto const* type = v->Type();
- auto address_space = core::AddressSpace::kUndefined;
- auto access = core::Access::kUndefined;
-
- if (auto* ptr = type->As<core::type::Pointer>()) {
- type = ptr->StoreType();
- switch (ptr->AddressSpace()) {
- case core::AddressSpace::kStorage:
- case core::AddressSpace::kUniform:
- // Not allowed by WGSL, but is used by certain transforms (e.g. DMA) to pass
- // storage buffers and uniform buffers down into transform-generated
- // functions. In this situation we want to generate the parameter without an
- // 'inout', using the address space and access from the pointer.
- address_space = ptr->AddressSpace();
- access = ptr->Access();
- break;
- default:
- // Transform regular WGSL pointer parameters in to `inout` parameters.
- out << "inout ";
- }
- }
-
- // Note: WGSL only allows for AddressSpace::kUndefined on parameters, however
- // the sanitizer transforms generates load / store functions for storage
- // or uniform buffers. These functions have a buffer parameter with
- // AddressSpace::kStorage or AddressSpace::kUniform. This is required to
- // correctly translate the parameter to a [RW]ByteAddressBuffer for
- // storage buffers and a uint4[N] for uniform buffers.
- if (!EmitTypeAndName(out, type, address_space, access,
- v->Declaration()->name->symbol.Name())) {
- return false;
- }
- }
- out << ") {";
- }
-
- if (sem->DiscardStatement() && !sem->ReturnType()->Is<core::type::Void>()) {
- // BUG(crbug.com/tint/1081): work around non-void functions with discard
- // failing compilation sometimes
- if (!EmitFunctionBodyWithDiscard(func)) {
- return false;
- }
- } else {
- if (!EmitStatementsWithIndent(func->body->statements)) {
- return false;
- }
- }
-
- Line() << "}";
-
- return true;
-}
-
-bool ASTPrinter::EmitFunctionBodyWithDiscard(const ast::Function* func) {
- // FXC sometimes fails to compile functions that discard with 'Not all control
- // paths return a value'. We work around this by wrapping the function body
- // within an "if (true) { <body> } return <default return type obj>;" so that
- // there is always an (unused) return statement.
-
- auto* sem = builder_.Sem().Get(func);
- TINT_ASSERT(sem->DiscardStatement() && !sem->ReturnType()->Is<core::type::Void>());
-
- ScopedIndent si(this);
- Line() << "if (true) {";
-
- if (!EmitStatementsWithIndent(func->body->statements)) {
- return false;
- }
-
- Line() << "}";
-
- // Return an unused result that matches the type of the return value
- auto name = builder_.Symbols().New("unused").Name();
- {
- auto out = Line();
- if (!EmitTypeAndName(out, sem->ReturnType(), core::AddressSpace::kUndefined,
- core::Access::kReadWrite, name)) {
- return false;
- }
- out << ";";
- }
- Line() << "return " << name << ";";
-
- return true;
-}
-
-bool ASTPrinter::EmitGlobalVariable(const ast::Variable* global) {
- return Switch(
- global, //
- [&](const ast::Var* var) {
- auto* sem = builder_.Sem().Get(global);
- switch (sem->AddressSpace()) {
- case core::AddressSpace::kUniform:
- return EmitUniformVariable(var, sem);
- case core::AddressSpace::kStorage:
- return EmitStorageVariable(var, sem);
- case core::AddressSpace::kHandle:
- return EmitHandleVariable(var, sem);
- case core::AddressSpace::kPrivate:
- return EmitPrivateVariable(sem);
- case core::AddressSpace::kWorkgroup:
- return EmitWorkgroupVariable(sem);
- case core::AddressSpace::kImmediate:
- diagnostics_.AddError(Source{})
- << "unhandled address space " << sem->AddressSpace();
- return false;
- default: {
- TINT_ICE() << "unhandled address space " << sem->AddressSpace();
- }
- }
- },
- [&](const ast::Override*) {
- // Override is removed with SubstituteOverride
- diagnostics_.AddError(Source{})
- << "override-expressions should have been removed with the SubstituteOverride "
- "transform";
- return false;
- },
- [&](const ast::Const*) {
- return true; // Constants are embedded at their use
- }, //
- TINT_ICE_ON_NO_MATCH);
-}
-
-bool ASTPrinter::EmitUniformVariable(const ast::Var* var, const sem::Variable* sem) {
- auto binding_point = *sem->As<sem::GlobalVariable>()->Attributes().binding_point;
- auto* type = sem->Type()->UnwrapRef();
- auto name = var->name->symbol.Name();
- Line() << "cbuffer cbuffer_" << name << RegisterAndSpace('b', binding_point) << " {";
-
- {
- ScopedIndent si(this);
- auto out = Line();
- if (!EmitTypeAndName(out, type, core::AddressSpace::kUniform, sem->Access(), name)) {
- return false;
- }
- out << ";";
- }
-
- Line() << "};";
-
- return true;
-}
-
-bool ASTPrinter::EmitStorageVariable(const ast::Var* var, const sem::Variable* sem) {
- auto* type = sem->Type()->UnwrapRef();
- auto out = Line();
- if (!EmitTypeAndName(out, type, core::AddressSpace::kStorage, sem->Access(),
- var->name->symbol.Name())) {
- return false;
- }
-
- auto* global_sem = sem->As<sem::GlobalVariable>();
- out << RegisterAndSpace(sem->Access() == core::Access::kRead ? 't' : 'u',
- *global_sem->Attributes().binding_point)
- << ";";
-
- return true;
-}
-
-bool ASTPrinter::EmitHandleVariable(const ast::Var* var, const sem::Variable* sem) {
- auto* unwrapped_type = sem->Type()->UnwrapRef();
- auto out = Line();
-
- auto name = var->name->symbol.Name();
- auto* type = sem->Type()->UnwrapRef();
- 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";
- }
- out << "RasterizerOrderedTexture2D";
- auto* component = ImageFormatToRWtextureType(storage->TexelFormat());
- if (DAWN_UNLIKELY(!component)) {
- TINT_ICE() << "Unsupported StorageTexture TexelFormat: "
- << static_cast<int>(storage->TexelFormat());
- }
- out << "<" << component << "> " << name;
- } else if (!EmitTypeAndName(out, type, sem->AddressSpace(), sem->Access(), name)) {
- return false;
- }
-
- const char* register_space = nullptr;
-
- if (unwrapped_type->Is<core::type::Texture>()) {
- register_space = "t";
- if (auto* st = unwrapped_type->As<core::type::StorageTexture>();
- st && st->Access() != core::Access::kRead) {
- register_space = "u";
- }
- } else if (unwrapped_type->Is<core::type::Sampler>()) {
- register_space = "s";
- }
-
- if (register_space) {
- auto bp = sem->As<sem::GlobalVariable>()->Attributes().binding_point;
- out << " : register(" << register_space << bp->binding;
- // Omit the space if it's 0, as it's the default.
- // SM 5.0 doesn't support spaces, so we don't emit them if group is 0 for better
- // compatibility.
- if (bp->group == 0) {
- out << ")";
- } else {
- out << ", space" << bp->group << ")";
- }
- }
-
- out << ";";
- return true;
-}
-
-bool ASTPrinter::EmitPrivateVariable(const sem::Variable* var) {
- auto* decl = var->Declaration();
- auto out = Line();
-
- out << "static ";
-
- auto name = decl->name->symbol.Name();
- auto* type = var->Type()->UnwrapRef();
- if (!EmitTypeAndName(out, type, var->AddressSpace(), var->Access(), name)) {
- return false;
- }
-
- out << " = ";
- if (auto* initializer = decl->initializer) {
- if (!EmitExpression(out, initializer)) {
- return false;
- }
- } else {
- if (!EmitZeroValue(out, var->Type()->UnwrapRef())) {
- return false;
- }
- }
-
- out << ";";
- return true;
-}
-
-bool ASTPrinter::EmitWorkgroupVariable(const sem::Variable* var) {
- auto* decl = var->Declaration();
- auto out = Line();
-
- out << "groupshared ";
-
- auto name = decl->name->symbol.Name();
- auto* type = var->Type()->UnwrapRef();
- if (!EmitTypeAndName(out, type, var->AddressSpace(), var->Access(), name)) {
- return false;
- }
-
- if (auto* initializer = decl->initializer) {
- out << " = ";
- if (!EmitExpression(out, initializer)) {
- return false;
- }
- }
-
- out << ";";
- return true;
-}
-
-std::string ASTPrinter::builtin_to_attribute(core::BuiltinValue builtin) const {
- switch (builtin) {
- case core::BuiltinValue::kPosition:
- return "SV_Position";
- case core::BuiltinValue::kVertexIndex:
- return "SV_VertexID";
- case core::BuiltinValue::kInstanceIndex:
- return "SV_InstanceID";
- case core::BuiltinValue::kFrontFacing:
- return "SV_IsFrontFace";
- case core::BuiltinValue::kFragDepth:
- return "SV_Depth";
- case core::BuiltinValue::kLocalInvocationId:
- return "SV_GroupThreadID";
- case core::BuiltinValue::kLocalInvocationIndex:
- return "SV_GroupIndex";
- case core::BuiltinValue::kGlobalInvocationId:
- return "SV_DispatchThreadID";
- case core::BuiltinValue::kWorkgroupId:
- return "SV_GroupID";
- case core::BuiltinValue::kSampleIndex:
- return "SV_SampleIndex";
- case core::BuiltinValue::kSampleMask:
- return "SV_Coverage";
- case core::BuiltinValue::kClipDistances:
- return "SV_ClipDistance0";
- default:
- break;
- }
- return "";
-}
-
-std::string ASTPrinter::interpolation_to_modifiers(core::InterpolationType type,
- core::InterpolationSampling sampling) const {
- std::string modifiers;
- switch (type) {
- case core::InterpolationType::kPerspective:
- modifiers += "linear ";
- break;
- case core::InterpolationType::kLinear:
- modifiers += "noperspective ";
- break;
- case core::InterpolationType::kFlat:
- modifiers += "nointerpolation ";
- break;
- case core::InterpolationType::kUndefined:
- break;
- }
- switch (sampling) {
- case core::InterpolationSampling::kCentroid:
- modifiers += "centroid ";
- break;
- case core::InterpolationSampling::kSample:
- modifiers += "sample ";
- break;
- case core::InterpolationSampling::kCenter:
- case core::InterpolationSampling::kFirst:
- case core::InterpolationSampling::kEither:
- case core::InterpolationSampling::kUndefined:
- break;
- }
- return modifiers;
-}
-
-bool ASTPrinter::EmitEntryPointFunction(const ast::Function* func) {
- auto* func_sem = builder_.Sem().Get(func);
-
- {
- auto out = Line();
- if (func->PipelineStage() == ast::PipelineStage::kCompute) {
- // Emit the workgroup_size attribute.
- auto wgsize = func_sem->WorkgroupSize();
- out << "[numthreads(";
- for (size_t i = 0; i < 3; i++) {
- if (i > 0) {
- out << ", ";
- }
- if (!wgsize[i].has_value()) {
- diagnostics_.AddError(Source{})
- << "override-expressions should have been removed with the "
- "SubstituteOverride transform";
- return false;
- }
- out << std::to_string(wgsize[i].value());
- }
- out << ")]\n";
- }
-
- if (!EmitTypeAndName(out, func_sem->ReturnType(), core::AddressSpace::kUndefined,
- core::Access::kUndefined, func->name->symbol.Name())) {
- return false;
- }
- out << "(";
-
- bool first = true;
-
- // Emit entry point parameters.
- for (auto* var : func->params) {
- auto* sem = builder_.Sem().Get(var);
- auto* type = sem->Type();
- if (DAWN_UNLIKELY(!type->Is<core::type::Struct>())) {
- // ICE likely indicates that the CanonicalizeEntryPointIO transform was
- // not run, or a builtin parameter was added after it was run.
- TINT_ICE() << "Unsupported non-struct entry point parameter";
- }
-
- if (!first) {
- out << ", ";
- }
- first = false;
-
- if (!EmitTypeAndName(out, type, sem->AddressSpace(), sem->Access(),
- var->name->symbol.Name())) {
- return false;
- }
- }
-
- out << ") {";
- }
-
- {
- ScopedIndent si(this);
-
- if (!EmitStatements(func->body->statements)) {
- return false;
- }
-
- if (!Is<ast::ReturnStatement>(func->body->Last())) {
- ast::ReturnStatement ret(GenerationID(), ast::NodeID{}, Source{});
- if (!EmitStatement(&ret)) {
- return false;
- }
- }
- }
-
- Line() << "}";
-
- return true;
-}
-
-bool ASTPrinter::EmitConstant(StringStream& out,
- const core::constant::Value* constant,
- bool is_variable_initializer) {
- return Switch(
- constant->Type(), //
- [&](const core::type::Bool*) {
- out << (constant->ValueAs<AInt>() ? "true" : "false");
- return true;
- },
- [&](const core::type::F32*) {
- PrintF32(out, constant->ValueAs<f32>());
- return true;
- },
- [&](const core::type::F16*) {
- // emit a f16 scalar with explicit float16_t type declaration.
- out << "float16_t(";
- PrintF16(out, constant->ValueAs<f16>());
- out << ")";
- return true;
- },
- [&](const core::type::I32*) {
- out << constant->ValueAs<AInt>();
- return true;
- },
- [&](const core::type::U32*) {
- out << constant->ValueAs<AInt>() << "u";
- return true;
- },
- [&](const core::type::Vector* v) {
- if (auto* splat = constant->As<core::constant::Splat>()) {
- {
- ScopedParen sp(out);
- if (!EmitConstant(out, splat->el, is_variable_initializer)) {
- return false;
- }
- }
- out << ".";
- for (size_t i = 0; i < v->Width(); i++) {
- out << "x";
- }
- return true;
- }
-
- if (!EmitType(out, v, core::AddressSpace::kUndefined, core::Access::kUndefined, "")) {
- return false;
- }
-
- ScopedParen sp(out);
-
- for (size_t i = 0; i < v->Width(); i++) {
- if (i > 0) {
- out << ", ";
- }
- if (!EmitConstant(out, constant->Index(i), is_variable_initializer)) {
- return false;
- }
- }
- return true;
- },
- [&](const core::type::Matrix* m) {
- if (!EmitType(out, m, core::AddressSpace::kUndefined, core::Access::kUndefined, "")) {
- return false;
- }
-
- ScopedParen sp(out);
-
- for (size_t i = 0; i < m->Columns(); i++) {
- if (i > 0) {
- out << ", ";
- }
- if (!EmitConstant(out, constant->Index(i), is_variable_initializer)) {
- return false;
- }
- }
- return true;
- },
- [&](const core::type::Array* a) {
- if (constant->AllZero()) {
- out << "(";
- if (!EmitType(out, a, core::AddressSpace::kUndefined, core::Access::kUndefined,
- "")) {
- return false;
- }
- out << ")0";
- return true;
- }
-
- out << "{";
- TINT_DEFER(out << "}");
-
- auto count = a->ConstantCount();
- if (!count) {
- diagnostics_.AddError(Source{}) << core::type::Array::kErrExpectedConstantCount;
- return false;
- }
-
- for (size_t i = 0; i < count; i++) {
- if (i > 0) {
- out << ", ";
- }
- if (!EmitConstant(out, constant->Index(i), is_variable_initializer)) {
- return false;
- }
- }
-
- return true;
- },
- [&](const core::type::Struct* s) {
- if (!EmitStructType(&helpers_, s)) {
- return false;
- }
-
- if (constant->AllZero()) {
- out << "(" << StructName(s) << ")0";
- return true;
- }
-
- auto emit_member_values = [&](StringStream& o) {
- o << "{";
- for (size_t i = 0; i < s->Members().Length(); i++) {
- if (i > 0) {
- o << ", ";
- }
- if (!EmitConstant(o, constant->Index(i), is_variable_initializer)) {
- return false;
- }
- }
- o << "}";
- return true;
- };
-
- if (is_variable_initializer) {
- if (!emit_member_values(out)) {
- return false;
- }
- } else {
- // HLSL requires structure initializers to be assigned directly to a variable.
- // For these constants use 'static const' at global-scope. 'const' at global scope
- // creates a variable who's initializer is ignored, and the value is expected to be
- // provided in a cbuffer. 'static const' is a true value-embedded-in-the-shader-code
- // constant. We also emit these for function-local constant expressions for
- // consistency and to ensure that these are not computed at execution time.
- auto name = UniqueIdentifier("c");
- {
- StringStream decl;
- decl << "static const " << StructName(s) << " " << name << " = ";
- if (!emit_member_values(decl)) {
- return false;
- }
- decl << ";";
- current_buffer_->Insert(decl.str(), global_insertion_point_++, 0);
- }
- out << name;
- }
-
- return true;
- }, //
- TINT_ICE_ON_NO_MATCH);
-}
-
-bool ASTPrinter::EmitLiteral(StringStream& out, const ast::LiteralExpression* lit) {
- return Switch(
- lit,
- [&](const ast::BoolLiteralExpression* l) {
- out << (l->value ? "true" : "false");
- return true;
- },
- [&](const ast::FloatLiteralExpression* l) {
- if (l->suffix == ast::FloatLiteralExpression::Suffix::kH) {
- // Emit f16 literal with explicit float16_t type declaration.
- out << "float16_t(";
- PrintF16(out, static_cast<float>(l->value));
- out << ")";
- }
- PrintF32(out, static_cast<float>(l->value));
- return true;
- },
- [&](const ast::IntLiteralExpression* i) {
- out << i->value;
- switch (i->suffix) {
- case ast::IntLiteralExpression::Suffix::kNone:
- case ast::IntLiteralExpression::Suffix::kI:
- return true;
- case ast::IntLiteralExpression::Suffix::kU:
- out << "u";
- return true;
- }
- diagnostics_.AddError(Source{}) << "unknown integer literal suffix type";
- return false;
- }, //
- TINT_ICE_ON_NO_MATCH);
-}
-
-bool ASTPrinter::EmitValue(StringStream& out, const core::type::Type* type, int value) {
- return Switch(
- type,
- [&](const core::type::Bool*) {
- out << (value == 0 ? "false" : "true");
- return true;
- },
- [&](const core::type::F32*) {
- out << value << ".0f";
- return true;
- },
- [&](const core::type::F16*) {
- out << "float16_t(" << value << ".0h)";
- return true;
- },
- [&](const core::type::I32*) {
- out << value;
- return true;
- },
- [&](const core::type::U32*) {
- out << value << "u";
- return true;
- },
- [&](const core::type::Vector* vec) {
- if (!EmitType(out, type, core::AddressSpace::kUndefined, core::Access::kReadWrite,
- "")) {
- return false;
- }
- ScopedParen sp(out);
- for (uint32_t i = 0; i < vec->Width(); i++) {
- if (i != 0) {
- out << ", ";
- }
- if (!EmitValue(out, vec->Type(), value)) {
- return false;
- }
- }
- return true;
- },
- [&](const core::type::Matrix* mat) {
- if (!EmitType(out, type, core::AddressSpace::kUndefined, core::Access::kReadWrite,
- "")) {
- return false;
- }
- ScopedParen sp(out);
- for (uint32_t i = 0; i < (mat->Rows() * mat->Columns()); i++) {
- if (i != 0) {
- out << ", ";
- }
- if (!EmitValue(out, mat->Type(), value)) {
- return false;
- }
- }
- return true;
- },
- [&](const core::type::Struct*) {
- out << "(";
- TINT_DEFER(out << ")" << value);
- return EmitType(out, type, core::AddressSpace::kUndefined, core::Access::kUndefined,
- "");
- },
- [&](const core::type::Array*) {
- out << "(";
- TINT_DEFER(out << ")" << value);
- return EmitType(out, type, core::AddressSpace::kUndefined, core::Access::kUndefined,
- "");
- }, //
- TINT_ICE_ON_NO_MATCH);
-}
-
-bool ASTPrinter::EmitZeroValue(StringStream& out, const core::type::Type* type) {
- return EmitValue(out, type, 0);
-}
-
-bool ASTPrinter::EmitLoop(const ast::LoopStatement* stmt) {
- auto emit_continuing = [this, stmt] {
- if (stmt->continuing && !stmt->continuing->Empty()) {
- if (!EmitBlock(stmt->continuing)) {
- return false;
- }
- }
- return true;
- };
-
- TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
- Line() << "while (true) {";
- {
- ScopedIndent si(this);
- if (!EmitStatements(stmt->body->statements)) {
- return false;
- }
- if (!emit_continuing_()) {
- return false;
- }
- }
- Line() << "}";
-
- return true;
-}
-
-bool ASTPrinter::EmitForLoop(const ast::ForLoopStatement* stmt) {
- // Nest a for loop with a new block. In HLSL the initializer scope is not
- // nested by the for-loop, so we may get variable redefinitions.
- Line() << "{";
- IncrementIndent();
- TINT_DEFER({
- DecrementIndent();
- Line() << "}";
- });
-
- TextBuffer init_buf;
- if (auto* init = stmt->initializer) {
- TINT_SCOPED_ASSIGNMENT(current_buffer_, &init_buf);
- if (!EmitStatement(init)) {
- return false;
- }
- }
-
- TextBuffer cond_pre;
- StringStream cond_buf;
- if (auto* cond = stmt->condition) {
- TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
- if (!EmitExpression(cond_buf, cond)) {
- return false;
- }
- }
-
- TextBuffer cont_buf;
- if (auto* cont = stmt->continuing) {
- TINT_SCOPED_ASSIGNMENT(current_buffer_, &cont_buf);
- if (!EmitStatement(cont)) {
- return false;
- }
- }
-
- // If the for-loop has a multi-statement conditional and / or continuing, then
- // we cannot emit this as a regular for-loop in HLSL. Instead we need to
- // generate a `while(true)` loop.
- bool emit_as_loop = cond_pre.lines.size() > 0 || cont_buf.lines.size() > 1;
-
- // If the for-loop has multi-statement initializer, or is going to be emitted
- // as a `while(true)` loop, then declare the initializer statement(s) before
- // the loop.
- if (init_buf.lines.size() > 1 || (stmt->initializer && emit_as_loop)) {
- current_buffer_->Append(init_buf);
- init_buf.lines.clear(); // Don't emit the initializer again in the 'for'
- }
-
- if (emit_as_loop) {
- auto emit_continuing = [&] {
- current_buffer_->Append(cont_buf);
- return true;
- };
-
- TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
- Line() << "while (true) {";
- IncrementIndent();
- TINT_DEFER({
- DecrementIndent();
- Line() << "}";
- });
-
- if (stmt->condition) {
- current_buffer_->Append(cond_pre);
- Line() << "if (!(" << cond_buf.str() << ")) { break; }";
- }
-
- if (!EmitStatements(stmt->body->statements)) {
- return false;
- }
-
- if (!emit_continuing_()) {
- return false;
- }
- } else {
- // For-loop can be generated.
- {
- auto out = Line();
- out << "for";
- {
- ScopedParen sp(out);
-
- if (!init_buf.lines.empty()) {
- out << init_buf.lines[0].content << " ";
- } else {
- out << "; ";
- }
-
- out << cond_buf.str() << "; ";
-
- if (!cont_buf.lines.empty()) {
- out << tint::TrimSuffix(cont_buf.lines[0].content, ";");
- }
- }
- out << " {";
- }
- {
- auto emit_continuing = [] { return true; };
- TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
- if (!EmitStatementsWithIndent(stmt->body->statements)) {
- return false;
- }
- }
- Line() << "}";
- }
-
- return true;
-}
-
-bool ASTPrinter::EmitWhile(const ast::WhileStatement* stmt) {
- TextBuffer cond_pre;
- StringStream cond_buf;
- {
- auto* cond = stmt->condition;
- TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
- if (!EmitExpression(cond_buf, cond)) {
- return false;
- }
- }
-
- auto emit_continuing = [&] { return true; };
- TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
-
- // If the while has a multi-statement conditional, then we cannot emit this
- // as a regular while in HLSL. Instead we need to generate a `while(true)` loop.
- bool emit_as_loop = cond_pre.lines.size() > 0;
- if (emit_as_loop) {
- Line() << "while (true) {";
- IncrementIndent();
- TINT_DEFER({
- DecrementIndent();
- Line() << "}";
- });
-
- current_buffer_->Append(cond_pre);
- Line() << "if (!(" << cond_buf.str() << ")) { break; }";
- if (!EmitStatements(stmt->body->statements)) {
- return false;
- }
- } else {
- // While can be generated.
- {
- auto out = Line();
- out << "while";
- {
- ScopedParen sp(out);
- out << cond_buf.str();
- }
- out << " {";
- }
- if (!EmitStatementsWithIndent(stmt->body->statements)) {
- return false;
- }
- Line() << "}";
- }
-
- return true;
-}
-
-bool ASTPrinter::EmitMemberAccessor(StringStream& out, const ast::MemberAccessorExpression* expr) {
- if (!EmitExpression(out, expr->object)) {
- return false;
- }
- out << ".";
-
- auto* sem = builder_.Sem().Get(expr)->UnwrapLoad();
-
- return Switch(
- sem,
- [&](const sem::Swizzle*) {
- // Swizzles output the name directly
- out << expr->member->symbol.Name();
- return true;
- },
- [&](const sem::StructMemberAccess* member_access) {
- out << member_access->Member()->Name().Name();
- return true;
- }, //
- TINT_ICE_ON_NO_MATCH);
-}
-
-bool ASTPrinter::EmitReturn(const ast::ReturnStatement* stmt) {
- if (stmt->value) {
- auto out = Line();
- out << "return ";
- if (!EmitExpression(out, stmt->value)) {
- return false;
- }
- out << ";";
- } else {
- Line() << "return;";
- }
- return true;
-}
-
-bool ASTPrinter::EmitStatement(const ast::Statement* stmt) {
- return Switch(
- stmt,
- [&](const ast::AssignmentStatement* a) { //
- return EmitAssign(a);
- },
- [&](const ast::BlockStatement* b) { //
- return EmitBlock(b);
- },
- [&](const ast::BreakStatement* b) { //
- return EmitBreak(b);
- },
- [&](const ast::BreakIfStatement* b) { //
- return EmitBreakIf(b);
- },
- [&](const ast::CallStatement* c) { //
- auto out = Line();
- if (!EmitCall(out, c->expr)) {
- return false;
- }
- out << ";";
- return true;
- },
- [&](const ast::ContinueStatement* c) { //
- return EmitContinue(c);
- },
- [&](const ast::DiscardStatement* d) { //
- return EmitDiscard(d);
- },
- [&](const ast::IfStatement* i) { //
- return EmitIf(i);
- },
- [&](const ast::LoopStatement* l) { //
- return EmitLoop(l);
- },
- [&](const ast::ForLoopStatement* l) { //
- return EmitForLoop(l);
- },
- [&](const ast::WhileStatement* l) { //
- return EmitWhile(l);
- },
- [&](const ast::ReturnStatement* r) { //
- return EmitReturn(r);
- },
- [&](const ast::SwitchStatement* s) { //
- return EmitSwitch(s);
- },
- [&](const ast::VariableDeclStatement* v) { //
- return Switch(
- v->variable, //
- [&](const ast::Var* var) { return EmitVar(var); },
- [&](const ast::Let* let) { return EmitLet(let); },
- [&](const ast::Const*) {
- return true; // Constants are embedded at their use
- }, //
- TINT_ICE_ON_NO_MATCH);
- },
- [&](const ast::ConstAssert*) {
- return true; // Not emitted
- }, //
- TINT_ICE_ON_NO_MATCH);
-}
-
-bool ASTPrinter::EmitDefaultOnlySwitch(const ast::SwitchStatement* stmt) {
- TINT_ASSERT(stmt->body.Length() == 1 && stmt->body[0]->ContainsDefault());
-
- // FXC fails to compile a switch with just a default case, ignoring the
- // default case body. We work around this here by emitting the default case
- // without the switch.
-
- // Emit the switch condition as-is if it has side-effects (e.g.
- // function call). Note that we can ignore the result of the expression (if any).
- if (auto* sem_cond = builder_.Sem().GetVal(stmt->condition); sem_cond->HasSideEffects()) {
- auto out = Line();
- if (!EmitExpression(out, stmt->condition)) {
- return false;
- }
- out << ";";
- }
-
- // Emit "do { <default case body> } while(false);". We use a 'do' loop so
- // that break statements work as expected, and make it 'while (false)' in
- // case there isn't a break statement.
- Line() << "do {";
- {
- ScopedIndent si(this);
- if (!EmitStatements(stmt->body[0]->body->statements)) {
- return false;
- }
- }
- Line() << "} while (false);";
- return true;
-}
-
-bool ASTPrinter::EmitSwitch(const ast::SwitchStatement* stmt) {
- // BUG(crbug.com/tint/1188): work around default-only switches
- if (stmt->body.Length() == 1 && stmt->body[0]->selectors.Length() == 1 &&
- stmt->body[0]->ContainsDefault()) {
- return EmitDefaultOnlySwitch(stmt);
- }
-
- { // switch(expr) {
- auto out = Line();
- out << "switch(";
- if (!EmitExpression(out, stmt->condition)) {
- return false;
- }
- out << ") {";
- }
-
- {
- ScopedIndent si(this);
- for (size_t i = 0; i < stmt->body.Length(); i++) {
- if (!EmitCase(stmt, i)) {
- return false;
- }
- }
- }
-
- Line() << "}";
-
- return true;
-}
-
-bool ASTPrinter::EmitType(StringStream& out,
- const core::type::Type* type,
- core::AddressSpace address_space,
- core::Access access,
- const std::string& name,
- bool* name_printed /* = nullptr */) {
- if (name_printed) {
- *name_printed = false;
- }
- switch (address_space) {
- case core::AddressSpace::kStorage:
- if (access != core::Access::kRead) {
- out << "RW";
- }
- out << "ByteAddressBuffer";
- return true;
- case core::AddressSpace::kUniform: {
- auto array_length = (type->Size() + 15) / 16;
- out << "uint4 " << name << "[" << array_length << "]";
- if (name_printed) {
- *name_printed = true;
- }
- return true;
- }
- default:
- break;
- }
-
- return Switch(
- type,
- [&](const core::type::Array* ary) {
- const core::type::Type* base_type = ary;
- std::vector<uint32_t> sizes;
- while (auto* arr = base_type->As<core::type::Array>()) {
- if (DAWN_UNLIKELY(arr->Count()->Is<core::type::RuntimeArrayCount>())) {
- TINT_ICE()
- << "runtime arrays may only exist in storage buffers, which should have "
- "been transformed into a ByteAddressBuffer";
- }
- const auto count = arr->ConstantCount();
- if (!count) {
- diagnostics_.AddError(Source{}) << core::type::Array::kErrExpectedConstantCount;
- return false;
- }
-
- sizes.push_back(count.value());
- base_type = arr->ElemType();
- }
- if (!EmitType(out, base_type, address_space, access, "")) {
- return false;
- }
- if (!name.empty()) {
- out << " " << name;
- if (name_printed) {
- *name_printed = true;
- }
- }
- for (uint32_t size : sizes) {
- out << "[" << size << "]";
- }
- return true;
- },
- [&](const core::type::Bool*) {
- out << "bool";
- return true;
- },
- [&](const core::type::F32*) {
- out << "float";
- return true;
- },
- [&](const core::type::F16*) {
- out << "float16_t";
- return true;
- },
- [&](const core::type::I32*) {
- out << "int";
- return true;
- },
- [&](const core::type::Matrix* mat) {
- if (mat->Type()->Is<core::type::F16>()) {
- // Use matrix<type, N, M> for f16 matrix
- out << "matrix<";
- if (!EmitType(out, mat->Type(), address_space, access, "")) {
- return false;
- }
- out << ", " << mat->Columns() << ", " << mat->Rows() << ">";
- return true;
- }
- if (!EmitType(out, mat->Type(), address_space, access, "")) {
- return false;
- }
- // Note: HLSL's matrices are declared as <type>NxM, where N is the
- // number of rows and M is the number of columns. Despite HLSL's
- // matrices being column-major by default, the index operator and
- // initializers actually operate on row-vectors, where as WGSL operates
- // on column vectors. To simplify everything we use the transpose of the
- // matrices. See:
- // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-per-component-math#matrix-ordering
- out << mat->Columns() << "x" << mat->Rows();
- return true;
- },
- [&](const core::type::Pointer*) -> bool {
- TINT_ICE() << "Attempting to emit pointer type. These should have been removed with "
- "the SimplifyPointers transform";
- },
- [&](const core::type::Sampler* sampler) {
- out << "Sampler";
- if (sampler->IsComparison()) {
- out << "Comparison";
- }
- out << "State";
- return true;
- },
- [&](const core::type::Struct* str) {
- out << StructName(str);
- return true;
- },
- [&](const core::type::Texture* tex) {
- if (DAWN_UNLIKELY(tex->Is<core::type::ExternalTexture>())) {
- TINT_ICE() << "Multiplanar external texture transform was not run.";
- }
-
- auto* storage = tex->As<core::type::StorageTexture>();
- auto* ms = tex->As<core::type::MultisampledTexture>();
- auto* depth_ms = tex->As<core::type::DepthMultisampledTexture>();
- auto* sampled = tex->As<core::type::SampledTexture>();
-
- if (storage && storage->Access() != core::Access::kRead) {
- out << "RW";
- }
- out << "Texture";
-
- switch (tex->Dim()) {
- case core::type::TextureDimension::k1d:
- out << "1D";
- break;
- case core::type::TextureDimension::k2d:
- out << ((ms || depth_ms) ? "2DMS" : "2D");
- break;
- case core::type::TextureDimension::k2dArray:
- out << ((ms || depth_ms) ? "2DMSArray" : "2DArray");
- break;
- case core::type::TextureDimension::k3d:
- out << "3D";
- break;
- case core::type::TextureDimension::kCube:
- out << "Cube";
- break;
- case core::type::TextureDimension::kCubeArray:
- out << "CubeArray";
- break;
- default:
- TINT_UNREACHABLE() << "unexpected TextureDimension " << tex->Dim();
- }
-
- if (storage) {
- auto* component = ImageFormatToRWtextureType(storage->TexelFormat());
- if (DAWN_UNLIKELY(!component)) {
- TINT_ICE() << "Unsupported StorageTexture TexelFormat: "
- << static_cast<int>(storage->TexelFormat());
- }
- out << "<" << component << ">";
- } else if (depth_ms) {
- out << "<float4>";
- } else if (sampled || ms) {
- auto* subtype = sampled ? sampled->Type() : ms->Type();
- out << "<";
- if (subtype->Is<core::type::F32>()) {
- out << "float4";
- } else if (subtype->Is<core::type::I32>()) {
- out << "int4";
- } else if (DAWN_LIKELY(subtype->Is<core::type::U32>())) {
- out << "uint4";
- } else {
- TINT_ICE() << "Unsupported multisampled texture type";
- }
- out << ">";
- }
- return true;
- },
- [&](const core::type::U32*) {
- out << "uint";
- return true;
- },
- [&](const core::type::Vector* vec) {
- auto width = vec->Width();
- if (vec->Type()->Is<core::type::F32>() && width >= 1 && width <= 4) {
- out << "float" << width;
- } else if (vec->Type()->Is<core::type::I32>() && width >= 1 && width <= 4) {
- out << "int" << width;
- } else if (vec->Type()->Is<core::type::U32>() && width >= 1 && width <= 4) {
- out << "uint" << width;
- } else if (vec->Type()->Is<core::type::Bool>() && width >= 1 && width <= 4) {
- out << "bool" << width;
- } else {
- // For example, use "vector<float16_t, N>" for f16 vector.
- out << "vector<";
- if (!EmitType(out, vec->Type(), address_space, access, "")) {
- return false;
- }
- out << ", " << width << ">";
- }
- return true;
- },
- [&](const core::type::Atomic* atomic) {
- return EmitType(out, atomic->Type(), address_space, access, name);
- },
- [&](const core::type::Void*) {
- out << "void";
- return true;
- }, //
- TINT_ICE_ON_NO_MATCH);
-}
-
-bool ASTPrinter::EmitTypeAndName(StringStream& out,
- const core::type::Type* type,
- core::AddressSpace address_space,
- core::Access access,
- const std::string& name) {
- bool name_printed = false;
- if (!EmitType(out, type, address_space, access, name, &name_printed)) {
- return false;
- }
- if (!name.empty() && !name_printed) {
- out << " " << name;
- }
- return true;
-}
-
-bool ASTPrinter::EmitStructType(TextBuffer* b,
- const core::type::Struct* str,
- VectorRef<const ast::StructMember*> ast_struct_members) {
- auto it = emitted_structs_.emplace(str);
- if (!it.second) {
- return true;
- }
-
- const auto struct_type_members = str->Members();
- size_t struct_type_member_length = struct_type_members.Length();
- TINT_ASSERT(ast_struct_members.IsEmpty() ||
- (struct_type_member_length == ast_struct_members.Length()));
-
- Line(b) << "struct " << StructName(str) << " {";
- {
- ScopedIndent si(b);
- for (size_t i = 0; i < struct_type_member_length; ++i) {
- auto* mem = struct_type_members[i];
- auto mem_name = mem->Name().Name();
- auto* ty = mem->Type();
- auto out = Line(b);
- std::string pre, post;
-
- auto& attributes = mem->Attributes();
-
- if (auto location = attributes.location) {
- auto& pipeline_stage_uses = str->PipelineStageUses();
- if (DAWN_UNLIKELY(pipeline_stage_uses.Count() != 1)) {
- TINT_ICE() << "invalid entry point IO struct uses";
- }
- if (pipeline_stage_uses.Contains(core::type::PipelineStageUsage::kVertexInput)) {
- post += " : TEXCOORD" + std::to_string(location.value());
- } else if (pipeline_stage_uses.Contains(
- core::type::PipelineStageUsage::kVertexOutput)) {
- post += " : TEXCOORD" + std::to_string(location.value());
- } else if (pipeline_stage_uses.Contains(
- core::type::PipelineStageUsage::kFragmentInput)) {
- post += " : TEXCOORD" + std::to_string(location.value());
- } else if (DAWN_LIKELY(pipeline_stage_uses.Contains(
- core::type::PipelineStageUsage::kFragmentOutput))) {
- if (auto blend_src = attributes.blend_src) {
- post +=
- " : SV_Target" + std::to_string(location.value() + blend_src.value());
- } else {
- post += " : SV_Target" + std::to_string(location.value());
- }
-
- } else {
- TINT_ICE() << "invalid use of location attribute";
- }
- }
- if (auto builtin = attributes.builtin) {
- auto name = builtin_to_attribute(builtin.value());
- if (name.empty()) {
- diagnostics_.AddError(Source{}) << "unsupported builtin";
- return false;
- }
- post += " : " + name;
- }
- if (auto interpolation = attributes.interpolation) {
- auto mod = interpolation_to_modifiers(interpolation->type, interpolation->sampling);
- if (mod.empty()) {
- diagnostics_.AddError(Source{}) << "unsupported interpolation";
- return false;
- }
- pre += mod;
- }
- if (attributes.invariant) {
- // Note: `precise` is not exactly the same as `invariant`, but is
- // stricter and therefore provides the necessary guarantees.
- // See discussion here: https://github.com/gpuweb/gpuweb/issues/893
- pre += "precise ";
- }
- if (!ast_struct_members.IsEmpty() &&
- ast::HasAttribute<ast::transform::CanonicalizeEntryPointIO::HLSLClipDistance1>(
- ast_struct_members[i]->attributes)) {
- post += " : SV_ClipDistance1";
- }
-
- out << pre;
- if (!EmitTypeAndName(out, ty, core::AddressSpace::kUndefined, core::Access::kReadWrite,
- mem_name)) {
- return false;
- }
- out << post << ";";
- }
- }
-
- Line(b) << "};";
- return true;
-}
-
-bool ASTPrinter::EmitUnaryOp(StringStream& out, const ast::UnaryOpExpression* expr) {
- switch (expr->op) {
- case core::UnaryOp::kIndirection:
- case core::UnaryOp::kAddressOf:
- return EmitExpression(out, expr->expr);
- case core::UnaryOp::kComplement:
- out << "~";
- break;
- case core::UnaryOp::kNot:
- out << "!";
- break;
- case core::UnaryOp::kNegation:
- out << "-";
- break;
- }
- out << "(";
-
- if (!EmitExpression(out, expr->expr)) {
- return false;
- }
-
- out << ")";
-
- return true;
-}
-
-bool ASTPrinter::EmitVar(const ast::Var* var) {
- auto* sem = builder_.Sem().Get(var);
- auto* type = sem->Type()->UnwrapRef();
-
- auto out = Line();
- if (!EmitTypeAndName(out, type, sem->AddressSpace(), sem->Access(), var->name->symbol.Name())) {
- return false;
- }
-
- out << " = ";
-
- if (var->initializer) {
- if (!EmitExpression(out, var->initializer)) {
- return false;
- }
- } else {
- if (!EmitZeroValue(out, type)) {
- return false;
- }
- }
- out << ";";
-
- return true;
-}
-
-bool ASTPrinter::EmitLet(const ast::Let* let) {
- auto* sem = builder_.Sem().Get(let);
- auto* type = sem->Type()->UnwrapRef();
-
- auto out = Line();
- if (!EmitTypeAndName(out, type, core::AddressSpace::kUndefined, core::Access::kUndefined,
- let->name->symbol.Name())) {
- return false;
- }
- out << " = ";
- if (!EmitExpression(out, let->initializer)) {
- return false;
- }
- out << ";";
-
- return true;
-}
-
-template <typename F>
-bool ASTPrinter::CallBuiltinHelper(StringStream& out,
- const ast::CallExpression* call,
- const sem::BuiltinFn* builtin,
- F&& build) {
- // Generate the helper function if it hasn't been created already
- auto fn = tint::GetOrAdd(builtins_, builtin, [&]() -> std::string {
- TextBuffer b;
- TINT_DEFER(helpers_.Append(b));
-
- auto fn_name = UniqueIdentifier(std::string("tint_") + wgsl::str(builtin->Fn()));
- std::vector<std::string> parameter_names;
- {
- auto decl = Line(&b);
- if (!EmitTypeAndName(decl, builtin->ReturnType(), core::AddressSpace::kUndefined,
- core::Access::kUndefined, fn_name)) {
- return "";
- }
- {
- ScopedParen sp(decl);
- for (auto* param : builtin->Parameters()) {
- if (!parameter_names.empty()) {
- decl << ", ";
- }
- auto param_name = "param_" + std::to_string(parameter_names.size());
- const auto* ty = param->Type();
- if (auto* ptr = ty->As<core::type::Pointer>()) {
- decl << "inout ";
- ty = ptr->StoreType();
- }
- if (!EmitTypeAndName(decl, ty, core::AddressSpace::kUndefined,
- core::Access::kUndefined, param_name)) {
- return "";
- }
- parameter_names.emplace_back(std::move(param_name));
- }
- }
- decl << " {";
- }
- {
- ScopedIndent si(&b);
- if (!build(&b, parameter_names)) {
- return "";
- }
- }
- Line(&b) << "}";
- Line(&b);
- return fn_name;
- });
-
- if (fn.empty()) {
- return false;
- }
-
- // Call the helper
- out << fn;
- {
- ScopedParen sp(out);
- bool first = true;
- for (auto* arg : call->args) {
- if (!first) {
- out << ", ";
- }
- first = false;
- if (!EmitExpression(out, arg)) {
- return false;
- }
- }
- }
- return true;
-}
-
-std::string ASTPrinter::StructName(const core::type::Struct* s) {
- auto name = s->Name().Name();
- if (HasPrefix(name, "__")) {
- name = tint::GetOrAdd(builtin_struct_names_, s,
- [&] { return UniqueIdentifier(name.substr(2)); });
- }
- return name;
-}
-
-std::string ASTPrinter::UniqueIdentifier(const std::string& prefix /* = "" */) {
- return builder_.Symbols().New(prefix).Name();
-}
-
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.h b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.h
deleted file mode 100644
index 77aa614..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.h
+++ /dev/null
@@ -1,638 +0,0 @@
-// Copyright 2020 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_LANG_HLSL_WRITER_AST_PRINTER_AST_PRINTER_H_
-#define SRC_TINT_LANG_HLSL_WRITER_AST_PRINTER_AST_PRINTER_H_
-
-#include <string>
-#include <tuple>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-
-#include "src/tint/api/common/binding_point.h"
-#include "src/tint/lang/core/builtin_value.h"
-#include "src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.h"
-#include "src/tint/lang/hlsl/writer/common/options.h"
-#include "src/tint/lang/wgsl/program/program_builder.h"
-#include "src/tint/utils/containers/scope_stack.h"
-#include "src/tint/utils/math/hash.h"
-#include "src/tint/utils/text_generator/text_generator.h"
-
-// Forward declarations
-namespace tint::sem {
-class BuiltinFn;
-class Call;
-class ValueConstructor;
-class ValueConversion;
-} // namespace tint::sem
-
-namespace tint::hlsl::writer {
-
-/// The result of sanitizing a program for generation.
-struct SanitizedResult {
- /// Constructor
- SanitizedResult();
- /// Destructor
- ~SanitizedResult();
- /// Move constructor
- SanitizedResult(SanitizedResult&&);
-
- /// The sanitized program.
- Program program;
- /// Indices into the array_length_from_uniform binding that are statically
- /// used.
- std::unordered_set<uint32_t> used_array_length_from_uniform_indices;
-};
-
-/// Sanitize a program in preparation for generating HLSL.
-/// @param program the input program
-/// @param options The HLSL generator options.
-/// @returns the sanitized program and any supplementary information
-SanitizedResult Sanitize(const Program& program, const Options& options);
-
-/// Implementation class for HLSL generator
-class ASTPrinter : public tint::TextGenerator {
- public:
- /// Constructor
- /// @param program the program to generate
- explicit ASTPrinter(const Program& program);
- ~ASTPrinter() override;
-
- /// @returns true on successful generation; false otherwise
- bool Generate();
-
- /// Handles an index accessor expression
- /// @param out the output stream
- /// @param expr the expression to emit
- /// @returns true if the index accessor was emitted
- bool EmitIndexAccessor(StringStream& out, const ast::IndexAccessorExpression* expr);
- /// Handles an assignment statement
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted successfully
- bool EmitAssign(const ast::AssignmentStatement* stmt);
- /// Handles generating a binary expression
- /// @param out the output stream
- /// @param expr the binary expression
- /// @returns true if the expression was emitted, false otherwise
- bool EmitBinary(StringStream& out, const ast::BinaryExpression* expr);
- /// Handles generating a bitcast expression
- /// @param out the output stream
- /// @param expr the as expression
- /// @returns true if the bitcast was emitted
- bool EmitBitcastCall(StringStream& out, const ast::CallExpression* expr);
- /// Emits a list of statements
- /// @param stmts the statement list
- /// @returns true if the statements were emitted successfully
- bool EmitStatements(VectorRef<const ast::Statement*> stmts);
- /// Emits a list of statements with an indentation
- /// @param stmts the statement list
- /// @returns true if the statements were emitted successfully
- bool EmitStatementsWithIndent(VectorRef<const ast::Statement*> stmts);
- /// Handles a block statement
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted successfully
- bool EmitBlock(const ast::BlockStatement* stmt);
- /// Handles a break statement
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted successfully
- bool EmitBreak(const ast::BreakStatement* stmt);
- /// Handles a break-if statement
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted successfully
- bool EmitBreakIf(const ast::BreakIfStatement* stmt);
- /// Handles generating a call expression
- /// @param out the output stream
- /// @param expr the call expression
- /// @returns true if the call expression is emitted
- bool EmitCall(StringStream& out, const ast::CallExpression* expr);
- /// Handles generating a function call expression
- /// @param out the output stream
- /// @param call the call expression
- /// @param function the function being called
- /// @returns true if the expression is emitted
- bool EmitFunctionCall(StringStream& out, const sem::Call* call, const sem::Function* function);
- /// Handles generating a builtin call expression
- /// @param out the output stream
- /// @param call the call expression
- /// @param builtin the builtin being called
- /// @returns true if the expression is emitted
- bool EmitBuiltinCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn* builtin);
- /// Handles generating a value conversion expression
- /// @param out the output stream
- /// @param call the call expression
- /// @param conv the value conversion
- /// @returns true if the expression is emitted
- bool EmitValueConversion(StringStream& out,
- const sem::Call* call,
- const sem::ValueConversion* conv);
- /// Handles generating a value constructor expression
- /// @param out the output stream
- /// @param call the call expression
- /// @param ctor the value constructor
- /// @returns true if the expression is emitted
- bool EmitValueConstructor(StringStream& out,
- const sem::Call* call,
- const sem::ValueConstructor* ctor);
- /// Handles generating a call expression to a
- /// DecomposeMemoryAccess::Intrinsic for a uniform buffer
- /// @param out the output stream
- /// @param expr the call expression
- /// @param intrinsic the DecomposeMemoryAccess::Intrinsic
- /// @returns true if the call expression is emitted
- bool EmitUniformBufferAccess(StringStream& out,
- const ast::CallExpression* expr,
- const DecomposeMemoryAccess::Intrinsic* intrinsic);
- /// Handles generating a call expression to a
- /// DecomposeMemoryAccess::Intrinsic for a storage buffer
- /// @param out the output stream
- /// @param expr the call expression
- /// @param intrinsic the DecomposeMemoryAccess::Intrinsic
- /// @returns true if the call expression is emitted
- bool EmitStorageBufferAccess(StringStream& out,
- const ast::CallExpression* expr,
- const DecomposeMemoryAccess::Intrinsic* intrinsic);
- /// Handles generating a barrier intrinsic call
- /// @param out the output stream
- /// @param builtin the semantic information for the barrier builtin
- /// @returns true if the call expression is emitted
- bool EmitBarrierCall(StringStream& out, const sem::BuiltinFn* builtin);
- /// Handles generating an atomic intrinsic call for a storage buffer variable
- /// @param out the output stream
- /// @param expr the call expression
- /// @param intrinsic the atomic intrinsic
- /// @returns true if the call expression is emitted
- bool EmitStorageAtomicCall(StringStream& out,
- const ast::CallExpression* expr,
- const DecomposeMemoryAccess::Intrinsic* intrinsic);
- /// Handles generating the helper function for the atomic intrinsic function
- /// @param func the function
- /// @param intrinsic the atomic intrinsic
- /// @returns true if the function is emitted
- bool EmitStorageAtomicIntrinsic(const ast::Function* func,
- const DecomposeMemoryAccess::Intrinsic* intrinsic);
- /// Handles generating an atomic intrinsic call for a workgroup variable
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the atomic builtin
- /// @returns true if the call expression is emitted
- bool EmitWorkgroupAtomicCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
- /// Handles generating a call to a texture function (`textureSample`,
- /// `textureSampleGrad`, etc)
- /// @param out the output stream
- /// @param call the call expression
- /// @param builtin the semantic information for the texture builtin
- /// @returns true if the call expression is emitted
- bool EmitTextureCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn* builtin);
- /// Handles generating a call to the `select()` builtin
- /// @param out the output stream
- /// @param expr the call expression
- /// @returns true if the call expression is emitted
- bool EmitSelectCall(StringStream& out, const ast::CallExpression* expr);
- /// Handles generating a call to the `modf()` builtin
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitModfCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
- /// Handles generating a call to the `frexp()` builtin
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitFrexpCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
- /// Handles generating a call to the `degrees()` builtin
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitDegreesCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
- /// Handles generating a call to the `radians()` builtin
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitRadiansCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
- /// Handles generating a call to the `sign()` builtin
- /// @param out the output stream
- /// @param call the call semantic node
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitSignCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn* builtin);
- /// Handles generating a call to data packing builtin
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitDataPackingCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
- /// Handles generating a call to data unpacking builtin
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitDataUnpackingCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
- /// Handles generating a call to the `quantizeToF16()` intrinsic
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitQuantizeToF16Call(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
- /// Handles generating a call to the `trunc()` intrinsic
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitTruncCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
- /// Handles generating a call to the builtins defined in the language extension
- /// `packed_4x8_integer_dot_product`.
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitPacked4x8IntegerDotProductBuiltinCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
- /// Handles generating a call to the `WaveReadLaneAt` intrinsic for subgroupShuffleXor,
- /// subgroupShuffleUp and subgroupShuffleDown
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitSubgroupShuffleBuiltinCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
-
- /// Handles generating a call to the `WavePrefixSum` and `WavePrefixProduct` intrinsic for
- /// subgroupInclusiveSum and subgroupInclusiveMul
- /// @param out the output stream
- /// @param expr the call expression
- /// @param builtin the semantic information for the builtin
- /// @returns true if the call expression is emitted
- bool EmitSubgroupInclusiveBuiltinCall(StringStream& out,
- const ast::CallExpression* expr,
- const sem::BuiltinFn* builtin);
-
- /// Handles a case statement
- /// @param s the switch statement
- /// @param case_idx the index of the switch case in the switch statement
- /// @returns true if the statement was emitted successfully
- bool EmitCase(const ast::SwitchStatement* s, size_t case_idx);
- /// Handles generating a discard statement
- /// @param stmt the discard statement
- /// @returns true if the statement was successfully emitted
- bool EmitDiscard(const ast::DiscardStatement* stmt);
- /// Handles a continue statement
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted successfully
- bool EmitContinue(const ast::ContinueStatement* stmt);
- /// Handles generating an Expression
- /// @param out the output stream
- /// @param expr the expression
- /// @returns true if the expression was emitted
- bool EmitExpression(StringStream& out, const ast::Expression* expr);
- /// Handles generating an Expression for texture or storage buffer call arguments. This is
- /// specifically to work around a DXC bug around passing signed integer splatted constants as
- /// args to these functions (see crbug.com/tint/1976)
- /// @param out the output stream
- /// @param expr the expression
- /// @returns true if the expression was emitted
- bool EmitTextureOrStorageBufferCallArgExpression(StringStream& out,
- const ast::Expression* expr);
- /// Handles generating a function
- /// @param func the function to generate
- /// @returns true if the function was emitted
- bool EmitFunction(const ast::Function* func);
- /// Handles emitting the function body if it discards to work around a FXC
- /// compilation bug.
- /// @param func the function with the body to emit
- /// @returns true if the function was emitted
- bool EmitFunctionBodyWithDiscard(const ast::Function* func);
- /// Handles emitting a global variable
- /// @param global the global variable
- /// @returns true on success
- bool EmitGlobalVariable(const ast::Variable* global);
-
- /// Handles emitting a global variable with the uniform address space
- /// @param var the AST node for the 'var'
- /// @param sem the semantic node for the 'var'
- /// @returns true on success
- bool EmitUniformVariable(const ast::Var* var, const sem::Variable* sem);
-
- /// Handles emitting a global variable with the storage address space
- /// @param var the AST node for the 'var'
- /// @param sem the semantic node for the 'var'
- /// @returns true on success
- bool EmitStorageVariable(const ast::Var* var, const sem::Variable* sem);
-
- /// Handles emitting a global variable with the handle address space
- /// @param var the AST node for the 'var'
- /// @param sem the semantic node for the 'var'
- /// @returns true on success
- bool EmitHandleVariable(const ast::Var* var, const sem::Variable* sem);
-
- /// Handles emitting a global variable with the private address space
- /// @param var the global variable
- /// @returns true on success
- bool EmitPrivateVariable(const sem::Variable* var);
-
- /// Handles emitting a global variable with the workgroup address space
- /// @param var the global variable
- /// @returns true on success
- bool EmitWorkgroupVariable(const sem::Variable* var);
-
- /// Handles emitting the entry point function
- /// @param func the entry point
- /// @returns true if the entry point function was emitted
- bool EmitEntryPointFunction(const ast::Function* func);
- /// Handles an if statement
- /// @param stmt the statement to emit
- /// @returns true if the statement was successfully emitted
- bool EmitIf(const ast::IfStatement* stmt);
- /// Handles a constant value
- /// @param out the output stream
- /// @param constant the constant value to emit
- /// @param is_variable_initializer true if the constant is used as the RHS of a variable
- /// initializer
- /// @returns true if the constant value was successfully emitted
- bool EmitConstant(StringStream& out,
- const core::constant::Value* constant,
- bool is_variable_initializer);
- /// Handles a literal
- /// @param out the output stream
- /// @param lit the literal to emit
- /// @returns true if the literal was successfully emitted
- bool EmitLiteral(StringStream& out, const ast::LiteralExpression* lit);
- /// Handles a loop statement
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted
- bool EmitLoop(const ast::LoopStatement* stmt);
- /// Handles a for loop statement
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted
- bool EmitForLoop(const ast::ForLoopStatement* stmt);
- /// Handles a while statement
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted
- bool EmitWhile(const ast::WhileStatement* stmt);
- /// Handles generating an identifier expression
- /// @param out the output stream
- /// @param expr the identifier expression
- /// @returns true if the identifeir was emitted
- bool EmitIdentifier(StringStream& out, const ast::IdentifierExpression* expr);
- /// Handles a member accessor expression
- /// @param out the output stream
- /// @param expr the member accessor expression
- /// @returns true if the member accessor was emitted
- bool EmitMemberAccessor(StringStream& out, const ast::MemberAccessorExpression* expr);
- /// Handles return statements
- /// @param stmt the statement to emit
- /// @returns true if the statement was successfully emitted
- bool EmitReturn(const ast::ReturnStatement* stmt);
- /// Handles statement
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted
- bool EmitStatement(const ast::Statement* stmt);
- /// Handles generating a switch statement
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted
- bool EmitSwitch(const ast::SwitchStatement* stmt);
- // Handles generating a switch statement with only a default case
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted
- bool EmitDefaultOnlySwitch(const ast::SwitchStatement* stmt);
- /// Handles generating type
- /// @param out the output stream
- /// @param type the type to generate
- /// @param address_space the address space of the variable
- /// @param access the access control type of the variable
- /// @param name the name of the variable, used for array emission.
- /// @param name_printed (optional) if not nullptr and an array was printed
- /// then the boolean is set to true.
- /// @returns true if the type is emitted
- bool EmitType(StringStream& out,
- const core::type::Type* type,
- core::AddressSpace address_space,
- core::Access access,
- const std::string& name,
- bool* name_printed = nullptr);
- /// Handles generating type and name
- /// @param out the output stream
- /// @param type the type to generate
- /// @param address_space the address space of the variable
- /// @param access the access control type of the variable
- /// @param name the name to emit
- /// @returns true if the type is emitted
- bool EmitTypeAndName(StringStream& out,
- const core::type::Type* type,
- core::AddressSpace address_space,
- core::Access access,
- const std::string& name);
- /// Handles generating a structure declaration. If the structure has already been emitted, then
- /// this function will simply return `true` without emitting anything.
- /// @param buffer the text buffer that the type declaration will be written to
- /// @param ty the struct to generate
- /// @param ast_struct_members the definition of struct members in the AST if not empty.
- /// @returns true if the struct is emitted
- bool EmitStructType(TextBuffer* buffer,
- const core::type::Struct* ty,
- VectorRef<const ast::StructMember*> ast_struct_members = Empty);
- /// Handles a unary op expression
- /// @param out the output stream
- /// @param expr the expression to emit
- /// @returns true if the expression was emitted
- bool EmitUnaryOp(StringStream& out, const ast::UnaryOpExpression* expr);
- /// Emits `value` for the given type
- /// @param out the output stream
- /// @param type the type to emit the value for
- /// @param value the value to emit
- /// @returns true if the value was successfully emitted.
- bool EmitValue(StringStream& out, const core::type::Type* type, int value);
- /// Emits the zero value for the given type
- /// @param out the output stream
- /// @param type the type to emit the value for
- /// @returns true if the zero value was successfully emitted.
- bool EmitZeroValue(StringStream& out, const core::type::Type* type);
- /// Handles generating a 'var' declaration
- /// @param var the variable to generate
- /// @returns true if the variable was emitted
- bool EmitVar(const ast::Var* var);
- /// Handles generating a 'let' declaration
- /// @param let the variable to generate
- /// @returns true if the variable was emitted
- bool EmitLet(const ast::Let* let);
- /// Emits call to a helper vector assignment function for the input assignment
- /// statement and vector type. This is used to work around FXC issues where
- /// assignments to vectors with dynamic indices cause compilation failures.
- /// @param stmt assignment statement that corresponds to a vector assignment
- /// via an accessor expression
- /// @param vec the vector type being assigned to
- /// @returns true on success
- bool EmitDynamicVectorAssignment(const ast::AssignmentStatement* stmt,
- const core::type::Vector* vec);
- /// Emits call to a helper matrix assignment function for the input assignment
- /// statement and matrix type. This is used to work around FXC issues where
- /// assignment of a vector to a matrix with a dynamic index causes compilation
- /// failures.
- /// @param stmt assignment statement that corresponds to a matrix assignment
- /// via an accessor expression
- /// @param mat the matrix type being assigned to
- /// @returns true on success
- bool EmitDynamicMatrixVectorAssignment(const ast::AssignmentStatement* stmt,
- const core::type::Matrix* mat);
- /// Emits call to a helper matrix assignment function for the input assignment
- /// statement and matrix type. This is used to work around FXC issues where
- /// assignment of a scalar to a matrix with at least one dynamic index causes
- /// compilation failures.
- /// @param stmt assignment statement that corresponds to a matrix assignment
- /// via an accessor expression
- /// @param mat the matrix type being assigned to
- /// @returns true on success
- bool EmitDynamicMatrixScalarAssignment(const ast::AssignmentStatement* stmt,
- const core::type::Matrix* mat);
-
- /// Handles generating a builtin method name
- /// @param builtin the semantic info for the builtin
- /// @returns the name or "" if not valid
- std::string generate_builtin_name(const sem::BuiltinFn* builtin);
- /// Converts a builtin to an attribute name
- /// @param builtin the builtin to convert
- /// @returns the string name of the builtin or blank on error
- std::string builtin_to_attribute(core::BuiltinValue builtin) const;
-
- /// Converts interpolation attributes to a HLSL modifiers
- /// @param type the interpolation type
- /// @param sampling the interpolation sampling
- /// @returns the string name of the attribute or blank on error
- std::string interpolation_to_modifiers(core::InterpolationType type,
- core::InterpolationSampling sampling) const;
-
- private:
- enum class VarType { kIn, kOut };
-
- struct EntryPointData {
- std::string struct_name;
- std::string var_name;
- };
-
- struct DMAIntrinsic {
- DecomposeMemoryAccess::Intrinsic::Op op;
- DecomposeMemoryAccess::Intrinsic::DataType type;
- bool operator==(const DMAIntrinsic& rhs) const { return op == rhs.op && type == rhs.type; }
- /// Hasher is a std::hash function for DMAIntrinsic
- struct Hasher {
- /// @param i the DMAIntrinsic to hash
- /// @returns the hash of `i`
- inline std::size_t operator()(const DMAIntrinsic& i) const {
- return Hash(i.op, i.type);
- }
- };
- };
-
- /// The map key for two semantic types.
- using BinaryType =
- tint::UnorderedKeyWrapper<std::tuple<const core::type::Type*, const core::type::Type*>>;
-
- /// CallBuiltinHelper will call the builtin helper function, creating it
- /// if it hasn't been built already. If the builtin needs to be built then
- /// CallBuiltinHelper will generate the function signature and will call
- /// `build` to emit the body of the function.
- /// @param out the output stream
- /// @param call the call expression
- /// @param builtin the semantic information for the builtin
- /// @param build a function with the signature:
- /// `bool(TextBuffer* buffer, const std::vector<std::string>& params)`
- /// Where:
- /// `buffer` is the body of the generated function
- /// `params` is the name of all the generated function parameters
- /// @returns true if the call expression is emitted
- template <typename F>
- bool CallBuiltinHelper(StringStream& out,
- const ast::CallExpression* call,
- const sem::BuiltinFn* builtin,
- F&& build);
-
- /// @param s the structure
- /// @returns the name of the structure, taking special care of builtin structures that start
- /// with double underscores. If the structure is a builtin, then the returned name will be a
- /// unique name without the leading underscores.
- std::string StructName(const core::type::Struct* s);
-
- /// @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.
- std::string UniqueIdentifier(const std::string& prefix = "");
-
- /// Alias for builder_.TypeOf(ptr)
- template <typename T>
- auto TypeOf(T* ptr) {
- return builder_.TypeOf(ptr);
- }
-
- ProgramBuilder builder_;
-
- /// Helper functions emitted at the top of the output
- TextBuffer helpers_;
-
- /// Map of builtin structure to unique generated name
- std::unordered_map<const core::type::Struct*, std::string> builtin_struct_names_;
- std::function<bool()> emit_continuing_;
- std::unordered_map<const core::type::Matrix*, std::string> matrix_scalar_inits_;
- std::unordered_map<const sem::BuiltinFn*, std::string> builtins_;
- // Polyfill functions for bitcast expression, BinaryType indicates the source type and the
- // destination type.
- std::unordered_map<BinaryType, std::string> bitcast_funcs_;
- std::unordered_map<const core::type::Vector*, std::string> dynamic_vector_write_;
- std::unordered_map<const core::type::Matrix*, std::string> dynamic_matrix_vector_write_;
- std::unordered_map<const core::type::Matrix*, std::string> dynamic_matrix_scalar_write_;
- std::unordered_map<const core::type::Type*, std::string> value_or_one_if_zero_;
- std::unordered_set<const core::type::Struct*> emitted_structs_;
-
- // The line index in current_buffer_ of the current global declaration / function.
- size_t global_insertion_point_ = 0;
-};
-
-} // namespace tint::hlsl::writer
-
-#endif // SRC_TINT_LANG_HLSL_WRITER_AST_PRINTER_AST_PRINTER_H_
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer_test.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer_test.cc
deleted file mode 100644
index faa95bf..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer_test.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-
-#include "src/tint/lang/hlsl/writer/writer.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest = TestHelper;
-
-TEST_F(HlslASTPrinterTest, InvalidProgram) {
- Diagnostics().AddError(Source{}) << "make the program invalid";
- ASSERT_FALSE(IsValid());
- auto program = resolver::Resolve(*this);
- ASSERT_FALSE(program.IsValid());
- auto result = Generate(program, Options{});
- EXPECT_NE(result, Success);
- EXPECT_EQ(result.Failure().reason, "error: make the program invalid");
-}
-
-TEST_F(HlslASTPrinterTest, UnsupportedExtension) {
- Enable(Source{{12, 34}}, wgsl::Extension::kChromiumExperimentalFramebufferFetch);
-
- ASTPrinter& gen = Build();
-
- ASSERT_FALSE(gen.Generate());
- EXPECT_EQ(
- gen.Diagnostics().Str(),
- R"(12:34 error: HLSL backend does not support extension 'chromium_experimental_framebuffer_fetch')");
-}
-
-TEST_F(HlslASTPrinterTest, RequiresDirective) {
- Require(wgsl::LanguageFeature::kReadonlyAndReadwriteStorageTextures);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), "");
-}
-
-TEST_F(HlslASTPrinterTest, Generate) {
- Func("my_func", {}, ty.void_(), {});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(void my_func() {
-}
-)");
-}
-
-struct HlslBuiltinData {
- core::BuiltinValue builtin;
- const char* attribute_name;
-};
-inline std::ostream& operator<<(std::ostream& out, HlslBuiltinData data) {
- StringStream str;
- str << data.builtin;
- out << str.str();
- return out;
-}
-using HlslBuiltinConversionTest = TestParamHelper<HlslBuiltinData>;
-TEST_P(HlslBuiltinConversionTest, Emit) {
- auto params = GetParam();
- ASTPrinter& gen = Build();
-
- EXPECT_EQ(gen.builtin_to_attribute(params.builtin), std::string(params.attribute_name));
-}
-INSTANTIATE_TEST_SUITE_P(
- HlslASTPrinterTest,
- HlslBuiltinConversionTest,
- testing::Values(HlslBuiltinData{core::BuiltinValue::kPosition, "SV_Position"},
- HlslBuiltinData{core::BuiltinValue::kVertexIndex, "SV_VertexID"},
- HlslBuiltinData{core::BuiltinValue::kInstanceIndex, "SV_InstanceID"},
- HlslBuiltinData{core::BuiltinValue::kFrontFacing, "SV_IsFrontFace"},
- HlslBuiltinData{core::BuiltinValue::kFragDepth, "SV_Depth"},
- HlslBuiltinData{core::BuiltinValue::kLocalInvocationId, "SV_GroupThreadID"},
- HlslBuiltinData{core::BuiltinValue::kLocalInvocationIndex, "SV_GroupIndex"},
- HlslBuiltinData{core::BuiltinValue::kGlobalInvocationId, "SV_DispatchThreadID"},
- HlslBuiltinData{core::BuiltinValue::kWorkgroupId, "SV_GroupID"},
- HlslBuiltinData{core::BuiltinValue::kSampleIndex, "SV_SampleIndex"},
- HlslBuiltinData{core::BuiltinValue::kSampleMask, "SV_Coverage"}));
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/binary_test.cc b/src/tint/lang/hlsl/writer/ast_printer/binary_test.cc
deleted file mode 100644
index 5bee9f9..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/binary_test.cc
+++ /dev/null
@@ -1,674 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/lang/wgsl/ast/call_statement.h"
-#include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
-#include "src/tint/utils/text/string_stream.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-using HlslASTPrinterTest_Binary = TestHelper;
-
-struct BinaryData {
- const char* result;
- core::BinaryOp op;
-
- enum Types { All = 0b11, Integer = 0b10, Float = 0b01 };
- Types valid_for = Types::All;
-};
-inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
- StringStream str;
- str << data.op;
- out << str.str();
- return out;
-}
-
-using HlslBinaryTest = TestParamHelper<BinaryData>;
-TEST_P(HlslBinaryTest, Emit_f32) {
- auto params = GetParam();
-
- if ((params.valid_for & BinaryData::Types::Float) == 0) {
- return;
- }
-
- // Skip ops that are illegal for this type
- if (params.op == core::BinaryOp::kAnd || params.op == core::BinaryOp::kOr ||
- params.op == core::BinaryOp::kXor || params.op == core::BinaryOp::kShiftLeft ||
- params.op == core::BinaryOp::kShiftRight) {
- return;
- }
-
- GlobalVar("left", ty.f32(), core::AddressSpace::kPrivate);
- GlobalVar("right", ty.f32(), core::AddressSpace::kPrivate);
-
- auto* left = Expr("left");
- auto* right = Expr("right");
-
- auto* expr = create<ast::BinaryExpression>(params.op, left, right);
-
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), params.result);
-}
-TEST_P(HlslBinaryTest, Emit_f16) {
- auto params = GetParam();
-
- if ((params.valid_for & BinaryData::Types::Float) == 0) {
- return;
- }
-
- // Skip ops that are illegal for this type
- if (params.op == core::BinaryOp::kAnd || params.op == core::BinaryOp::kOr ||
- params.op == core::BinaryOp::kXor || params.op == core::BinaryOp::kShiftLeft ||
- params.op == core::BinaryOp::kShiftRight) {
- return;
- }
-
- Enable(wgsl::Extension::kF16);
-
- GlobalVar("left", ty.f16(), core::AddressSpace::kPrivate);
- GlobalVar("right", ty.f16(), core::AddressSpace::kPrivate);
-
- auto* left = Expr("left");
- auto* right = Expr("right");
-
- auto* expr = create<ast::BinaryExpression>(params.op, left, right);
-
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), params.result);
-}
-TEST_P(HlslBinaryTest, Emit_u32) {
- auto params = GetParam();
-
- if ((params.valid_for & BinaryData::Types::Integer) == 0) {
- return;
- }
-
- GlobalVar("left", ty.u32(), core::AddressSpace::kPrivate);
- GlobalVar("right", ty.u32(), core::AddressSpace::kPrivate);
-
- auto* left = Expr("left");
- auto* right = Expr("right");
-
- auto* expr = create<ast::BinaryExpression>(params.op, left, right);
-
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), params.result);
-}
-TEST_P(HlslBinaryTest, Emit_i32) {
- auto params = GetParam();
-
- if ((params.valid_for & BinaryData::Types::Integer) == 0) {
- return;
- }
-
- // Skip ops that are illegal for this type
- if (params.op == core::BinaryOp::kShiftLeft || params.op == core::BinaryOp::kShiftRight) {
- return;
- }
-
- GlobalVar("left", ty.i32(), core::AddressSpace::kPrivate);
- GlobalVar("right", ty.i32(), core::AddressSpace::kPrivate);
-
- auto* left = Expr("left");
- auto* right = Expr("right");
-
- auto* expr = create<ast::BinaryExpression>(params.op, left, right);
-
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), params.result);
-}
-INSTANTIATE_TEST_SUITE_P(
- HlslASTPrinterTest,
- HlslBinaryTest,
- testing::Values(BinaryData{"(left & right)", core::BinaryOp::kAnd},
- BinaryData{"(left | right)", core::BinaryOp::kOr},
- BinaryData{"(left ^ right)", core::BinaryOp::kXor},
- BinaryData{"(left == right)", core::BinaryOp::kEqual},
- BinaryData{"(left != right)", core::BinaryOp::kNotEqual},
- BinaryData{"(left < right)", core::BinaryOp::kLessThan},
- BinaryData{"(left > right)", core::BinaryOp::kGreaterThan},
- BinaryData{"(left <= right)", core::BinaryOp::kLessThanEqual},
- BinaryData{"(left >= right)", core::BinaryOp::kGreaterThanEqual},
- BinaryData{"(left << right)", core::BinaryOp::kShiftLeft},
- BinaryData{"(left >> right)", core::BinaryOp::kShiftRight},
- BinaryData{"(left + right)", core::BinaryOp::kAdd},
- BinaryData{"(left - right)", core::BinaryOp::kSubtract},
- BinaryData{"(left * right)", core::BinaryOp::kMultiply},
- // NOTE: Integer divide covered by DivOrModBy* tests below
- BinaryData{"(left / right)", core::BinaryOp::kDivide, BinaryData::Types::Float},
- // NOTE: Integer modulo covered by DivOrModBy* tests below
- BinaryData{"(left % right)", core::BinaryOp::kModulo,
- BinaryData::Types::Float}));
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_VectorScalar_f32) {
- auto* lhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
- auto* rhs = Expr(1_f);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
-
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(1.0f).xxx");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_VectorScalar_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* lhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
- auto* rhs = Expr(1_h);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
-
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(float16_t(1.0h)).xxx");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_ScalarVector_f32) {
- auto* lhs = Expr(1_f);
- auto* rhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
-
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(1.0f).xxx");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_ScalarVector_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* lhs = Expr(1_h);
- auto* rhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
-
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(float16_t(1.0h)).xxx");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_MatrixScalar_f32) {
- GlobalVar("mat", ty.mat3x3<f32>(), core::AddressSpace::kPrivate);
- auto* lhs = Expr("mat");
- auto* rhs = Expr(1_f);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(mat * 1.0f)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_MatrixScalar_f16) {
- Enable(wgsl::Extension::kF16);
-
- GlobalVar("mat", ty.mat3x3<f16>(), core::AddressSpace::kPrivate);
- auto* lhs = Expr("mat");
- auto* rhs = Expr(1_h);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(mat * float16_t(1.0h))");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_ScalarMatrix_f32) {
- GlobalVar("mat", ty.mat3x3<f32>(), core::AddressSpace::kPrivate);
- auto* lhs = Expr(1_f);
- auto* rhs = Expr("mat");
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(1.0f * mat)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_ScalarMatrix_f16) {
- Enable(wgsl::Extension::kF16);
-
- GlobalVar("mat", ty.mat3x3<f16>(), core::AddressSpace::kPrivate);
- auto* lhs = Expr(1_h);
- auto* rhs = Expr("mat");
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(float16_t(1.0h) * mat)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_MatrixVector_f32) {
- GlobalVar("mat", ty.mat3x3<f32>(), core::AddressSpace::kPrivate);
- auto* lhs = Expr("mat");
- auto* rhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "mul((1.0f).xxx, mat)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_MatrixVector_f16) {
- Enable(wgsl::Extension::kF16);
-
- GlobalVar("mat", ty.mat3x3<f16>(), core::AddressSpace::kPrivate);
- auto* lhs = Expr("mat");
- auto* rhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "mul((float16_t(1.0h)).xxx, mat)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_VectorMatrix_f32) {
- GlobalVar("mat", ty.mat3x3<f32>(), core::AddressSpace::kPrivate);
- auto* lhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
- auto* rhs = Expr("mat");
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "mul(mat, (1.0f).xxx)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_VectorMatrix_f16) {
- Enable(wgsl::Extension::kF16);
-
- GlobalVar("mat", ty.mat3x3<f16>(), core::AddressSpace::kPrivate);
- auto* lhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
- auto* rhs = Expr("mat");
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, lhs, rhs);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "mul(mat, (float16_t(1.0h)).xxx)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_MatrixMatrix_f32) {
- GlobalVar("lhs", ty.mat3x3<f32>(), core::AddressSpace::kPrivate);
- GlobalVar("rhs", ty.mat3x3<f32>(), core::AddressSpace::kPrivate);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "mul(rhs, lhs)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Multiply_MatrixMatrix_f16) {
- Enable(wgsl::Extension::kF16);
-
- GlobalVar("lhs", ty.mat3x3<f16>(), core::AddressSpace::kPrivate);
- GlobalVar("rhs", ty.mat3x3<f16>(), core::AddressSpace::kPrivate);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "mul(rhs, lhs)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Logical_And) {
- GlobalVar("a", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("b", ty.bool_(), core::AddressSpace::kPrivate);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kLogicalAnd, Expr("a"), Expr("b"));
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(tint_tmp)");
- EXPECT_EQ(gen.Result(), R"(bool tint_tmp = a;
-if (tint_tmp) {
- tint_tmp = b;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Logical_Multi) {
- // (a && b) || (c || d)
- GlobalVar("a", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("b", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("c", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("d", ty.bool_(), core::AddressSpace::kPrivate);
-
- auto* expr = create<ast::BinaryExpression>(
- core::BinaryOp::kLogicalOr,
- create<ast::BinaryExpression>(core::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
- create<ast::BinaryExpression>(core::BinaryOp::kLogicalOr, Expr("c"), Expr("d")));
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(tint_tmp)");
- EXPECT_EQ(gen.Result(), R"(bool tint_tmp_1 = a;
-if (tint_tmp_1) {
- tint_tmp_1 = b;
-}
-bool tint_tmp = (tint_tmp_1);
-if (!tint_tmp) {
- bool tint_tmp_2 = c;
- if (!tint_tmp_2) {
- tint_tmp_2 = d;
- }
- tint_tmp = (tint_tmp_2);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Logical_Or) {
- GlobalVar("a", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("b", ty.bool_(), core::AddressSpace::kPrivate);
-
- auto* expr = create<ast::BinaryExpression>(core::BinaryOp::kLogicalOr, Expr("a"), Expr("b"));
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(tint_tmp)");
- EXPECT_EQ(gen.Result(), R"(bool tint_tmp = a;
-if (!tint_tmp) {
- tint_tmp = b;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, If_WithLogical) {
- // if (a && b) {
- // return 1i;
- // } else if (b || c) {
- // return 2i;
- // } else {
- // return 3i;
- // }
-
- GlobalVar("a", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("b", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("c", ty.bool_(), core::AddressSpace::kPrivate);
-
- auto* expr =
- If(create<ast::BinaryExpression>(core::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
- Block(Return(1_i)),
- Else(If(create<ast::BinaryExpression>(core::BinaryOp::kLogicalOr, Expr("b"), Expr("c")),
- Block(Return(2_i)), Else(Block(Return(3_i))))));
- Func("func", tint::Empty, ty.i32(), Vector{WrapInStatement(expr)});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.EmitStatement(expr)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(bool tint_tmp = a;
-if (tint_tmp) {
- tint_tmp = b;
-}
-if ((tint_tmp)) {
- return 1;
-} else {
- bool tint_tmp_1 = b;
- if (!tint_tmp_1) {
- tint_tmp_1 = c;
- }
- if ((tint_tmp_1)) {
- return 2;
- } else {
- return 3;
- }
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Return_WithLogical) {
- // return (a && b) || c;
-
- GlobalVar("a", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("b", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("c", ty.bool_(), core::AddressSpace::kPrivate);
-
- auto* expr = Return(create<ast::BinaryExpression>(
- core::BinaryOp::kLogicalOr,
- create<ast::BinaryExpression>(core::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
- Expr("c")));
- Func("func", tint::Empty, ty.bool_(), Vector{WrapInStatement(expr)});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.EmitStatement(expr)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(bool tint_tmp_1 = a;
-if (tint_tmp_1) {
- tint_tmp_1 = b;
-}
-bool tint_tmp = (tint_tmp_1);
-if (!tint_tmp) {
- tint_tmp = c;
-}
-return (tint_tmp);
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Assign_WithLogical) {
- // a = (b || c) && d;
-
- GlobalVar("a", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("b", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("c", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("d", ty.bool_(), core::AddressSpace::kPrivate);
-
- auto* expr =
- Assign(Expr("a"),
- create<ast::BinaryExpression>(
- core::BinaryOp::kLogicalAnd,
- create<ast::BinaryExpression>(core::BinaryOp::kLogicalOr, Expr("b"), Expr("c")),
- Expr("d")));
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.EmitStatement(expr)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(bool tint_tmp_1 = b;
-if (!tint_tmp_1) {
- tint_tmp_1 = c;
-}
-bool tint_tmp = (tint_tmp_1);
-if (tint_tmp) {
- tint_tmp = d;
-}
-a = (tint_tmp);
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Decl_WithLogical) {
- // var a : bool = (b && c) || d;
-
- GlobalVar("b", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("c", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("d", ty.bool_(), core::AddressSpace::kPrivate);
-
- auto* var =
- Var("a", ty.bool_(), core::AddressSpace::kUndefined,
- create<ast::BinaryExpression>(
- core::BinaryOp::kLogicalOr,
- create<ast::BinaryExpression>(core::BinaryOp::kLogicalAnd, Expr("b"), Expr("c")),
- Expr("d")));
-
- auto* decl = Decl(var);
- WrapInFunction(decl);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.EmitStatement(decl)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(bool tint_tmp_1 = b;
-if (tint_tmp_1) {
- tint_tmp_1 = c;
-}
-bool tint_tmp = (tint_tmp_1);
-if (!tint_tmp) {
- tint_tmp = d;
-}
-bool a = (tint_tmp);
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Binary, Call_WithLogical) {
- // foo(a && b, c || d, (a || c) && (b || d))
-
- Func("foo",
- Vector{
- Param(Sym(), ty.bool_()),
- Param(Sym(), ty.bool_()),
- Param(Sym(), ty.bool_()),
- },
- ty.void_(), tint::Empty, tint::Empty);
- GlobalVar("a", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("b", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("c", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("d", ty.bool_(), core::AddressSpace::kPrivate);
-
- Vector params{
- create<ast::BinaryExpression>(core::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
- create<ast::BinaryExpression>(core::BinaryOp::kLogicalOr, Expr("c"), Expr("d")),
- create<ast::BinaryExpression>(
- core::BinaryOp::kLogicalAnd,
- create<ast::BinaryExpression>(core::BinaryOp::kLogicalOr, Expr("a"), Expr("c")),
- create<ast::BinaryExpression>(core::BinaryOp::kLogicalOr, Expr("b"), Expr("d"))),
- };
-
- auto* expr = CallStmt(Call("foo", params));
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.EmitStatement(expr)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(bool tint_tmp = a;
-if (tint_tmp) {
- tint_tmp = b;
-}
-bool tint_tmp_1 = c;
-if (!tint_tmp_1) {
- tint_tmp_1 = d;
-}
-bool tint_tmp_3 = a;
-if (!tint_tmp_3) {
- tint_tmp_3 = c;
-}
-bool tint_tmp_2 = (tint_tmp_3);
-if (tint_tmp_2) {
- bool tint_tmp_4 = b;
- if (!tint_tmp_4) {
- tint_tmp_4 = d;
- }
- tint_tmp_2 = (tint_tmp_4);
-}
-foo((tint_tmp), (tint_tmp_1), (tint_tmp_2));
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/bitcast_test.cc b/src/tint/lang/hlsl/writer/ast_printer/bitcast_test.cc
deleted file mode 100644
index bb89d6f..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/bitcast_test.cc
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/utils/text/string_stream.h"
-
-#include "gmock/gmock.h"
-
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Bitcast = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Bitcast, EmitExpression_Bitcast_Float) {
- auto* a = Let("a", Expr(1_i));
- auto* bitcast = Bitcast<f32>(Expr("a"));
- WrapInFunction(a, bitcast);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "asfloat(a)");
-}
-
-TEST_F(HlslASTPrinterTest_Bitcast, EmitExpression_Bitcast_Int) {
- auto* a = Let("a", Expr(1_u));
- auto* bitcast = Bitcast<i32>(Expr("a"));
- WrapInFunction(a, bitcast);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "asint(a)");
-}
-
-TEST_F(HlslASTPrinterTest_Bitcast, EmitExpression_Bitcast_Uint) {
- auto* a = Let("a", Expr(1_i));
- auto* bitcast = Bitcast<u32>(Expr("a"));
- WrapInFunction(a, bitcast);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "asuint(a)");
-}
-
-TEST_F(HlslASTPrinterTest_Bitcast, EmitExpression_Bitcast_F16_Vec2) {
- Enable(wgsl::Extension::kF16);
-
- auto* a = Let("a", Call<vec2<f16>>(1_h, 2_h));
- auto* b = Let("b", Bitcast<i32>(Expr("a")));
- auto* c = Let("c", Bitcast<vec2<f16>>(Expr("b")));
- auto* d = Let("d", Bitcast<f32>(Expr("c")));
- auto* e = Let("e", Bitcast<vec2<f16>>(Expr("d")));
- auto* f = Let("f", Bitcast<u32>(Expr("e")));
- auto* g = Let("g", Bitcast<vec2<f16>>(Expr("f")));
- WrapInFunction(a, b, c, d, e, f, g);
-
- ASTPrinter& gen = Build();
-
- gen.Generate();
- EXPECT_THAT(gen.Diagnostics(), testing::IsEmpty());
- EXPECT_EQ(gen.Result(), R"(int tint_bitcast_from_f16(vector<float16_t, 2> src) {
- uint2 r = f32tof16(float2(src));
- return asint(uint((r.x & 0xffff) | ((r.y & 0xffff) << 16)));
-}
-
-vector<float16_t, 2> tint_bitcast_to_f16(int src) {
- uint v = asuint(src);
- float t_low = f16tof32(v & 0xffff);
- float t_high = f16tof32((v >> 16) & 0xffff);
- return vector<float16_t, 2>(t_low.x, t_high.x);
-}
-
-float tint_bitcast_from_f16_1(vector<float16_t, 2> src) {
- uint2 r = f32tof16(float2(src));
- return asfloat(uint((r.x & 0xffff) | ((r.y & 0xffff) << 16)));
-}
-
-vector<float16_t, 2> tint_bitcast_to_f16_1(float src) {
- uint v = asuint(src);
- float t_low = f16tof32(v & 0xffff);
- float t_high = f16tof32((v >> 16) & 0xffff);
- return vector<float16_t, 2>(t_low.x, t_high.x);
-}
-
-uint tint_bitcast_from_f16_2(vector<float16_t, 2> src) {
- uint2 r = f32tof16(float2(src));
- return asuint(uint((r.x & 0xffff) | ((r.y & 0xffff) << 16)));
-}
-
-vector<float16_t, 2> tint_bitcast_to_f16_2(uint src) {
- uint v = asuint(src);
- float t_low = f16tof32(v & 0xffff);
- float t_high = f16tof32((v >> 16) & 0xffff);
- return vector<float16_t, 2>(t_low.x, t_high.x);
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- vector<float16_t, 2> a = vector<float16_t, 2>(float16_t(1.0h), float16_t(2.0h));
- int b = tint_bitcast_from_f16(a);
- vector<float16_t, 2> c = tint_bitcast_to_f16(b);
- float d = tint_bitcast_from_f16_1(c);
- vector<float16_t, 2> e = tint_bitcast_to_f16_1(d);
- uint f = tint_bitcast_from_f16_2(e);
- vector<float16_t, 2> g = tint_bitcast_to_f16_2(f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Bitcast, EmitExpression_Bitcast_F16_Vec4) {
- Enable(wgsl::Extension::kF16);
-
- auto* a = Let("a", Call<vec4<f16>>(1_h, 2_h, 3_h, 4_h));
- auto* b = Let("b", Bitcast<vec2<i32>>(Expr("a")));
- auto* c = Let("c", Bitcast<vec4<f16>>(Expr("b")));
- auto* d = Let("d", Bitcast<vec2<f32>>(Expr("c")));
- auto* e = Let("e", Bitcast<vec4<f16>>(Expr("d")));
- auto* f = Let("f", Bitcast<vec2<u32>>(Expr("e")));
- auto* g = Let("g", Bitcast<vec4<f16>>(Expr("f")));
- WrapInFunction(a, b, c, d, e, f, g);
-
- ASTPrinter& gen = Build();
-
- gen.Generate();
- EXPECT_THAT(gen.Diagnostics(), testing::IsEmpty());
- EXPECT_EQ(gen.Result(), R"(int2 tint_bitcast_from_f16(vector<float16_t, 4> src) {
- uint4 r = f32tof16(float4(src));
- return asint(uint2((r.x & 0xffff) | ((r.y & 0xffff) << 16), (r.z & 0xffff) | ((r.w & 0xffff) << 16)));
-}
-
-vector<float16_t, 4> tint_bitcast_to_f16(int2 src) {
- uint2 v = asuint(src);
- float2 t_low = f16tof32(v & 0xffff);
- float2 t_high = f16tof32((v >> 16) & 0xffff);
- return vector<float16_t, 4>(t_low.x, t_high.x, t_low.y, t_high.y);
-}
-
-float2 tint_bitcast_from_f16_1(vector<float16_t, 4> src) {
- uint4 r = f32tof16(float4(src));
- return asfloat(uint2((r.x & 0xffff) | ((r.y & 0xffff) << 16), (r.z & 0xffff) | ((r.w & 0xffff) << 16)));
-}
-
-vector<float16_t, 4> tint_bitcast_to_f16_1(float2 src) {
- uint2 v = asuint(src);
- float2 t_low = f16tof32(v & 0xffff);
- float2 t_high = f16tof32((v >> 16) & 0xffff);
- return vector<float16_t, 4>(t_low.x, t_high.x, t_low.y, t_high.y);
-}
-
-uint2 tint_bitcast_from_f16_2(vector<float16_t, 4> src) {
- uint4 r = f32tof16(float4(src));
- return asuint(uint2((r.x & 0xffff) | ((r.y & 0xffff) << 16), (r.z & 0xffff) | ((r.w & 0xffff) << 16)));
-}
-
-vector<float16_t, 4> tint_bitcast_to_f16_2(uint2 src) {
- uint2 v = asuint(src);
- float2 t_low = f16tof32(v & 0xffff);
- float2 t_high = f16tof32((v >> 16) & 0xffff);
- return vector<float16_t, 4>(t_low.x, t_high.x, t_low.y, t_high.y);
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- vector<float16_t, 4> a = vector<float16_t, 4>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h), float16_t(4.0h));
- int2 b = tint_bitcast_from_f16(a);
- vector<float16_t, 4> c = tint_bitcast_to_f16(b);
- float2 d = tint_bitcast_from_f16_1(c);
- vector<float16_t, 4> e = tint_bitcast_to_f16_1(d);
- uint2 f = tint_bitcast_from_f16_2(e);
- vector<float16_t, 4> g = tint_bitcast_to_f16_2(f);
- return;
-}
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/block_test.cc b/src/tint/lang/hlsl/writer/ast_printer/block_test.cc
deleted file mode 100644
index faa847b..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/block_test.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Block = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Block, Emit_Block) {
- auto* b = Block(Return());
- WrapInFunction(b);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(b)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( {
- return;
- }
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/break_test.cc b/src/tint/lang/hlsl/writer/ast_printer/break_test.cc
deleted file mode 100644
index 61b39d4..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/break_test.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Break = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Break, Emit_Break) {
- auto* b = create<ast::BreakStatement>();
- WrapInFunction(Loop(Block(b)));
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(b)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), " break;\n");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc b/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc
deleted file mode 100644
index 770f7ce..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc
+++ /dev/null
@@ -1,1538 +0,0 @@
-// Copyright 2020 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 "gmock/gmock.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/lang/wgsl/ast/call_statement.h"
-#include "src/tint/lang/wgsl/ast/stage_attribute.h"
-#include "src/tint/lang/wgsl/sem/call.h"
-#include "src/tint/utils/text/string_stream.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using ::testing::HasSubstr;
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-using HlslASTPrinterTest_Builtin = TestHelper;
-
-enum class CallParamType {
- kF32,
- kU32,
- kBool,
- kF16,
-};
-
-struct BuiltinData {
- wgsl::BuiltinFn builtin;
- CallParamType type;
- const char* hlsl_name;
-};
-inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
- out << data.hlsl_name << "<";
- switch (data.type) {
- case CallParamType::kF32:
- out << "f32";
- break;
- case CallParamType::kU32:
- out << "u32";
- break;
- case CallParamType::kBool:
- out << "bool";
- break;
- case CallParamType::kF16:
- out << "f16";
- break;
- }
- out << ">";
- return out;
-}
-
-const ast::CallExpression* GenerateCall(wgsl::BuiltinFn builtin,
- CallParamType type,
- ProgramBuilder* builder) {
- std::string name;
- StringStream str;
- str << name << builtin;
- switch (builtin) {
- case wgsl::BuiltinFn::kAcos:
- case wgsl::BuiltinFn::kAsin:
- case wgsl::BuiltinFn::kAtan:
- case wgsl::BuiltinFn::kCeil:
- case wgsl::BuiltinFn::kCos:
- case wgsl::BuiltinFn::kCosh:
- case wgsl::BuiltinFn::kDpdx:
- case wgsl::BuiltinFn::kDpdxCoarse:
- case wgsl::BuiltinFn::kDpdxFine:
- case wgsl::BuiltinFn::kDpdy:
- case wgsl::BuiltinFn::kDpdyCoarse:
- case wgsl::BuiltinFn::kDpdyFine:
- case wgsl::BuiltinFn::kExp:
- case wgsl::BuiltinFn::kExp2:
- case wgsl::BuiltinFn::kFloor:
- case wgsl::BuiltinFn::kFract:
- case wgsl::BuiltinFn::kFwidth:
- case wgsl::BuiltinFn::kFwidthCoarse:
- case wgsl::BuiltinFn::kFwidthFine:
- case wgsl::BuiltinFn::kInverseSqrt:
- case wgsl::BuiltinFn::kLength:
- case wgsl::BuiltinFn::kLog:
- case wgsl::BuiltinFn::kLog2:
- case wgsl::BuiltinFn::kNormalize:
- case wgsl::BuiltinFn::kRound:
- case wgsl::BuiltinFn::kSin:
- case wgsl::BuiltinFn::kSinh:
- case wgsl::BuiltinFn::kSqrt:
- case wgsl::BuiltinFn::kTan:
- case wgsl::BuiltinFn::kTanh:
- if (type == CallParamType::kF16) {
- return builder->Call(str.str(), "h2");
- } else {
- return builder->Call(str.str(), "f2");
- }
- case wgsl::BuiltinFn::kLdexp:
- if (type == CallParamType::kF16) {
- return builder->Call(str.str(), "h2", "i2");
- } else {
- return builder->Call(str.str(), "f2", "i2");
- }
- case wgsl::BuiltinFn::kAtan2:
- case wgsl::BuiltinFn::kDot:
- case wgsl::BuiltinFn::kDistance:
- case wgsl::BuiltinFn::kPow:
- case wgsl::BuiltinFn::kReflect:
- case wgsl::BuiltinFn::kStep:
- if (type == CallParamType::kF16) {
- return builder->Call(str.str(), "h2", "h2");
- } else {
- return builder->Call(str.str(), "f2", "f2");
- }
- case wgsl::BuiltinFn::kCross:
- if (type == CallParamType::kF16) {
- return builder->Call(str.str(), "h3", "h3");
- } else {
- return builder->Call(str.str(), "f3", "f3");
- }
- case wgsl::BuiltinFn::kFma:
- case wgsl::BuiltinFn::kMix:
- case wgsl::BuiltinFn::kFaceForward:
- case wgsl::BuiltinFn::kSmoothstep:
- if (type == CallParamType::kF16) {
- return builder->Call(str.str(), "h2", "h2", "h2");
- } else {
- return builder->Call(str.str(), "f2", "f2", "f2");
- }
- case wgsl::BuiltinFn::kAll:
- case wgsl::BuiltinFn::kAny:
- return builder->Call(str.str(), "b2");
- case wgsl::BuiltinFn::kAbs:
- if (type == CallParamType::kF32) {
- return builder->Call(str.str(), "f2");
- } else if (type == CallParamType::kF16) {
- return builder->Call(str.str(), "h2");
- } else {
- return builder->Call(str.str(), "u2");
- }
- case wgsl::BuiltinFn::kCountOneBits:
- case wgsl::BuiltinFn::kReverseBits:
- return builder->Call(str.str(), "u2");
- case wgsl::BuiltinFn::kMax:
- case wgsl::BuiltinFn::kMin:
- if (type == CallParamType::kF32) {
- return builder->Call(str.str(), "f2", "f2");
- } else if (type == CallParamType::kF16) {
- return builder->Call(str.str(), "h2", "h2");
- } else {
- return builder->Call(str.str(), "u2", "u2");
- }
- case wgsl::BuiltinFn::kClamp:
- if (type == CallParamType::kF32) {
- return builder->Call(str.str(), "f2", "f2", "f2");
- } else if (type == CallParamType::kF16) {
- return builder->Call(str.str(), "h2", "h2", "h2");
- } else {
- return builder->Call(str.str(), "u2", "u2", "u2");
- }
- case wgsl::BuiltinFn::kSelect:
- if (type == CallParamType::kF16) {
- return builder->Call(str.str(), "h2", "h2", "b2");
- } else {
- return builder->Call(str.str(), "f2", "f2", "b2");
- }
- case wgsl::BuiltinFn::kDeterminant:
- if (type == CallParamType::kF16) {
- return builder->Call(str.str(), "hm2x2");
- } else {
- return builder->Call(str.str(), "m2x2");
- }
- case wgsl::BuiltinFn::kTranspose:
- if (type == CallParamType::kF16) {
- return builder->Call(str.str(), "hm3x2");
- } else {
- return builder->Call(str.str(), "m3x2");
- }
- default:
- break;
- }
- return nullptr;
-}
-
-using HlslBuiltinTest = TestParamHelper<BuiltinData>;
-TEST_P(HlslBuiltinTest, Emit) {
- auto param = GetParam();
-
- if (param.type == CallParamType::kF16) {
- Enable(wgsl::Extension::kF16);
-
- GlobalVar("h2", ty.vec2<f16>(), core::AddressSpace::kPrivate);
- GlobalVar("h3", ty.vec3<f16>(), core::AddressSpace::kPrivate);
- GlobalVar("hm2x2", ty.mat2x2<f16>(), core::AddressSpace::kPrivate);
- GlobalVar("hm3x2", ty.mat3x2<f16>(), core::AddressSpace::kPrivate);
- }
-
- GlobalVar("f2", ty.vec2<f32>(), core::AddressSpace::kPrivate);
- GlobalVar("f3", ty.vec3<f32>(), core::AddressSpace::kPrivate);
- GlobalVar("u2", ty.vec2<u32>(), core::AddressSpace::kPrivate);
- GlobalVar("i2", ty.vec2<i32>(), core::AddressSpace::kPrivate);
- GlobalVar("b2", ty.vec2<bool>(), core::AddressSpace::kPrivate);
- GlobalVar("m2x2", ty.mat2x2<f32>(), core::AddressSpace::kPrivate);
- GlobalVar("m3x2", ty.mat3x2<f32>(), core::AddressSpace::kPrivate);
-
- auto* call = GenerateCall(param.builtin, param.type, this);
- ASSERT_NE(nullptr, call) << "Unhandled builtin";
- Func("func", tint::Empty, ty.void_(),
- Vector{
- Assign(Phony(), call),
- },
- Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
-
- ASTPrinter& gen = Build();
-
- auto* sem = program->Sem().Get<sem::Call>(call);
- ASSERT_NE(sem, nullptr);
- auto* target = sem->Target();
- ASSERT_NE(target, nullptr);
- auto* builtin = target->As<sem::BuiltinFn>();
- ASSERT_NE(builtin, nullptr);
-
- EXPECT_EQ(gen.generate_builtin_name(builtin), param.hlsl_name);
-}
-INSTANTIATE_TEST_SUITE_P(
- HlslASTPrinterTest_Builtin,
- HlslBuiltinTest,
- testing::Values(/* Logical built-in */
- BuiltinData{wgsl::BuiltinFn::kAll, CallParamType::kBool, "all"},
- BuiltinData{wgsl::BuiltinFn::kAny, CallParamType::kBool, "any"},
- /* Float built-in */
- BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kF32, "abs"},
- BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kF16, "abs"},
- BuiltinData{wgsl::BuiltinFn::kAcos, CallParamType::kF32, "acos"},
- BuiltinData{wgsl::BuiltinFn::kAcos, CallParamType::kF16, "acos"},
- BuiltinData{wgsl::BuiltinFn::kAsin, CallParamType::kF32, "asin"},
- BuiltinData{wgsl::BuiltinFn::kAsin, CallParamType::kF16, "asin"},
- BuiltinData{wgsl::BuiltinFn::kAtan, CallParamType::kF32, "atan"},
- BuiltinData{wgsl::BuiltinFn::kAtan, CallParamType::kF16, "atan"},
- BuiltinData{wgsl::BuiltinFn::kAtan2, CallParamType::kF32, "atan2"},
- BuiltinData{wgsl::BuiltinFn::kAtan2, CallParamType::kF16, "atan2"},
- BuiltinData{wgsl::BuiltinFn::kCeil, CallParamType::kF32, "ceil"},
- BuiltinData{wgsl::BuiltinFn::kCeil, CallParamType::kF16, "ceil"},
- BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kF32, "clamp"},
- BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kF16, "clamp"},
- BuiltinData{wgsl::BuiltinFn::kCos, CallParamType::kF32, "cos"},
- BuiltinData{wgsl::BuiltinFn::kCos, CallParamType::kF16, "cos"},
- BuiltinData{wgsl::BuiltinFn::kCosh, CallParamType::kF32, "cosh"},
- BuiltinData{wgsl::BuiltinFn::kCosh, CallParamType::kF16, "cosh"},
- BuiltinData{wgsl::BuiltinFn::kCross, CallParamType::kF32, "cross"},
- BuiltinData{wgsl::BuiltinFn::kCross, CallParamType::kF16, "cross"},
- BuiltinData{wgsl::BuiltinFn::kDistance, CallParamType::kF32, "distance"},
- BuiltinData{wgsl::BuiltinFn::kDistance, CallParamType::kF16, "distance"},
- BuiltinData{wgsl::BuiltinFn::kExp, CallParamType::kF32, "exp"},
- BuiltinData{wgsl::BuiltinFn::kExp, CallParamType::kF16, "exp"},
- BuiltinData{wgsl::BuiltinFn::kExp2, CallParamType::kF32, "exp2"},
- BuiltinData{wgsl::BuiltinFn::kExp2, CallParamType::kF16, "exp2"},
- BuiltinData{wgsl::BuiltinFn::kFaceForward, CallParamType::kF32, "faceforward"},
- BuiltinData{wgsl::BuiltinFn::kFaceForward, CallParamType::kF16, "faceforward"},
- BuiltinData{wgsl::BuiltinFn::kFloor, CallParamType::kF32, "floor"},
- BuiltinData{wgsl::BuiltinFn::kFloor, CallParamType::kF16, "floor"},
- BuiltinData{wgsl::BuiltinFn::kFma, CallParamType::kF32, "mad"},
- BuiltinData{wgsl::BuiltinFn::kFma, CallParamType::kF16, "mad"},
- BuiltinData{wgsl::BuiltinFn::kFract, CallParamType::kF32, "frac"},
- BuiltinData{wgsl::BuiltinFn::kFract, CallParamType::kF16, "frac"},
- BuiltinData{wgsl::BuiltinFn::kInverseSqrt, CallParamType::kF32, "rsqrt"},
- BuiltinData{wgsl::BuiltinFn::kInverseSqrt, CallParamType::kF16, "rsqrt"},
- BuiltinData{wgsl::BuiltinFn::kLdexp, CallParamType::kF32, "ldexp"},
- BuiltinData{wgsl::BuiltinFn::kLdexp, CallParamType::kF16, "ldexp"},
- BuiltinData{wgsl::BuiltinFn::kLength, CallParamType::kF32, "length"},
- BuiltinData{wgsl::BuiltinFn::kLength, CallParamType::kF16, "length"},
- BuiltinData{wgsl::BuiltinFn::kLog, CallParamType::kF32, "log"},
- BuiltinData{wgsl::BuiltinFn::kLog, CallParamType::kF16, "log"},
- BuiltinData{wgsl::BuiltinFn::kLog2, CallParamType::kF32, "log2"},
- BuiltinData{wgsl::BuiltinFn::kLog2, CallParamType::kF16, "log2"},
- BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kF32, "max"},
- BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kF16, "max"},
- BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kF32, "min"},
- BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kF16, "min"},
- BuiltinData{wgsl::BuiltinFn::kMix, CallParamType::kF32, "lerp"},
- BuiltinData{wgsl::BuiltinFn::kMix, CallParamType::kF16, "lerp"},
- BuiltinData{wgsl::BuiltinFn::kNormalize, CallParamType::kF32, "normalize"},
- BuiltinData{wgsl::BuiltinFn::kNormalize, CallParamType::kF16, "normalize"},
- BuiltinData{wgsl::BuiltinFn::kPow, CallParamType::kF32, "pow"},
- BuiltinData{wgsl::BuiltinFn::kPow, CallParamType::kF16, "pow"},
- BuiltinData{wgsl::BuiltinFn::kReflect, CallParamType::kF32, "reflect"},
- BuiltinData{wgsl::BuiltinFn::kReflect, CallParamType::kF16, "reflect"},
- BuiltinData{wgsl::BuiltinFn::kSin, CallParamType::kF32, "sin"},
- BuiltinData{wgsl::BuiltinFn::kSin, CallParamType::kF16, "sin"},
- BuiltinData{wgsl::BuiltinFn::kSinh, CallParamType::kF32, "sinh"},
- BuiltinData{wgsl::BuiltinFn::kSinh, CallParamType::kF16, "sinh"},
- BuiltinData{wgsl::BuiltinFn::kSmoothstep, CallParamType::kF32, "smoothstep"},
- BuiltinData{wgsl::BuiltinFn::kSmoothstep, CallParamType::kF16, "smoothstep"},
- BuiltinData{wgsl::BuiltinFn::kSqrt, CallParamType::kF32, "sqrt"},
- BuiltinData{wgsl::BuiltinFn::kSqrt, CallParamType::kF16, "sqrt"},
- BuiltinData{wgsl::BuiltinFn::kStep, CallParamType::kF32, "step"},
- BuiltinData{wgsl::BuiltinFn::kStep, CallParamType::kF16, "step"},
- BuiltinData{wgsl::BuiltinFn::kTan, CallParamType::kF32, "tan"},
- BuiltinData{wgsl::BuiltinFn::kTan, CallParamType::kF16, "tan"},
- BuiltinData{wgsl::BuiltinFn::kTanh, CallParamType::kF32, "tanh"},
- BuiltinData{wgsl::BuiltinFn::kTanh, CallParamType::kF16, "tanh"},
- /* Integer built-in */
- BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kU32, "abs"},
- BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kU32, "clamp"},
- BuiltinData{wgsl::BuiltinFn::kCountOneBits, CallParamType::kU32, "countbits"},
- BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kU32, "max"},
- BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kU32, "min"},
- BuiltinData{wgsl::BuiltinFn::kReverseBits, CallParamType::kU32, "reversebits"},
- BuiltinData{wgsl::BuiltinFn::kRound, CallParamType::kU32, "round"},
- /* Matrix built-in */
- BuiltinData{wgsl::BuiltinFn::kDeterminant, CallParamType::kF32, "determinant"},
- BuiltinData{wgsl::BuiltinFn::kDeterminant, CallParamType::kF16, "determinant"},
- BuiltinData{wgsl::BuiltinFn::kTranspose, CallParamType::kF32, "transpose"},
- BuiltinData{wgsl::BuiltinFn::kTranspose, CallParamType::kF16, "transpose"},
- /* Vector built-in */
- BuiltinData{wgsl::BuiltinFn::kDot, CallParamType::kF32, "dot"},
- BuiltinData{wgsl::BuiltinFn::kDot, CallParamType::kF16, "dot"},
- /* Derivate built-in */
- BuiltinData{wgsl::BuiltinFn::kDpdx, CallParamType::kF32, "ddx"},
- BuiltinData{wgsl::BuiltinFn::kDpdxCoarse, CallParamType::kF32, "ddx_coarse"},
- BuiltinData{wgsl::BuiltinFn::kDpdxFine, CallParamType::kF32, "ddx_fine"},
- BuiltinData{wgsl::BuiltinFn::kDpdy, CallParamType::kF32, "ddy"},
- BuiltinData{wgsl::BuiltinFn::kDpdyCoarse, CallParamType::kF32, "ddy_coarse"},
- BuiltinData{wgsl::BuiltinFn::kDpdyFine, CallParamType::kF32, "ddy_fine"},
- BuiltinData{wgsl::BuiltinFn::kFwidth, CallParamType::kF32, "fwidth"},
- BuiltinData{wgsl::BuiltinFn::kFwidthCoarse, CallParamType::kF32, "fwidth"},
- BuiltinData{wgsl::BuiltinFn::kFwidthFine, CallParamType::kF32, "fwidth"}));
-
-TEST_F(HlslASTPrinterTest_Builtin, Builtin_Call) {
- auto* call = Call("dot", "param1", "param2");
-
- GlobalVar("param1", ty.vec3<f32>(), core::AddressSpace::kPrivate);
- GlobalVar("param2", ty.vec3<f32>(), core::AddressSpace::kPrivate);
-
- WrapInFunction(Decl(Var("r", call)));
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "dot(param1, param2)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Select_Scalar) {
- GlobalVar("a", Expr(1_f), core::AddressSpace::kPrivate);
- GlobalVar("b", Expr(2_f), core::AddressSpace::kPrivate);
- auto* call = Call("select", "a", "b", true);
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(true ? b : a)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Select_Vector) {
- GlobalVar("a", Call<vec2<i32>>(1_i, 2_i), core::AddressSpace::kPrivate);
- GlobalVar("b", Call<vec2<i32>>(3_i, 4_i), core::AddressSpace::kPrivate);
- auto* call = Call("select", "a", "b", Call<vec2<bool>>(true, false));
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "(bool2(true, false) ? b : a)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Runtime_Modf_Scalar_f32) {
- WrapInFunction(Decl(Let("f", Expr(1.5_f))), //
- Decl(Let("v", Call("modf", "f"))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct modf_result_f32 {
- float fract;
- float whole;
-};
-modf_result_f32 tint_modf(float param_0) {
- modf_result_f32 result;
- result.fract = modf(param_0, result.whole);
- return result;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float f = 1.5f;
- modf_result_f32 v = tint_modf(f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Runtime_Modf_Scalar_f16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Decl(Let("f", Expr(1.5_h))), //
- Decl(Let("v", Call("modf", "f"))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct modf_result_f16 {
- float16_t fract;
- float16_t whole;
-};
-modf_result_f16 tint_modf(float16_t param_0) {
- modf_result_f16 result;
- result.fract = modf(param_0, result.whole);
- return result;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float16_t f = float16_t(1.5h);
- modf_result_f16 v = tint_modf(f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Runtime_Modf_Vector_f32) {
- WrapInFunction(Decl(Let("f", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f))), //
- Decl(Let("v", Call("modf", "f"))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct modf_result_vec3_f32 {
- float3 fract;
- float3 whole;
-};
-modf_result_vec3_f32 tint_modf(float3 param_0) {
- modf_result_vec3_f32 result;
- result.fract = modf(param_0, result.whole);
- return result;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float3 f = float3(1.5f, 2.5f, 3.5f);
- modf_result_vec3_f32 v = tint_modf(f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Runtime_Modf_Vector_f16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Decl(Let("f", Call<vec3<f16>>(1.5_h, 2.5_h, 3.5_h))), //
- Decl(Let("v", Call("modf", "f"))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct modf_result_vec3_f16 {
- vector<float16_t, 3> fract;
- vector<float16_t, 3> whole;
-};
-modf_result_vec3_f16 tint_modf(vector<float16_t, 3> param_0) {
- modf_result_vec3_f16 result;
- result.fract = modf(param_0, result.whole);
- return result;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- vector<float16_t, 3> f = vector<float16_t, 3>(float16_t(1.5h), float16_t(2.5h), float16_t(3.5h));
- modf_result_vec3_f16 v = tint_modf(f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Const_Modf_Scalar_f32) {
- WrapInFunction(Decl(Let("v", Call("modf", 1.5_f))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct modf_result_f32 {
- float fract;
- float whole;
-};
-[numthreads(1, 1, 1)]
-void test_function() {
- modf_result_f32 v = {0.5f, 1.0f};
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Const_Modf_Scalar_f16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Decl(Let("v", Call("modf", 1.5_h))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct modf_result_f16 {
- float16_t fract;
- float16_t whole;
-};
-[numthreads(1, 1, 1)]
-void test_function() {
- modf_result_f16 v = {float16_t(0.5h), float16_t(1.0h)};
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Const_Modf_Vector_f32) {
- WrapInFunction(Decl(Let("v", Call("modf", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f)))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct modf_result_vec3_f32 {
- float3 fract;
- float3 whole;
-};
-[numthreads(1, 1, 1)]
-void test_function() {
- modf_result_vec3_f32 v = {(0.5f).xxx, float3(1.0f, 2.0f, 3.0f)};
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Const_Modf_Vector_f16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Decl(Let("v", Call("modf", Call<vec3<f16>>(1.5_h, 2.5_h, 3.5_h)))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct modf_result_vec3_f16 {
- vector<float16_t, 3> fract;
- vector<float16_t, 3> whole;
-};
-[numthreads(1, 1, 1)]
-void test_function() {
- modf_result_vec3_f16 v = {(float16_t(0.5h)).xxx, vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h))};
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, NonInitializer_Modf_Vector_f32) {
- WrapInFunction(
- // Declare a variable with the result of a modf call.
- // This is required to infer the 'var' type.
- Decl(Var("v", Call("modf", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f)))),
- // Now assign 'v' again with another modf call.
- // This requires generating a temporary variable for the struct initializer.
- Assign("v", Call("modf", Call<vec3<f32>>(4.5_a, 5.5_a, 6.5_a))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct modf_result_vec3_f32 {
- float3 fract;
- float3 whole;
-};
-[numthreads(1, 1, 1)]
-void test_function() {
- modf_result_vec3_f32 v = {(0.5f).xxx, float3(1.0f, 2.0f, 3.0f)};
- modf_result_vec3_f32 tint_symbol = {(0.5f).xxx, float3(4.0f, 5.0f, 6.0f)};
- v = tint_symbol;
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Runtime_Frexp_Scalar_f32) {
- WrapInFunction(Var("f", Expr(1_f)), //
- Var("v", Call("frexp", "f")));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct frexp_result_f32 {
- float fract;
- int exp;
-};
-frexp_result_f32 tint_frexp(float param_0) {
- float exp;
- float fract = sign(param_0) * frexp(param_0, exp);
- frexp_result_f32 result = {fract, int(exp)};
- return result;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float f = 1.0f;
- frexp_result_f32 v = tint_frexp(f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Runtime_Frexp_Scalar_f16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Var("f", Expr(1_h)), //
- Var("v", Call("frexp", "f")));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct frexp_result_f16 {
- float16_t fract;
- int exp;
-};
-frexp_result_f16 tint_frexp(float16_t param_0) {
- float16_t exp;
- float16_t fract = sign(param_0) * frexp(param_0, exp);
- frexp_result_f16 result = {fract, int(exp)};
- return result;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float16_t f = float16_t(1.0h);
- frexp_result_f16 v = tint_frexp(f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Runtime_Frexp_Vector_f32) {
- WrapInFunction(Var("f", Call<vec3<f32>>()), //
- Var("v", Call("frexp", "f")));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct frexp_result_vec3_f32 {
- float3 fract;
- int3 exp;
-};
-frexp_result_vec3_f32 tint_frexp(float3 param_0) {
- float3 exp;
- float3 fract = sign(param_0) * frexp(param_0, exp);
- frexp_result_vec3_f32 result = {fract, int3(exp)};
- return result;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float3 f = (0.0f).xxx;
- frexp_result_vec3_f32 v = tint_frexp(f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Runtime_Frexp_Vector_f16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Var("f", Call<vec3<f16>>()), //
- Var("v", Call("frexp", "f")));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct frexp_result_vec3_f16 {
- vector<float16_t, 3> fract;
- int3 exp;
-};
-frexp_result_vec3_f16 tint_frexp(vector<float16_t, 3> param_0) {
- vector<float16_t, 3> exp;
- vector<float16_t, 3> fract = sign(param_0) * frexp(param_0, exp);
- frexp_result_vec3_f16 result = {fract, int3(exp)};
- return result;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- vector<float16_t, 3> f = (float16_t(0.0h)).xxx;
- frexp_result_vec3_f16 v = tint_frexp(f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Const_Frexp_Scalar_f32) {
- WrapInFunction(Decl(Let("v", Call("frexp", 1_f))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct frexp_result_f32 {
- float fract;
- int exp;
-};
-[numthreads(1, 1, 1)]
-void test_function() {
- frexp_result_f32 v = {0.5f, 1};
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Const_Frexp_Scalar_f16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Decl(Let("v", Call("frexp", 1_h))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct frexp_result_f16 {
- float16_t fract;
- int exp;
-};
-[numthreads(1, 1, 1)]
-void test_function() {
- frexp_result_f16 v = {float16_t(0.5h), 1};
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Const_Frexp_Vector_f32) {
- WrapInFunction(Decl(Let("v", Call("frexp", Call<vec3<f32>>()))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct frexp_result_vec3_f32 {
- float3 fract;
- int3 exp;
-};
-[numthreads(1, 1, 1)]
-void test_function() {
- frexp_result_vec3_f32 v = (frexp_result_vec3_f32)0;
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Const_Frexp_Vector_f16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Decl(Let("v", Call("frexp", Call<vec3<f16>>()))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct frexp_result_vec3_f16 {
- vector<float16_t, 3> fract;
- int3 exp;
-};
-[numthreads(1, 1, 1)]
-void test_function() {
- frexp_result_vec3_f16 v = (frexp_result_vec3_f16)0;
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, NonInitializer_Frexp_Vector_f32) {
- WrapInFunction(
- // Declare a variable with the result of a frexp call.
- // This is required to infer the 'var' type.
- Decl(Var("v", Call("frexp", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f)))),
- // Now assign 'v' again with another frexp call.
- // This requires generating a temporary variable for the struct initializer.
- Assign("v", Call("frexp", Call<vec3<f32>>(4.5_a, 5.5_a, 6.5_a))));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct frexp_result_vec3_f32 {
- float3 fract;
- int3 exp;
-};
-[numthreads(1, 1, 1)]
-void test_function() {
- frexp_result_vec3_f32 v = {float3(0.75f, 0.625f, 0.875f), int3(1, 2, 2)};
- frexp_result_vec3_f32 tint_symbol = {float3(0.5625f, 0.6875f, 0.8125f), (3).xxx};
- v = tint_symbol;
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Degrees_Scalar_f32) {
- auto* val = Var("val", ty.f32());
- auto* call = Call("degrees", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float tint_degrees(float param_0) {
- return param_0 * 57.29577951308232286465;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float val = 0.0f;
- float tint_symbol = tint_degrees(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Degrees_Vector_f32) {
- auto* val = Var("val", ty.vec3<f32>());
- auto* call = Call("degrees", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float3 tint_degrees(float3 param_0) {
- return param_0 * 57.29577951308232286465;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float3 val = float3(0.0f, 0.0f, 0.0f);
- float3 tint_symbol = tint_degrees(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Degrees_Scalar_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* val = Var("val", ty.f16());
- auto* call = Call("degrees", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float16_t tint_degrees(float16_t param_0) {
- return param_0 * 57.29577951308232286465;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float16_t val = float16_t(0.0h);
- float16_t tint_symbol = tint_degrees(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Degrees_Vector_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* val = Var("val", ty.vec3<f16>());
- auto* call = Call("degrees", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(vector<float16_t, 3> tint_degrees(vector<float16_t, 3> param_0) {
- return param_0 * 57.29577951308232286465;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- vector<float16_t, 3> val = vector<float16_t, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
- vector<float16_t, 3> tint_symbol = tint_degrees(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Radians_Scalar_f32) {
- auto* val = Var("val", ty.f32());
- auto* call = Call("radians", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float tint_radians(float param_0) {
- return param_0 * 0.01745329251994329547;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float val = 0.0f;
- float tint_symbol = tint_radians(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Radians_Vector_f32) {
- auto* val = Var("val", ty.vec3<f32>());
- auto* call = Call("radians", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float3 tint_radians(float3 param_0) {
- return param_0 * 0.01745329251994329547;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float3 val = float3(0.0f, 0.0f, 0.0f);
- float3 tint_symbol = tint_radians(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Radians_Scalar_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* val = Var("val", ty.f16());
- auto* call = Call("radians", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float16_t tint_radians(float16_t param_0) {
- return param_0 * 0.01745329251994329547;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float16_t val = float16_t(0.0h);
- float16_t tint_symbol = tint_radians(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Radians_Vector_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* val = Var("val", ty.vec3<f16>());
- auto* call = Call("radians", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(vector<float16_t, 3> tint_radians(vector<float16_t, 3> param_0) {
- return param_0 * 0.01745329251994329547;
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- vector<float16_t, 3> val = vector<float16_t, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
- vector<float16_t, 3> tint_symbol = tint_radians(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Sign_Scalar_i32) {
- auto* val = Var("val", ty.i32());
- auto* call = Call("sign", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(1, 1, 1)]
-void test_function() {
- int val = 0;
- int tint_symbol = int(sign(val));
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Sign_Vector_i32) {
- auto* val = Var("val", ty.vec3<i32>());
- auto* call = Call("sign", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(1, 1, 1)]
-void test_function() {
- int3 val = int3(0, 0, 0);
- int3 tint_symbol = int3(sign(val));
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Sign_Scalar_f32) {
- auto* val = Var("val", ty.f32());
- auto* call = Call("sign", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(1, 1, 1)]
-void test_function() {
- float val = 0.0f;
- float tint_symbol = float(sign(val));
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Sign_Vector_f32) {
- auto* val = Var("val", ty.vec3<f32>());
- auto* call = Call("sign", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(1, 1, 1)]
-void test_function() {
- float3 val = float3(0.0f, 0.0f, 0.0f);
- float3 tint_symbol = float3(sign(val));
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Sign_Scalar_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* val = Var("val", ty.f16());
- auto* call = Call("sign", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(1, 1, 1)]
-void test_function() {
- float16_t val = float16_t(0.0h);
- float16_t tint_symbol = float16_t(sign(val));
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Sign_Vector_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* val = Var("val", ty.vec3<f16>());
- auto* call = Call("sign", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(1, 1, 1)]
-void test_function() {
- vector<float16_t, 3> val = vector<float16_t, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
- vector<float16_t, 3> tint_symbol = vector<float16_t, 3>(sign(val));
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Trunc_Scalar_f32) {
- auto* val = Var("val", ty.f32());
- auto* call = Call("trunc", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float tint_trunc(float param_0) {
- return param_0 < 0 ? ceil(param_0) : floor(param_0);
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float val = 0.0f;
- float tint_symbol = tint_trunc(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Trunc_Vector_f32) {
- auto* val = Var("val", ty.vec3<f32>());
- auto* call = Call("trunc", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float3 tint_trunc(float3 param_0) {
- return param_0 < 0 ? ceil(param_0) : floor(param_0);
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float3 val = float3(0.0f, 0.0f, 0.0f);
- float3 tint_symbol = tint_trunc(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Trunc_Scalar_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* val = Var("val", ty.f16());
- auto* call = Call("trunc", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float16_t tint_trunc(float16_t param_0) {
- return param_0 < 0 ? ceil(param_0) : floor(param_0);
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float16_t val = float16_t(0.0h);
- float16_t tint_symbol = tint_trunc(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Trunc_Vector_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* val = Var("val", ty.vec3<f16>());
- auto* call = Call("trunc", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(vector<float16_t, 3> tint_trunc(vector<float16_t, 3> param_0) {
- return param_0 < 0 ? ceil(param_0) : floor(param_0);
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- vector<float16_t, 3> val = vector<float16_t, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
- vector<float16_t, 3> tint_symbol = tint_trunc(val);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Pack4x8Snorm) {
- auto* call = Call("pack4x8snorm", "p1");
- GlobalVar("p1", ty.vec4<f32>(), core::AddressSpace::kPrivate);
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(uint tint_pack4x8snorm(float4 param_0) {
- int4 i = int4(round(clamp(param_0, -1.0, 1.0) * 127.0)) & 0xff;
- return asuint(i.x | i.y << 8 | i.z << 16 | i.w << 24);
-}
-
-static float4 p1 = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-[numthreads(1, 1, 1)]
-void test_function() {
- uint r = tint_pack4x8snorm(p1);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Pack4x8Unorm) {
- auto* call = Call("pack4x8unorm", "p1");
- GlobalVar("p1", ty.vec4<f32>(), core::AddressSpace::kPrivate);
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(uint tint_pack4x8unorm(float4 param_0) {
- uint4 i = uint4(round(clamp(param_0, 0.0, 1.0) * 255.0));
- return (i.x | i.y << 8 | i.z << 16 | i.w << 24);
-}
-
-static float4 p1 = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-[numthreads(1, 1, 1)]
-void test_function() {
- uint r = tint_pack4x8unorm(p1);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Pack2x16Snorm) {
- auto* call = Call("pack2x16snorm", "p1");
- GlobalVar("p1", ty.vec2<f32>(), core::AddressSpace::kPrivate);
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(uint tint_pack2x16snorm(float2 param_0) {
- int2 i = int2(round(clamp(param_0, -1.0, 1.0) * 32767.0)) & 0xffff;
- return asuint(i.x | i.y << 16);
-}
-
-static float2 p1 = float2(0.0f, 0.0f);
-
-[numthreads(1, 1, 1)]
-void test_function() {
- uint r = tint_pack2x16snorm(p1);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Pack2x16Unorm) {
- auto* call = Call("pack2x16unorm", "p1");
- GlobalVar("p1", ty.vec2<f32>(), core::AddressSpace::kPrivate);
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(uint tint_pack2x16unorm(float2 param_0) {
- uint2 i = uint2(round(clamp(param_0, 0.0, 1.0) * 65535.0));
- return (i.x | i.y << 16);
-}
-
-static float2 p1 = float2(0.0f, 0.0f);
-
-[numthreads(1, 1, 1)]
-void test_function() {
- uint r = tint_pack2x16unorm(p1);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Pack2x16Float) {
- auto* call = Call("pack2x16float", "p1");
- GlobalVar("p1", ty.vec2<f32>(), core::AddressSpace::kPrivate);
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(uint tint_pack2x16float(float2 param_0) {
- uint2 i = f32tof16(param_0);
- return i.x | (i.y << 16);
-}
-
-static float2 p1 = float2(0.0f, 0.0f);
-
-[numthreads(1, 1, 1)]
-void test_function() {
- uint r = tint_pack2x16float(p1);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Unpack4x8Snorm) {
- auto* call = Call("unpack4x8snorm", "p1");
- GlobalVar("p1", ty.u32(), core::AddressSpace::kPrivate);
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float4 tint_unpack4x8snorm(uint param_0) {
- int j = int(param_0);
- int4 i = int4(j << 24, j << 16, j << 8, j) >> 24;
- return clamp(float4(i) / 127.0, -1.0, 1.0);
-}
-
-static uint p1 = 0u;
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float4 r = tint_unpack4x8snorm(p1);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Unpack4x8Unorm) {
- auto* call = Call("unpack4x8unorm", "p1");
- GlobalVar("p1", ty.u32(), core::AddressSpace::kPrivate);
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float4 tint_unpack4x8unorm(uint param_0) {
- uint j = param_0;
- uint4 i = uint4(j & 0xff, (j >> 8) & 0xff, (j >> 16) & 0xff, j >> 24);
- return float4(i) / 255.0;
-}
-
-static uint p1 = 0u;
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float4 r = tint_unpack4x8unorm(p1);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Unpack2x16Snorm) {
- auto* call = Call("unpack2x16snorm", "p1");
- GlobalVar("p1", ty.u32(), core::AddressSpace::kPrivate);
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float2 tint_unpack2x16snorm(uint param_0) {
- int j = int(param_0);
- int2 i = int2(j << 16, j) >> 16;
- return clamp(float2(i) / 32767.0, -1.0, 1.0);
-}
-
-static uint p1 = 0u;
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float2 r = tint_unpack2x16snorm(p1);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Unpack2x16Unorm) {
- auto* call = Call("unpack2x16unorm", "p1");
- GlobalVar("p1", ty.u32(), core::AddressSpace::kPrivate);
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float2 tint_unpack2x16unorm(uint param_0) {
- uint j = param_0;
- uint2 i = uint2(j & 0xffff, j >> 16);
- return float2(i) / 65535.0;
-}
-
-static uint p1 = 0u;
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float2 r = tint_unpack2x16unorm(p1);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Unpack2x16Float) {
- auto* call = Call("unpack2x16float", "p1");
- GlobalVar("p1", ty.u32(), core::AddressSpace::kPrivate);
- WrapInFunction(Decl(Var("r", call)));
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float2 tint_unpack2x16float(uint param_0) {
- uint i = param_0;
- return f16tof32(uint2(i & 0xffff, i >> 16));
-}
-
-static uint p1 = 0u;
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float2 r = tint_unpack2x16float(p1);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, StorageBarrier) {
- Func("main", tint::Empty, ty.void_(),
- Vector{
- CallStmt(Call("storageBarrier")),
- },
- Vector{
- Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(1_i),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(1, 1, 1)]
-void main() {
- DeviceMemoryBarrierWithGroupSync();
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, WorkgroupBarrier) {
- Func("main", tint::Empty, ty.void_(),
- Vector{
- CallStmt(Call("workgroupBarrier")),
- },
- Vector{
- Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(1_i),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(1, 1, 1)]
-void main() {
- GroupMemoryBarrierWithGroupSync();
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Dot4I8Packed) {
- Require(wgsl::LanguageFeature::kPacked4X8IntegerDotProduct);
-
- auto* val1 = Var("val1", ty.u32());
- auto* val2 = Var("val2", ty.u32());
- auto* call = Call("dot4I8Packed", val1, val2);
- WrapInFunction(val1, val2, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(int tint_dot4I8Packed(uint param_0, uint param_1) {
- int accumulator = 0;
- return dot4add_i8packed(param_0, param_1, accumulator);
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- uint val1 = 0u;
- uint val2 = 0u;
- int tint_symbol = tint_dot4I8Packed(val1, val2);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, Dot4U8Packed) {
- Require(wgsl::LanguageFeature::kPacked4X8IntegerDotProduct);
-
- auto* val1 = Var("val1", ty.u32());
- auto* val2 = Var("val2", ty.u32());
- auto* call = Call("dot4U8Packed", val1, val2);
- WrapInFunction(val1, val2, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(uint tint_dot4U8Packed(uint param_0, uint param_1) {
- uint accumulator = 0u;
- return dot4add_u8packed(param_0, param_1, accumulator);
-}
-
-[numthreads(1, 1, 1)]
-void test_function() {
- uint val1 = 0u;
- uint val2 = 0u;
- uint tint_symbol = tint_dot4U8Packed(val1, val2);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, CountOneBits) {
- auto* val = Var("val1", ty.i32());
- auto* call = Call("countOneBits", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(1, 1, 1)]
-void test_function() {
- int val1 = 0;
- int tint_symbol = asint(countbits(asuint(val1)));
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Builtin, ReverseBits) {
- auto* val = Var("val1", ty.i32());
- auto* call = Call("reverseBits", val);
- WrapInFunction(val, call);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(1, 1, 1)]
-void test_function() {
- int val1 = 0;
- int tint_symbol = asint(reversebits(asuint(val1)));
- return;
-}
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/builtin_texture_test.cc b/src/tint/lang/hlsl/writer/ast_printer/builtin_texture_test.cc
deleted file mode 100644
index ef0918f..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/builtin_texture_test.cc
+++ /dev/null
@@ -1,409 +0,0 @@
-// Copyright 2020 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 "gmock/gmock.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/lang/wgsl/ast/builtin_texture_helper_test.h"
-#include "src/tint/lang/wgsl/ast/call_statement.h"
-#include "src/tint/lang/wgsl/ast/stage_attribute.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using ::testing::HasSubstr;
-
-struct ExpectedResult {
- ExpectedResult(const char* o) : out(o) {} // NOLINT
- ExpectedResult(const char* p, const char* o) : pre(p), out(o) {}
-
- std::string pre;
- std::string out;
-};
-
-ExpectedResult expected_texture_overload(ast::test::ValidTextureOverload overload) {
- using ValidTextureOverload = ast::test::ValidTextureOverload;
- switch (overload) {
- case ValidTextureOverload::kDimensions1d:
- case ValidTextureOverload::kDimensionsStorageWO1d:
- return {
- R"(int tint_tmp;
- tint_symbol.GetDimensions(tint_tmp);
-)",
- "tint_tmp;",
- };
- case ValidTextureOverload::kDimensions2d:
- case ValidTextureOverload::kDimensionsDepth2d:
- case ValidTextureOverload::kDimensionsStorageWO2d:
- return {
- R"(int2 tint_tmp;
- tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y);
-)",
- "tint_tmp;",
- };
- case ValidTextureOverload::kDimensionsDepthMultisampled2d:
- case ValidTextureOverload::kDimensionsMultisampled2d:
- return {
- R"(int3 tint_tmp;
- tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
-)",
- "tint_tmp.xy;",
- };
-
- case ValidTextureOverload::kDimensions2dArray:
- case ValidTextureOverload::kDimensionsDepth2dArray:
- case ValidTextureOverload::kDimensionsStorageWO2dArray:
- return {
- R"(int3 tint_tmp;
- tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
-)",
- "tint_tmp.xy;",
- };
- case ValidTextureOverload::kDimensions3d:
- case ValidTextureOverload::kDimensionsStorageWO3d:
- return {
- R"(int3 tint_tmp;
- tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
-)",
- "tint_tmp;",
- };
- case ValidTextureOverload::kDimensionsCube:
- case ValidTextureOverload::kDimensionsDepthCube:
- return {
- R"(int2 tint_tmp;
- tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y);
-)",
- "tint_tmp;",
- };
- case ValidTextureOverload::kDimensionsCubeArray:
- case ValidTextureOverload::kDimensionsDepthCubeArray:
- return {
- R"(int3 tint_tmp;
- tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
-)",
- "tint_tmp.xy;",
- };
- case ValidTextureOverload::kDimensions2dLevel:
- case ValidTextureOverload::kDimensionsDepth2dLevel:
- return {
- R"(int3 tint_tmp;
- tint_symbol.GetDimensions(1, tint_tmp.x, tint_tmp.y, tint_tmp.z);
-)",
- "tint_tmp.xy;",
- };
- case ValidTextureOverload::kDimensions2dArrayLevel:
- case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
- return {
- R"(int4 tint_tmp;
- tint_symbol.GetDimensions(1, tint_tmp.x, tint_tmp.y, tint_tmp.z, tint_tmp.w);
-)",
- "tint_tmp.xy;",
- };
- case ValidTextureOverload::kDimensions3dLevel:
- return {
- R"(int4 tint_tmp;
- tint_symbol.GetDimensions(1, tint_tmp.x, tint_tmp.y, tint_tmp.z, tint_tmp.w);
-)",
- "tint_tmp.xyz;",
- };
- case ValidTextureOverload::kDimensionsCubeLevel:
- case ValidTextureOverload::kDimensionsDepthCubeLevel:
- return {
- R"(int3 tint_tmp;
- tint_symbol.GetDimensions(1, tint_tmp.x, tint_tmp.y, tint_tmp.z);
-)",
- "tint_tmp.xy;",
- };
- case ValidTextureOverload::kDimensionsCubeArrayLevel:
- case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
- return {
- R"(int4 tint_tmp;
- tint_symbol.GetDimensions(1, tint_tmp.x, tint_tmp.y, tint_tmp.z, tint_tmp.w);
-)",
- "tint_tmp.xy;",
- };
- case ValidTextureOverload::kGather2dF32:
- return R"(tint_symbol.GatherRed(tint_symbol_1, float2(1.0f, 2.0f)))";
- case ValidTextureOverload::kGather2dOffsetF32:
- return R"(tint_symbol.GatherRed(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4)))";
- case ValidTextureOverload::kGather2dArrayF32:
- return R"(tint_symbol.GatherRed(tint_symbol_1, float3(1.0f, 2.0f, float(3))))";
- case ValidTextureOverload::kGather2dArrayOffsetF32:
- return R"(tint_symbol.GatherRed(tint_symbol_1, float3(1.0f, 2.0f, float(3u)), int2(4, 5)))";
- case ValidTextureOverload::kGatherCubeF32:
- return R"(tint_symbol.GatherRed(tint_symbol_1, float3(1.0f, 2.0f, 3.0f)))";
- case ValidTextureOverload::kGatherCubeArrayF32:
- return R"(tint_symbol.GatherRed(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4u))))";
- case ValidTextureOverload::kGatherDepth2dF32:
- return R"(tint_symbol.Gather(tint_symbol_1, float2(1.0f, 2.0f)))";
- case ValidTextureOverload::kGatherDepth2dOffsetF32:
- return R"(tint_symbol.Gather(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4)))";
- case ValidTextureOverload::kGatherDepth2dArrayF32:
- return R"(tint_symbol.Gather(tint_symbol_1, float3(1.0f, 2.0f, float(3u))))";
- case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
- return R"(tint_symbol.Gather(tint_symbol_1, float3(1.0f, 2.0f, float(3)), int2(4, 5)))";
- case ValidTextureOverload::kGatherDepthCubeF32:
- return R"(tint_symbol.Gather(tint_symbol_1, float3(1.0f, 2.0f, 3.0f)))";
- case ValidTextureOverload::kGatherDepthCubeArrayF32:
- return R"(tint_symbol.Gather(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4u))))";
- case ValidTextureOverload::kGatherCompareDepth2dF32:
- return R"(tint_symbol.GatherCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f))";
- case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
- return R"(tint_symbol.GatherCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5)))";
- case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
- return R"(tint_symbol.GatherCmp(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f))";
- case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
- return R"(tint_symbol.GatherCmp(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f, int2(5, 6)))";
- case ValidTextureOverload::kGatherCompareDepthCubeF32:
- return R"(tint_symbol.GatherCmp(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f))";
- case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
- return R"(tint_symbol.GatherCmp(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4u)), 5.0f))";
- case ValidTextureOverload::kNumLayers2dArray:
- case ValidTextureOverload::kNumLayersDepth2dArray:
- case ValidTextureOverload::kNumLayersCubeArray:
- case ValidTextureOverload::kNumLayersDepthCubeArray:
- case ValidTextureOverload::kNumLayersStorageWO2dArray:
- return {
- R"(int3 tint_tmp;
- tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
-)",
- "tint_tmp.z;",
- };
- case ValidTextureOverload::kNumLevels2d:
- case ValidTextureOverload::kNumLevelsCube:
- case ValidTextureOverload::kNumLevelsDepth2d:
- case ValidTextureOverload::kNumLevelsDepthCube:
- return {
- R"(int3 tint_tmp;
- tint_symbol.GetDimensions(0, tint_tmp.x, tint_tmp.y, tint_tmp.z);
-)",
- "tint_tmp.z;",
- };
- case ValidTextureOverload::kNumLevels2dArray:
- case ValidTextureOverload::kNumLevels3d:
- case ValidTextureOverload::kNumLevelsCubeArray:
- case ValidTextureOverload::kNumLevelsDepth2dArray:
- case ValidTextureOverload::kNumLevelsDepthCubeArray:
- return {
- R"(int4 tint_tmp;
- tint_symbol.GetDimensions(0, tint_tmp.x, tint_tmp.y, tint_tmp.z, tint_tmp.w);
-)",
- "tint_tmp.w;",
- };
- case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
- case ValidTextureOverload::kNumSamplesMultisampled2d:
- return {
- R"(int3 tint_tmp;
- tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
-)",
- "tint_tmp.z;",
- };
- case ValidTextureOverload::kSample1dF32:
- return R"(tint_symbol.Sample(tint_symbol_1, 1.0f);)";
- case ValidTextureOverload::kSample2dF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f));)";
- case ValidTextureOverload::kSample2dOffsetF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4));)";
- case ValidTextureOverload::kSample2dArrayF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3)));)";
- case ValidTextureOverload::kSample2dArrayOffsetF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3u)), int2(4, 5));)";
- case ValidTextureOverload::kSample3dF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f));)";
- case ValidTextureOverload::kSample3dOffsetF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), int3(4, 5, 6));)";
- case ValidTextureOverload::kSampleCubeF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f));)";
- case ValidTextureOverload::kSampleCubeArrayF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)));)";
- case ValidTextureOverload::kSampleDepth2dF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f)).x;)";
- case ValidTextureOverload::kSampleDepth2dOffsetF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4)).x;)";
- case ValidTextureOverload::kSampleDepth2dArrayF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3))).x;)";
- case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3)), int2(4, 5)).x;)";
- case ValidTextureOverload::kSampleDepthCubeF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f)).x;)";
- case ValidTextureOverload::kSampleDepthCubeArrayF32:
- return R"(tint_symbol.Sample(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4u))).x;)";
- case ValidTextureOverload::kSampleBias2dF32:
- return R"(tint_symbol.SampleBias(tint_symbol_1, float2(1.0f, 2.0f), clamp(3.0f, -16.0f, 15.99f));)";
- case ValidTextureOverload::kSampleBias2dOffsetF32:
- return R"(tint_symbol.SampleBias(tint_symbol_1, float2(1.0f, 2.0f), clamp(3.0f, -16.0f, 15.99f), int2(4, 5));)";
- case ValidTextureOverload::kSampleBias2dArrayF32:
- return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, float(4u)), clamp(3.0f, -16.0f, 15.99f));)";
- case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
- return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, float(3)), clamp(4.0f, -16.0f, 15.99f), int2(5, 6));)";
- case ValidTextureOverload::kSampleBias3dF32:
- return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), clamp(4.0f, -16.0f, 15.99f));)";
- case ValidTextureOverload::kSampleBias3dOffsetF32:
- return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), clamp(4.0f, -16.0f, 15.99f), int3(5, 6, 7));)";
- case ValidTextureOverload::kSampleBiasCubeF32:
- return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), clamp(4.0f, -16.0f, 15.99f));)";
- case ValidTextureOverload::kSampleBiasCubeArrayF32:
- return R"(tint_symbol.SampleBias(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(3)), clamp(4.0f, -16.0f, 15.99f));)";
- case ValidTextureOverload::kSampleLevel2dF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3.0f);)";
- case ValidTextureOverload::kSampleLevel2dOffsetF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5));)";
- case ValidTextureOverload::kSampleLevel2dArrayF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f);)";
- case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f, int2(5, 6));)";
- case ValidTextureOverload::kSampleLevel3dF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
- case ValidTextureOverload::kSampleLevel3dOffsetF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f, int3(5, 6, 7));)";
- case ValidTextureOverload::kSampleLevelCubeF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
- case ValidTextureOverload::kSampleLevelCubeArrayF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
- case ValidTextureOverload::kSampleLevelDepth2dF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3u).x;)";
- case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3, int2(4, 5)).x;)";
- case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3u)), 4u).x;)";
- case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3u)), 4u, int2(5, 6)).x;)";
- case ValidTextureOverload::kSampleLevelDepthCubeF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4).x;)";
- case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
- return R"(tint_symbol.SampleLevel(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5).x;)";
- case ValidTextureOverload::kSampleGrad2dF32:
- return R"(tint_symbol.SampleGrad(tint_symbol_1, float2(1.0f, 2.0f), float2(3.0f, 4.0f), float2(5.0f, 6.0f));)";
- case ValidTextureOverload::kSampleGrad2dOffsetF32:
- return R"(tint_symbol.SampleGrad(tint_symbol_1, float2(1.0f, 2.0f), float2(3.0f, 4.0f), float2(5.0f, 6.0f), int2((7).xx));)";
- case ValidTextureOverload::kSampleGrad2dArrayF32:
- return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, float(3)), float2(4.0f, 5.0f), float2(6.0f, 7.0f));)";
- case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
- return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, float(3u)), float2(4.0f, 5.0f), float2(6.0f, 7.0f), int2(6, 7));)";
- case ValidTextureOverload::kSampleGrad3dF32:
- return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));)";
- case ValidTextureOverload::kSampleGrad3dOffsetF32:
- return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f), int3(0, 1, 2));)";
- case ValidTextureOverload::kSampleGradCubeF32:
- return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));)";
- case ValidTextureOverload::kSampleGradCubeArrayF32:
- return R"(tint_symbol.SampleGrad(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4u)), float3(5.0f, 6.0f, 7.0f), float3(8.0f, 9.0f, 10.0f));)";
- case ValidTextureOverload::kSampleCompareDepth2dF32:
- return R"(tint_symbol.SampleCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f);)";
- case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
- return R"(tint_symbol.SampleCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5));)";
- case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
- return R"(tint_symbol.SampleCmp(tint_symbol_1, float3(1.0f, 2.0f, float(4)), 3.0f);)";
- case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
- return R"(tint_symbol.SampleCmp(tint_symbol_1, float3(1.0f, 2.0f, float(4u)), 3.0f, int2(5, 6));)";
- case ValidTextureOverload::kSampleCompareDepthCubeF32:
- return R"(tint_symbol.SampleCmp(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
- case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
- return R"(tint_symbol.SampleCmp(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
- case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
- return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float2(1.0f, 2.0f), 3.0f);)";
- case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
- return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5));)";
- case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
- return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f);)";
- case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
- return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f, int2(5, 6));)";
- case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
- return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
- case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
- return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
- case ValidTextureOverload::kLoad1dLevelF32:
- return R"(tint_symbol.Load(uint2(1u, 3u));)";
- case ValidTextureOverload::kLoad1dLevelU32:
- case ValidTextureOverload::kLoad1dLevelI32:
- return R"(tint_symbol.Load(int2(1, 3));)";
- case ValidTextureOverload::kLoad2dLevelU32:
- return R"(tint_symbol.Load(int3(1, 2, 3));)";
- case ValidTextureOverload::kLoad2dLevelF32:
- case ValidTextureOverload::kLoad2dLevelI32:
- return R"(tint_symbol.Load(uint3(1u, 2u, 3u));)";
- case ValidTextureOverload::kLoad2dArrayLevelF32:
- case ValidTextureOverload::kLoad2dArrayLevelU32:
- case ValidTextureOverload::kLoad3dLevelF32:
- case ValidTextureOverload::kLoad3dLevelU32:
- return R"(tint_symbol.Load(int4(1, 2, 3, 4));)";
- case ValidTextureOverload::kLoad2dArrayLevelI32:
- case ValidTextureOverload::kLoad3dLevelI32:
- return R"(tint_symbol.Load(uint4(1u, 2u, 3u, 4u));)";
- case ValidTextureOverload::kLoadMultisampled2dF32:
- case ValidTextureOverload::kLoadMultisampled2dU32:
- return R"(tint_symbol.Load(int2(1, 2), 3);)";
- case ValidTextureOverload::kLoadMultisampled2dI32:
- return R"(tint_symbol.Load(uint2(1u, 2u), 3u);)";
- case ValidTextureOverload::kLoadDepth2dLevelF32:
- return R"(tint_symbol.Load(int3(1, 2, 3)).x;)";
- case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
- return R"(tint_symbol.Load(uint4(1u, 2u, 3u, 4u)).x;)";
- case ValidTextureOverload::kLoadDepthMultisampled2dF32:
- return R"(tint_symbol.Load(uint3(1u, 2u, uint(0)), 3u).x;)";
- case ValidTextureOverload::kStoreWO1dRgba32float:
- return R"(tint_symbol[1] = float4(2.0f, 3.0f, 4.0f, 5.0f);)";
- case ValidTextureOverload::kStoreWO2dRgba32float:
- return R"(tint_symbol[int2(1, 2)] = float4(3.0f, 4.0f, 5.0f, 6.0f);)";
- case ValidTextureOverload::kStoreWO2dArrayRgba32float:
- return R"(tint_symbol[uint3(1u, 2u, 3u)] = float4(4.0f, 5.0f, 6.0f, 7.0f);)";
- case ValidTextureOverload::kStoreWO3dRgba32float:
- return R"(tint_symbol[uint3(1u, 2u, 3u)] = float4(4.0f, 5.0f, 6.0f, 7.0f);)";
- }
- return "<unmatched texture overload>";
-} // NOLINT - Ignore the length of this function
-
-class HlslGeneratorBuiltinTextureTest : public TestParamHelper<ast::test::TextureOverloadCase> {};
-
-TEST_P(HlslGeneratorBuiltinTextureTest, Call) {
- auto param = GetParam();
-
- param.BuildTextureVariable(this);
- param.BuildSamplerVariable(this);
-
- auto* call = Call(param.function, param.args(this));
- auto* stmt = param.returns_value ? static_cast<const ast::Statement*>(Decl(Var("v", call)))
- : static_cast<const ast::Statement*>(CallStmt(call));
-
- Func("main", tint::Empty, ty.void_(), Vector{stmt},
- Vector{Stage(ast::PipelineStage::kFragment)});
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- auto expected = expected_texture_overload(param.overload);
-
- EXPECT_THAT(gen.Result(), HasSubstr(expected.pre));
- EXPECT_THAT(gen.Result(), HasSubstr(expected.out));
-}
-
-INSTANTIATE_TEST_SUITE_P(HlslGeneratorBuiltinTextureTest,
- HlslGeneratorBuiltinTextureTest,
- testing::ValuesIn(ast::test::TextureOverloadCase::ValidCases()));
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/call_test.cc b/src/tint/lang/hlsl/writer/ast_printer/call_test.cc
deleted file mode 100644
index fbffc01..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/call_test.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/lang/wgsl/ast/call_statement.h"
-#include "src/tint/utils/text/string_stream.h"
-
-using namespace tint::core::number_suffixes; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Call = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Call, EmitExpression_Call_WithoutParams) {
- Func("my_func", tint::Empty, ty.f32(), Vector{Return(1.23_f)});
-
- auto* call = Call("my_func");
- WrapInFunction(call);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "my_func()");
-}
-
-TEST_F(HlslASTPrinterTest_Call, EmitExpression_Call_WithParams) {
- Func("my_func",
- Vector{
- Param(Sym(), ty.f32()),
- Param(Sym(), ty.f32()),
- },
- ty.f32(), Vector{Return(1.23_f)});
- GlobalVar("param1", ty.f32(), core::AddressSpace::kPrivate);
- GlobalVar("param2", ty.f32(), core::AddressSpace::kPrivate);
-
- auto* call = Call("my_func", "param1", "param2");
- WrapInFunction(call);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "my_func(param1, param2)");
-}
-
-TEST_F(HlslASTPrinterTest_Call, EmitStatement_Call) {
- Func("my_func",
- Vector{
- Param(Sym(), ty.f32()),
- Param(Sym(), ty.f32()),
- },
- ty.void_(), tint::Empty, tint::Empty);
- GlobalVar("param1", ty.f32(), core::AddressSpace::kPrivate);
- GlobalVar("param2", ty.f32(), core::AddressSpace::kPrivate);
-
- auto* call = CallStmt(Call("my_func", "param1", "param2"));
- WrapInFunction(call);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
- ASSERT_TRUE(gen.EmitStatement(call)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), " my_func(param1, param2);\n");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/case_test.cc b/src/tint/lang/hlsl/writer/ast_printer/case_test.cc
deleted file mode 100644
index 82bafe9..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/case_test.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-
-using namespace tint::core::number_suffixes; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Case = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Case, Emit_Case) {
- auto* s =
- Switch(1_i, Case(CaseSelector(5_i), Block(create<ast::BreakStatement>())), DefaultCase());
- WrapInFunction(s);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( case 5: {
- break;
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Case, Emit_Case_BreaksByDefault) {
- auto* s = Switch(1_i, Case(CaseSelector(5_i), Block()), DefaultCase());
- WrapInFunction(s);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( case 5: {
- break;
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Case, Emit_Case_MultipleSelectors) {
- auto* s = Switch(
- 1_i,
- Case(Vector{CaseSelector(5_i), CaseSelector(6_i)}, Block(create<ast::BreakStatement>())),
- DefaultCase());
- WrapInFunction(s);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( case 5:
- case 6: {
- break;
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Case, Emit_Case_Default) {
- auto* s = Switch(1_i, DefaultCase(Block(create<ast::BreakStatement>())));
- WrapInFunction(s);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitCase(s, 0u)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( default: {
- break;
- }
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/cast_test.cc b/src/tint/lang/hlsl/writer/ast_printer/cast_test.cc
deleted file mode 100644
index 739a364..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/cast_test.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/utils/text/string_stream.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-using HlslASTPrinterTest_Cast = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Cast, EmitExpression_Cast_Scalar) {
- auto* cast = Call<f32>(1_i);
- WrapInFunction(cast);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "1.0f");
-}
-
-TEST_F(HlslASTPrinterTest_Cast, EmitExpression_Cast_Vector) {
- auto* cast = Call<vec3<f32>>(Call<vec3<i32>>(1_i, 2_i, 3_i));
- WrapInFunction(cast);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "float3(1.0f, 2.0f, 3.0f)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/const_assert_test.cc b/src/tint/lang/hlsl/writer/ast_printer/const_assert_test.cc
deleted file mode 100644
index 3b4c728..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/const_assert_test.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2022 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/hlsl/writer/ast_printer/helper_test.h"
-
-using namespace tint::core::number_suffixes; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest = TestHelper;
-
-TEST_F(HlslASTPrinterTest, Emit_GlobalConstAssert) {
- GlobalConstAssert(true);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- // const asserts are not emitted
- EXPECT_EQ(gen.Result(), "");
-}
-
-TEST_F(HlslASTPrinterTest, Emit_FunctionConstAssert) {
- Func("f", tint::Empty, ty.void_(), Vector{ConstAssert(true)});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- // const asserts are not emitted
- EXPECT_EQ(gen.Result(), R"(void f() {
-}
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/constructor_test.cc b/src/tint/lang/hlsl/writer/ast_printer/constructor_test.cc
deleted file mode 100644
index 5a9a9a3..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/constructor_test.cc
+++ /dev/null
@@ -1,465 +0,0 @@
-// Copyright 2020 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 "gmock/gmock.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/helper_test.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using ::testing::HasSubstr;
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-using HlslASTPrinterTest_Constructor = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Constructor, Bool) {
- WrapInFunction(Expr(false));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("false"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Int) {
- WrapInFunction(Expr(-12345_i));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("-12345"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, UInt) {
- WrapInFunction(Expr(56779_u));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("56779u"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Float) {
- // Use a number close to 1<<30 but whose decimal representation ends in 0.
- WrapInFunction(Expr(f32((1 << 30) - 4)));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("1073741824.0f"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, F16) {
- Enable(wgsl::Extension::kF16);
-
- // Use a number close to 1<<16 but whose decimal representation ends in 0.
- WrapInFunction(Expr(f16((1 << 15) - 8)));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("float16_t(32752.0h)"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Float) {
- WrapInFunction(Call<f32>(-1.2e-5_f));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("-0.00001200000042445026f"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_F16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Call<f16>(-1.2e-3_h));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("float16_t(-0.0011997222900390625h)"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Bool) {
- WrapInFunction(Call<bool>(true));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("true"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Int) {
- WrapInFunction(Call<i32>(-12345_i));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("-12345"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Uint) {
- WrapInFunction(Call<u32>(12345_u));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("12345u"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_F32) {
- WrapInFunction(Call<vec3<f32>>(1_f, 2_f, 3_f));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("float3(1.0f, 2.0f, 3.0f)"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_F16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Call<vec3<f16>>(1_h, 2_h, 3_h));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(
- gen.Result(),
- HasSubstr("vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h))"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_Empty_F32) {
- WrapInFunction(Call<vec3<f32>>());
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("0.0f).xxx"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_Empty_F16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Call<vec3<f16>>());
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("(float16_t(0.0h)).xxx"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_SingleScalar_F32_Literal) {
- WrapInFunction(Call<vec3<f32>>(2_f));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("2.0f).xxx"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_SingleScalar_F16_Literal) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Call<vec3<f16>>(2_h));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("(float16_t(2.0h)).xxx"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_SingleScalar_F32_Var) {
- auto* var = Var("v", Expr(2_f));
- auto* cast = Call<vec3<f32>>(var);
- WrapInFunction(var, cast);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(R"(float v = 2.0f;
- float3 tint_symbol = float3((v).xxx);)"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_SingleScalar_F16_Var) {
- Enable(wgsl::Extension::kF16);
-
- auto* var = Var("v", Expr(2_h));
- auto* cast = Call<vec3<f16>>(var);
- WrapInFunction(var, cast);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(R"(float16_t v = float16_t(2.0h);
- vector<float16_t, 3> tint_symbol = vector<float16_t, 3>((v).xxx);)"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_SingleScalar_Bool_Literal) {
- WrapInFunction(Call<vec3<bool>>(true));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("(true).xxx"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_SingleScalar_Bool_Var) {
- auto* var = Var("v", Expr(true));
- auto* cast = Call<vec3<bool>>(var);
- WrapInFunction(var, cast);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(R"(bool v = true;
- bool3 tint_symbol = bool3((v).xxx);)"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_SingleScalar_Int) {
- WrapInFunction(Call<vec3<i32>>(2_i));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("2).xxx"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Vec_SingleScalar_UInt) {
- WrapInFunction(Call<vec3<u32>>(2_u));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("2u).xxx"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Mat_F32) {
- WrapInFunction(
- Call<mat2x3<f32>>(Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(3_f, 4_f, 5_f)));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_THAT(gen.Result(),
- HasSubstr("float2x3(float3(1.0f, 2.0f, 3.0f), float3(3.0f, 4.0f, 5.0f))"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Mat_F16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(
- Call<mat2x3<f16>>(Call<vec3<f16>>(1_h, 2_h, 3_h), Call<vec3<f16>>(3_h, 4_h, 5_h)));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_THAT(gen.Result(),
- HasSubstr("matrix<float16_t, 2, 3>(vector<float16_t, 3>(float16_t(1.0h), "
- "float16_t(2.0h), float16_t(3.0h)), vector<float16_t, "
- "3>(float16_t(3.0h), float16_t(4.0h), float16_t(5.0h)))"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Mat_Complex_F32) {
- // mat4x4<f32>(
- // vec4<f32>(2.0f, 3.0f, 4.0f, 8.0f),
- // vec4<f32>(),
- // vec4<f32>(7.0f),
- // vec4<f32>(vec4<f32>(42.0f, 21.0f, 6.0f, -5.0f)),
- // );
- auto* vector_literal = Call<vec4<f32>>(f32(2.0), f32(3.0), f32(4.0), f32(8.0));
- auto* vector_zero_init = Call<vec4<f32>>();
- auto* vector_single_scalar_init = Call<vec4<f32>>(f32(7.0));
- auto* vector_identical_init =
- Call<vec4<f32>>(Call<vec4<f32>>(f32(42.0), f32(21.0), f32(6.0), f32(-5.0)));
-
- auto* constructor = Call<mat4x4<f32>>(vector_literal, vector_zero_init,
- vector_single_scalar_init, vector_identical_init);
-
- WrapInFunction(constructor);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_THAT(gen.Result(), HasSubstr("float4x4(float4(2.0f, 3.0f, 4.0f, 8.0f), (0.0f).xxxx, "
- "(7.0f).xxxx, float4(42.0f, 21.0f, 6.0f, -5.0f))"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Mat_Complex_F16) {
- // mat4x4<f16>(
- // vec4<f16>(2.0h, 3.0h, 4.0h, 8.0h),
- // vec4<f16>(),
- // vec4<f16>(7.0h),
- // vec4<f16>(vec4<f16>(42.0h, 21.0h, 6.0h, -5.0h)),
- // );
- Enable(wgsl::Extension::kF16);
-
- auto* vector_literal = Call<vec4<f16>>(f16(2.0), f16(3.0), f16(4.0), f16(8.0));
- auto* vector_zero_init = Call<vec4<f16>>();
- auto* vector_single_scalar_init = Call<vec4<f16>>(f16(7.0));
- auto* vector_identical_init =
- Call<vec4<f16>>(Call<vec4<f16>>(f16(42.0), f16(21.0), f16(6.0), f16(-5.0)));
-
- auto* constructor = Call<mat4x4<f16>>(vector_literal, vector_zero_init,
- vector_single_scalar_init, vector_identical_init);
-
- WrapInFunction(constructor);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_THAT(gen.Result(), HasSubstr("matrix<float16_t, 4, 4>("
- "vector<float16_t, 4>(float16_t(2.0h), float16_t(3.0h), "
- "float16_t(4.0h), float16_t(8.0h)), "
- "(float16_t(0.0h)).xxxx, (float16_t(7.0h)).xxxx, "
- "vector<float16_t, 4>(float16_t(42.0h), float16_t(21.0h), "
- "float16_t(6.0h), float16_t(-5.0h)))"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Mat_Empty_F32) {
- WrapInFunction(Call<mat2x3<f32>>());
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_THAT(gen.Result(), HasSubstr("float2x3 tint_symbol = float2x3((0.0f).xxx, (0.0f).xxx)"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Mat_Empty_F16) {
- Enable(wgsl::Extension::kF16);
-
- WrapInFunction(Call<mat2x3<f16>>());
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_THAT(gen.Result(),
- HasSubstr("matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx)"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Mat_Identity_F32) {
- // fn f() {
- // var m_1: mat4x4<f32> = mat4x4<f32>();
- // var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
- // }
-
- auto* m_1 = Var("m_1", ty.mat4x4(ty.f32()), Call<mat4x4<f32>>());
- auto* m_2 = Var("m_2", ty.mat4x4(ty.f32()), Call<mat4x4<f32>>(m_1));
-
- WrapInFunction(m_1, m_2);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_THAT(gen.Result(), HasSubstr("float4x4 m_2 = float4x4(m_1);"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Mat_Identity_F16) {
- // fn f() {
- // var m_1: mat4x4<f16> = mat4x4<f16>();
- // var m_2: mat4x4<f16> = mat4x4<f16>(m_1);
- // }
-
- Enable(wgsl::Extension::kF16);
-
- auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), Call<mat4x4<f16>>());
- auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), Call<mat4x4<f16>>(m_1));
-
- WrapInFunction(m_1, m_2);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_THAT(gen.Result(),
- HasSubstr("matrix<float16_t, 4, 4> m_2 = matrix<float16_t, 4, 4>(m_1);"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Array) {
- WrapInFunction(Call<array<vec3<f32>, 3>>(Call<vec3<f32>>(1_f, 2_f, 3_f),
- Call<vec3<f32>>(4_f, 5_f, 6_f),
- Call<vec3<f32>>(7_f, 8_f, 9_f)));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(
- gen.Result(),
- HasSubstr(
- "{float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f)}"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Array_Empty) {
- WrapInFunction(Call<array<vec3<f32>, 3>>());
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("(float3[3])0"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Struct) {
- auto* str = Structure("S", Vector{
- Member("a", ty.i32()),
- Member("b", ty.f32()),
- Member("c", ty.vec3<i32>()),
- });
-
- WrapInFunction(Call(ty.Of(str), 1_i, 2_f, Call<vec3<i32>>(3_i, 4_i, 5_i)));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("{1, 2.0f, int3(3, 4, 5)}"));
-}
-
-TEST_F(HlslASTPrinterTest_Constructor, Type_Struct_Empty) {
- auto* str = Structure("S", Vector{
- Member("a", ty.i32()),
- Member("b", ty.f32()),
- Member("c", ty.vec3<i32>()),
- });
-
- WrapInFunction(Call(ty.Of(str)));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("(S)0"));
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/continue_test.cc b/src/tint/lang/hlsl/writer/ast_printer/continue_test.cc
deleted file mode 100644
index 0581c1f..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/continue_test.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Continue = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Continue, Emit_Continue) {
- auto* loop = Loop(Block(If(false, Block(Break())), //
- Continue()));
- WrapInFunction(loop);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(loop)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( while (true) {
- if (false) {
- break;
- }
- continue;
- }
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/discard_test.cc b/src/tint/lang/hlsl/writer/ast_printer/discard_test.cc
deleted file mode 100644
index 0d06a09..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/discard_test.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Discard = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Discard, Emit_Discard) {
- auto* stmt = Discard();
-
- Func("F", tint::Empty, ty.void_(), Vector{stmt}, Vector{Stage(ast::PipelineStage::kFragment)});
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), " discard;\n");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/function_test.cc b/src/tint/lang/hlsl/writer/ast_printer/function_test.cc
deleted file mode 100644
index 2575346..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/function_test.cc
+++ /dev/null
@@ -1,895 +0,0 @@
-// Copyright 2020 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 "gmock/gmock.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/lang/wgsl/ast/stage_attribute.h"
-#include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
-#include "src/tint/lang/wgsl/ast/workgroup_attribute.h"
-
-using ::testing::HasSubstr;
-
-namespace tint::hlsl::writer {
-namespace {
-
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-using HlslASTPrinterTest_Function = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Function) {
- Func("my_func", tint::Empty, ty.void_(),
- Vector{
- Return(),
- });
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( void my_func() {
- return;
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Function_Name_Collision) {
- Func("GeometryShader", tint::Empty, ty.void_(),
- Vector{
- Return(),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(R"( void tint_symbol() {
- return;
- })"));
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Function_WithParams) {
- Func("my_func",
- Vector{
- Param("a", ty.f32()),
- Param("b", ty.i32()),
- },
- ty.void_(),
- Vector{
- Return(),
- });
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( void my_func(float a, int b) {
- return;
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_NoReturn_Void) {
- Func("main", tint::Empty, ty.void_(), tint::Empty /* no explicit return */,
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(void main() {
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, PtrParameter) {
- // fn f(foo : ptr<function, f32>) -> f32 {
- // return *foo;
- // }
- Func("f", Vector{Param("foo", ty.ptr<function, f32>())}, ty.f32(),
- Vector{Return(Deref("foo"))});
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(R"(float f(inout float foo) {
- return foo;
-}
-)"));
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_WithInOutVars) {
- // fn frag_main(@location(0) foo : f32) -> @location(1) f32 {
- // return foo;
- // }
- auto* foo_in = Param("foo", ty.f32(), Vector{Location(0_a)});
- Func("frag_main", Vector{foo_in}, ty.f32(),
- Vector{
- Return("foo"),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- },
- Vector{
- Location(1_a),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct tint_symbol_1 {
- float foo : TEXCOORD0;
-};
-struct tint_symbol_2 {
- float value : SV_Target1;
-};
-
-float frag_main_inner(float foo) {
- return foo;
-}
-
-tint_symbol_2 frag_main(tint_symbol_1 tint_symbol) {
- float inner_result = frag_main_inner(tint_symbol.foo);
- tint_symbol_2 wrapper_result = (tint_symbol_2)0;
- wrapper_result.value = inner_result;
- return wrapper_result;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_WithInOut_Builtins) {
- // fn frag_main(@position(0) coord : vec4<f32>) -> @frag_depth f32 {
- // return coord.x;
- // }
- auto* coord_in = Param("coord", ty.vec4<f32>(), Vector{Builtin(core::BuiltinValue::kPosition)});
- Func("frag_main", Vector{coord_in}, ty.f32(),
- Vector{
- Return(MemberAccessor("coord", "x")),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- },
- Vector{
- Builtin(core::BuiltinValue::kFragDepth),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct tint_symbol_1 {
- float4 coord : SV_Position;
-};
-struct tint_symbol_2 {
- float value : SV_Depth;
-};
-
-float frag_main_inner(float4 coord) {
- return coord.x;
-}
-
-tint_symbol_2 frag_main(tint_symbol_1 tint_symbol) {
- float inner_result = frag_main_inner(float4(tint_symbol.coord.xyz, (1.0f / tint_symbol.coord.w)));
- tint_symbol_2 wrapper_result = (tint_symbol_2)0;
- wrapper_result.value = inner_result;
- return wrapper_result;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_SharedStruct_DifferentStages) {
- // struct Interface {
- // @builtin(position) pos : vec4<f32>;
- // @location(1) col1 : f32;
- // @location(2) col2 : f32;
- // };
- // fn vert_main() -> Interface {
- // return Interface(vec4<f32>(), 0.4, 0.6);
- // }
- // fn frag_main(inputs : Interface) {
- // const r = inputs.col1;
- // const g = inputs.col2;
- // const p = inputs.pos;
- // }
- auto* interface_struct =
- Structure("Interface",
- Vector{
- Member("pos", ty.vec4<f32>(), Vector{Builtin(core::BuiltinValue::kPosition)}),
- Member("col1", ty.f32(), Vector{Location(1_a)}),
- Member("col2", ty.f32(), Vector{Location(2_a)}),
- });
-
- Func("vert_main", tint::Empty, ty.Of(interface_struct),
- Vector{
- Return(Call(ty.Of(interface_struct), Call<vec4<f32>>(), 0.5_f, 0.25_f)),
- },
- Vector{Stage(ast::PipelineStage::kVertex)});
-
- Func("frag_main", Vector{Param("inputs", ty.Of(interface_struct))}, ty.void_(),
- Vector{
- Decl(Let("r", ty.f32(), MemberAccessor("inputs", "col1"))),
- Decl(Let("g", ty.f32(), MemberAccessor("inputs", "col2"))),
- Decl(Let("p", ty.vec4<f32>(), MemberAccessor("inputs", "pos"))),
- },
- Vector{Stage(ast::PipelineStage::kFragment)});
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct Interface {
- float4 pos;
- float col1;
- float col2;
-};
-struct tint_symbol {
- float col1 : TEXCOORD1;
- float col2 : TEXCOORD2;
- float4 pos : SV_Position;
-};
-
-Interface vert_main_inner() {
- Interface tint_symbol_3 = {(0.0f).xxxx, 0.5f, 0.25f};
- return tint_symbol_3;
-}
-
-tint_symbol vert_main() {
- Interface inner_result = vert_main_inner();
- tint_symbol wrapper_result = (tint_symbol)0;
- wrapper_result.pos = inner_result.pos;
- wrapper_result.col1 = inner_result.col1;
- wrapper_result.col2 = inner_result.col2;
- return wrapper_result;
-}
-
-struct tint_symbol_2 {
- float col1 : TEXCOORD1;
- float col2 : TEXCOORD2;
- float4 pos : SV_Position;
-};
-
-void frag_main_inner(Interface inputs) {
- float r = inputs.col1;
- float g = inputs.col2;
- float4 p = inputs.pos;
-}
-
-void frag_main(tint_symbol_2 tint_symbol_1) {
- Interface tint_symbol_4 = {float4(tint_symbol_1.pos.xyz, (1.0f / tint_symbol_1.pos.w)), tint_symbol_1.col1, tint_symbol_1.col2};
- frag_main_inner(tint_symbol_4);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_SharedStruct_HelperFunction) {
- // struct VertexOutput {
- // @builtin(position) pos : vec4<f32>;
- // };
- // fn foo(x : f32) -> VertexOutput {
- // return VertexOutput(vec4<f32>(x, x, x, 1.0));
- // }
- // fn vert_main1() -> VertexOutput {
- // return foo(0.5);
- // }
- // fn vert_main2() -> VertexOutput {
- // return foo(0.25);
- // }
- auto* vertex_output_struct = Structure(
- "VertexOutput",
- Vector{Member("pos", ty.vec4<f32>(), Vector{Builtin(core::BuiltinValue::kPosition)})});
-
- Func("foo", Vector{Param("x", ty.f32())}, ty.Of(vertex_output_struct),
- Vector{
- Return(Call(ty.Of(vertex_output_struct), Call<vec4<f32>>("x", "x", "x", 1_f))),
- },
- tint::Empty);
-
- Func("vert_main1", tint::Empty, ty.Of(vertex_output_struct),
- Vector{
- Return(Call("foo", Expr(0.5_f))),
- },
- Vector{Stage(ast::PipelineStage::kVertex)});
-
- Func("vert_main2", tint::Empty, ty.Of(vertex_output_struct),
- Vector{
- Return(Call("foo", Expr(0.25_f))),
- },
- Vector{Stage(ast::PipelineStage::kVertex)});
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct VertexOutput {
- float4 pos;
-};
-
-VertexOutput foo(float x) {
- VertexOutput tint_symbol_2 = {float4(x, x, x, 1.0f)};
- return tint_symbol_2;
-}
-
-struct tint_symbol {
- float4 pos : SV_Position;
-};
-
-VertexOutput vert_main1_inner() {
- return foo(0.5f);
-}
-
-tint_symbol vert_main1() {
- VertexOutput inner_result = vert_main1_inner();
- tint_symbol wrapper_result = (tint_symbol)0;
- wrapper_result.pos = inner_result.pos;
- return wrapper_result;
-}
-
-struct tint_symbol_1 {
- float4 pos : SV_Position;
-};
-
-VertexOutput vert_main2_inner() {
- return foo(0.25f);
-}
-
-tint_symbol_1 vert_main2() {
- VertexOutput inner_result_1 = vert_main2_inner();
- tint_symbol_1 wrapper_result_1 = (tint_symbol_1)0;
- wrapper_result_1.pos = inner_result_1.pos;
- return wrapper_result_1;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_With_Uniform) {
- auto* ubo_ty = Structure("UBO", Vector{Member("coord", ty.vec4<f32>())});
- auto* ubo =
- GlobalVar("ubo", ty.Of(ubo_ty), core::AddressSpace::kUniform, Binding(0_a), Group(1_a));
-
- Func("sub_func",
- Vector{
- Param("param", ty.f32()),
- },
- ty.f32(),
- Vector{
- Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
- });
-
- auto* var = Var("v", ty.f32(), Call("sub_func", 1_f));
-
- Func("frag_main", tint::Empty, ty.void_(),
- Vector{
- Decl(var),
- Return(),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(cbuffer cbuffer_ubo : register(b0, space1) {
- uint4 ubo[1];
-};
-
-float sub_func(float param) {
- return asfloat(ubo[0].x);
-}
-
-void frag_main() {
- float v = sub_func(1.0f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_With_UniformStruct) {
- auto* s = Structure("Uniforms", Vector{Member("coord", ty.vec4<f32>())});
-
- GlobalVar("uniforms", ty.Of(s), core::AddressSpace::kUniform, Binding(0_a), Group(1_a));
-
- auto* var = Var("v", ty.f32(), MemberAccessor(MemberAccessor("uniforms", "coord"), "x"));
-
- Func("frag_main", tint::Empty, ty.void_(),
- Vector{
- Decl(var),
- Return(),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(cbuffer cbuffer_uniforms : register(b0, space1) {
- uint4 uniforms[1];
-};
-
-void frag_main() {
- float v = uniforms.coord.x;
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_With_RW_StorageBuffer_Read) {
- auto* s = Structure("Data", Vector{
- Member("a", ty.i32()),
- Member("b", ty.f32()),
- });
-
- GlobalVar("coord", ty.Of(s), core::AddressSpace::kStorage, core::Access::kReadWrite,
- Binding(0_a), Group(1_a));
-
- auto* var = Var("v", ty.f32(), MemberAccessor("coord", "b"));
-
- Func("frag_main", tint::Empty, ty.void_(),
- Vector{
- Decl(var),
- Return(),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(),
- R"(RWByteAddressBuffer coord : register(u0, space1);
-
-void frag_main() {
- float v = asfloat(coord.Load(4u));
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_With_RO_StorageBuffer_Read) {
- auto* s = Structure("Data", Vector{
- Member("a", ty.i32()),
- Member("b", ty.f32()),
- });
-
- GlobalVar("coord", ty.Of(s), core::AddressSpace::kStorage, core::Access::kRead, Binding(0_a),
- Group(1_a));
-
- auto* var = Var("v", ty.f32(), MemberAccessor("coord", "b"));
-
- Func("frag_main", tint::Empty, ty.void_(),
- Vector{
- Decl(var),
- Return(),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(),
- R"(ByteAddressBuffer coord : register(t0, space1);
-
-void frag_main() {
- float v = asfloat(coord.Load(4u));
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_With_WO_StorageBuffer_Store) {
- auto* s = Structure("Data", Vector{
- Member("a", ty.i32()),
- Member("b", ty.f32()),
- });
-
- GlobalVar("coord", ty.Of(s), core::AddressSpace::kStorage, core::Access::kReadWrite,
- Binding(0_a), Group(1_a));
-
- Func("frag_main", tint::Empty, ty.void_(),
- Vector{
- Assign(MemberAccessor("coord", "b"), Expr(2_f)),
- Return(),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(),
- R"(RWByteAddressBuffer coord : register(u0, space1);
-
-void frag_main() {
- coord.Store(4u, asuint(2.0f));
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_With_StorageBuffer_Store) {
- auto* s = Structure("Data", Vector{
- Member("a", ty.i32()),
- Member("b", ty.f32()),
- });
-
- GlobalVar("coord", ty.Of(s), core::AddressSpace::kStorage, core::Access::kReadWrite,
- Binding(0_a), Group(1_a));
-
- Func("frag_main", tint::Empty, ty.void_(),
- Vector{
- Assign(MemberAccessor("coord", "b"), Expr(2_f)),
- Return(),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(),
- R"(RWByteAddressBuffer coord : register(u0, space1);
-
-void frag_main() {
- coord.Store(4u, asuint(2.0f));
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
- auto* s = Structure("S", Vector{Member("x", ty.f32())});
- GlobalVar("coord", ty.Of(s), core::AddressSpace::kUniform, Binding(0_a), Group(1_a));
-
- Func("sub_func",
- Vector{
- Param("param", ty.f32()),
- },
- ty.f32(),
- Vector{
- Return(MemberAccessor("coord", "x")),
- });
-
- auto* var = Var("v", ty.f32(), Call("sub_func", 1_f));
-
- Func("frag_main", tint::Empty, ty.void_(),
- Vector{
- Decl(var),
- Return(),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(cbuffer cbuffer_coord : register(b0, space1) {
- uint4 coord[1];
-};
-
-float sub_func(float param) {
- return coord.x;
-}
-
-void frag_main() {
- float v = sub_func(1.0f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_Called_By_EntryPoint_With_StorageBuffer) {
- auto* s = Structure("S", Vector{Member("x", ty.f32())});
- GlobalVar("coord", ty.Of(s), core::AddressSpace::kStorage, core::Access::kReadWrite,
- Binding(0_a), Group(1_a));
-
- Func("sub_func",
- Vector{
- Param("param", ty.f32()),
- },
- ty.f32(),
- Vector{
- Return(MemberAccessor("coord", "x")),
- });
-
- auto* var = Var("v", ty.f32(), Call("sub_func", 1_f));
-
- Func("frag_main", tint::Empty, ty.void_(),
- Vector{
- Decl(var),
- Return(),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(),
- R"(RWByteAddressBuffer coord : register(u0, space1);
-
-float sub_func(float param) {
- return asfloat(coord.Load(0u));
-}
-
-void frag_main() {
- float v = sub_func(1.0f);
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_WithNameCollision) {
- Func("GeometryShader", tint::Empty, ty.void_(), tint::Empty,
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(void tint_symbol() {
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_Compute) {
- Func("main", tint::Empty, ty.void_(),
- Vector{
- Return(),
- },
- Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(1, 1, 1)]
-void main() {
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Literal) {
- Func("main", tint::Empty, ty.void_(), tint::Empty,
- Vector{
- Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(2_i, 4_i, 6_i),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(2, 4, 6)]
-void main() {
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Const) {
- GlobalConst("width", ty.i32(), Call<i32>(2_i));
- GlobalConst("height", ty.i32(), Call<i32>(3_i));
- GlobalConst("depth", ty.i32(), Call<i32>(4_i));
- Func("main", tint::Empty, ty.void_(), tint::Empty,
- Vector{
- Stage(ast::PipelineStage::kCompute),
- WorkgroupSize("width", "height", "depth"),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"([numthreads(2, 3, 4)]
-void main() {
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function,
- Emit_Attribute_EntryPoint_Compute_WithWorkgroup_OverridableConst) {
- Override("width", ty.i32(), Call<i32>(2_i), Id(7_u));
- Override("height", ty.i32(), Call<i32>(3_i), Id(8_u));
- Override("depth", ty.i32(), Call<i32>(4_i), Id(9_u));
- Func("main", tint::Empty, ty.void_(), tint::Empty,
- Vector{
- Stage(ast::PipelineStage::kCompute),
- WorkgroupSize("width", "height", "depth"),
- });
-
- ASTPrinter& gen = Build();
-
- EXPECT_FALSE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(
- gen.Diagnostics().Str(),
- R"(error: override-expressions should have been removed with the SubstituteOverride transform)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Function_WithArrayParams) {
- Func("my_func",
- Vector{
- Param("a", ty.array<f32, 5>()),
- },
- ty.void_(),
- Vector{
- Return(),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(void my_func(float a[5]) {
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Function_WithArrayReturn) {
- Func("my_func", tint::Empty, ty.array<f32, 5>(),
- Vector{
- Return(Call<array<f32, 5>>()),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(typedef float my_func_ret[5];
-my_func_ret my_func() {
- return (float[5])0;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Function_WithDiscardAndVoidReturn) {
- Func("my_func", Vector{Param("a", ty.i32())}, ty.void_(),
- Vector{
- If(Equal("a", 0_i), //
- Block(Discard())),
- Return(),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(void my_func(int a) {
- if ((a == 0)) {
- discard;
- }
- return;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Function, Emit_Function_WithDiscardAndNonVoidReturn) {
- Func("my_func", Vector{Param("a", ty.i32())}, ty.i32(),
- Vector{
- If(Equal("a", 0_i), //
- Block(Discard())),
- Return(42_i),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(int my_func(int a) {
- if (true) {
- if ((a == 0)) {
- discard;
- }
- return 42;
- }
- int unused;
- return unused;
-}
-)");
-}
-
-// https://crbug.com/tint/297
-TEST_F(HlslASTPrinterTest_Function, Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
- // struct Data {
- // d : f32;
- // };
- // @binding(0) @group(0) var<storage> data : Data;
- //
- // @compute @workgroup_size(1)
- // fn a() {
- // var v = data.d;
- // return;
- // }
- //
- // @compute @workgroup_size(1)
- // fn b() {
- // var v = data.d;
- // return;
- // }
-
- auto* s = Structure("Data", Vector{Member("d", ty.f32())});
-
- GlobalVar("data", ty.Of(s), core::AddressSpace::kStorage, core::Access::kReadWrite,
- Binding(0_a), Group(0_a));
-
- {
- auto* var = Var("v", ty.f32(), MemberAccessor("data", "d"));
-
- Func("a", tint::Empty, ty.void_(),
- Vector{
- Decl(var),
- Return(),
- },
- Vector{
- Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(1_i),
- });
- }
-
- {
- auto* var = Var("v", ty.f32(), MemberAccessor("data", "d"));
-
- Func("b", tint::Empty, ty.void_(),
- Vector{
- Decl(var),
- Return(),
- },
- Vector{
- Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(1_i),
- });
- }
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(RWByteAddressBuffer data : register(u0);
-
-[numthreads(1, 1, 1)]
-void a() {
- float v = asfloat(data.Load(0u));
- return;
-}
-
-[numthreads(1, 1, 1)]
-void b() {
- float v = asfloat(data.Load(0u));
- return;
-}
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/helper_test.h b/src/tint/lang/hlsl/writer/ast_printer/helper_test.h
deleted file mode 100644
index 800d85d..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/helper_test.h
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2020 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_LANG_HLSL_WRITER_AST_PRINTER_HELPER_TEST_H_
-#define SRC_TINT_LANG_HLSL_WRITER_AST_PRINTER_HELPER_TEST_H_
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "gtest/gtest.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/ast_printer.h"
-#include "src/tint/lang/hlsl/writer/common/options.h"
-#include "src/tint/lang/wgsl/ast/transform/manager.h"
-#include "src/tint/lang/wgsl/ast/transform/renamer.h"
-#include "src/tint/lang/wgsl/resolver/resolve.h"
-
-namespace tint::hlsl::writer {
-
-/// Helper class for testing
-template <typename BODY>
-class TestHelperBase : public BODY, public ProgramBuilder {
- public:
- TestHelperBase() = default;
- ~TestHelperBase() override = default;
-
- /// @returns the default generator options for SanitizeAndBuild(), if no explicit options are
- /// provided.
- static Options DefaultOptions() {
- Options opts;
- opts.disable_robustness = true;
- return opts;
- }
-
- /// Builds the program and returns a ASTPrinter from the program.
- /// @note The generator is only built once. Multiple calls to Build() will
- /// return the same ASTPrinter without rebuilding.
- /// @return the built generator
- ASTPrinter& Build() {
- if (gen_) {
- return *gen_;
- }
- if (!IsValid()) {
- ADD_FAILURE() << "ProgramBuilder is not valid: " << Diagnostics();
- }
- program = std::make_unique<Program>(resolver::Resolve(*this));
- if (!program->IsValid()) {
- ADD_FAILURE() << program->Diagnostics();
- }
- gen_ = std::make_unique<ASTPrinter>(*program);
- return *gen_;
- }
-
- /// Builds the program, runs the program through the HLSL sanitizer
- /// and returns a ASTPrinter from the sanitized program.
- /// @param options The HLSL generator options.
- /// @note The generator is only built once. Multiple calls to Build() will
- /// return the same ASTPrinter without rebuilding.
- /// @return the built generator
- ASTPrinter& SanitizeAndBuild(const Options& options = DefaultOptions()) {
- if (gen_) {
- return *gen_;
- }
- if (!IsValid()) {
- ADD_FAILURE() << "ProgramBuilder is not valid: " << Diagnostics();
- }
- program = std::make_unique<Program>(resolver::Resolve(*this));
- if (!program->IsValid()) {
- ADD_FAILURE() << program->Diagnostics();
- }
-
- auto sanitized_result = Sanitize(*program, options);
- if (!sanitized_result.program.IsValid()) {
- ADD_FAILURE() << sanitized_result.program.Diagnostics();
- }
-
- ast::transform::Manager transform_manager;
- ast::transform::DataMap transform_data;
- ast::transform::DataMap outputs;
- transform_data.Add<ast::transform::Renamer::Config>(
- ast::transform::Renamer::Target::kHlslKeywords);
- transform_manager.Add<tint::ast::transform::Renamer>();
- auto result = transform_manager.Run(sanitized_result.program, transform_data, outputs);
- if (!result.IsValid()) {
- ADD_FAILURE() << result.Diagnostics();
- }
- *program = std::move(result);
- gen_ = std::make_unique<ASTPrinter>(*program);
- return *gen_;
- }
-
- /// The program built with a call to Build()
- std::unique_ptr<Program> program;
-
- private:
- std::unique_ptr<ASTPrinter> gen_;
-};
-
-/// TestHelper the base class for HLSL writer unit tests.
-/// Use this form when you don't need to template any further.
-using TestHelper = TestHelperBase<testing::Test>;
-
-/// TestParamHelper the base class for HLSL unit tests that take a templated
-/// parameter.
-template <typename T>
-using TestParamHelper = TestHelperBase<testing::TestWithParam<T>>;
-
-} // namespace tint::hlsl::writer
-
-#endif // SRC_TINT_LANG_HLSL_WRITER_AST_PRINTER_HELPER_TEST_H_
diff --git a/src/tint/lang/hlsl/writer/ast_printer/identifier_test.cc b/src/tint/lang/hlsl/writer/ast_printer/identifier_test.cc
deleted file mode 100644
index 46bb0f9..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/identifier_test.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/utils/text/string_stream.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Identifier = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Identifier, EmitIdentifierExpression) {
- GlobalVar("foo", ty.i32(), core::AddressSpace::kPrivate);
-
- auto* i = Expr("foo");
- WrapInFunction(i);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "foo");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/if_test.cc b/src/tint/lang/hlsl/writer/ast_printer/if_test.cc
deleted file mode 100644
index b5a5a63..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/if_test.cc
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_If = TestHelper;
-
-TEST_F(HlslASTPrinterTest_If, Emit_If) {
- GlobalVar("cond", ty.bool_(), core::AddressSpace::kPrivate);
-
- auto* cond = Expr("cond");
- auto* body = Block(Return());
- auto* i = If(cond, body);
- WrapInFunction(i);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
- ASSERT_TRUE(gen.EmitStatement(i)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( if (cond) {
- return;
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_If, Emit_IfWithElseIf) {
- GlobalVar("cond", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("else_cond", ty.bool_(), core::AddressSpace::kPrivate);
-
- auto* else_cond = Expr("else_cond");
- auto* else_body = Block(Return());
-
- auto* cond = Expr("cond");
- auto* body = Block(Return());
- auto* i = If(cond, body, Else(If(else_cond, else_body)));
- WrapInFunction(i);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(i)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( if (cond) {
- return;
- } else {
- if (else_cond) {
- return;
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_If, Emit_IfWithElse) {
- GlobalVar("cond", ty.bool_(), core::AddressSpace::kPrivate);
-
- auto* else_body = Block(Return());
-
- auto* cond = Expr("cond");
- auto* body = Block(Return());
- auto* i = If(cond, body, Else(else_body));
- WrapInFunction(i);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(i)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( if (cond) {
- return;
- } else {
- return;
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_If, Emit_IfWithMultiple) {
- GlobalVar("cond", ty.bool_(), core::AddressSpace::kPrivate);
- GlobalVar("else_cond", ty.bool_(), core::AddressSpace::kPrivate);
-
- auto* else_cond = Expr("else_cond");
-
- auto* else_body = Block(Return());
-
- auto* else_body_2 = Block(Return());
-
- auto* cond = Expr("cond");
- auto* body = Block(Return());
- auto* i = If(cond, body, Else(If(else_cond, else_body, Else(else_body_2))));
- WrapInFunction(i);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(i)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( if (cond) {
- return;
- } else {
- if (else_cond) {
- return;
- } else {
- return;
- }
- }
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/import_test.cc b/src/tint/lang/hlsl/writer/ast_printer/import_test.cc
deleted file mode 100644
index fa3cb3d..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/import_test.cc
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/utils/text/string_stream.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-using HlslASTPrinterTest_Import = TestHelper;
-
-struct HlslImportData {
- const char* name;
- const char* hlsl_name;
-};
-inline std::ostream& operator<<(std::ostream& out, HlslImportData data) {
- out << data.name;
- return out;
-}
-
-using HlslImportData_SingleParamTest = TestParamHelper<HlslImportData>;
-TEST_P(HlslImportData_SingleParamTest, FloatScalar) {
- auto param = GetParam();
-
- auto* expr = Call(param.name, 1_f);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f)");
-}
-INSTANTIATE_TEST_SUITE_P(HlslASTPrinterTest_Import,
- HlslImportData_SingleParamTest,
- testing::Values(HlslImportData{"abs", "abs"},
- HlslImportData{"acos", "acos"},
- HlslImportData{"asin", "asin"},
- HlslImportData{"atan", "atan"},
- HlslImportData{"cos", "cos"},
- HlslImportData{"cosh", "cosh"},
- HlslImportData{"ceil", "ceil"},
- HlslImportData{"exp", "exp"},
- HlslImportData{"exp2", "exp2"},
- HlslImportData{"floor", "floor"},
- HlslImportData{"fract", "frac"},
- HlslImportData{"inverseSqrt", "rsqrt"},
- HlslImportData{"length", "length"},
- HlslImportData{"log", "log"},
- HlslImportData{"log2", "log2"},
- HlslImportData{"round", "round"},
- HlslImportData{"sin", "sin"},
- HlslImportData{"sinh", "sinh"},
- HlslImportData{"sqrt", "sqrt"},
- HlslImportData{"tan", "tan"},
- HlslImportData{"tanh", "tanh"}));
-
-using HlslImportData_SingleIntParamTest = TestParamHelper<HlslImportData>;
-TEST_P(HlslImportData_SingleIntParamTest, IntScalar) {
- auto param = GetParam();
-
- auto* expr = Call(param.name, Expr(1_i));
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1)");
-}
-INSTANTIATE_TEST_SUITE_P(HlslASTPrinterTest_Import,
- HlslImportData_SingleIntParamTest,
- testing::Values(HlslImportData{"abs", "abs"}));
-
-using HlslImportData_SingleVectorParamTest = TestParamHelper<HlslImportData>;
-TEST_P(HlslImportData_SingleVectorParamTest, FloatVector) {
- auto param = GetParam();
-
- auto* expr = Call(param.name, Call<vec3<f32>>(0.1_f, 0.2_f, 0.3_f));
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(
- out.str(),
- std::string(param.hlsl_name) +
- "(float3(0.10000000149011611938f, 0.20000000298023223877f, 0.30000001192092895508f))");
-}
-INSTANTIATE_TEST_SUITE_P(HlslASTPrinterTest_Import,
- HlslImportData_SingleVectorParamTest,
- testing::Values(HlslImportData{"abs", "abs"},
- HlslImportData{"acos", "acos"},
- HlslImportData{"asin", "asin"},
- HlslImportData{"atan", "atan"},
- HlslImportData{"cos", "cos"},
- HlslImportData{"cosh", "cosh"},
- HlslImportData{"ceil", "ceil"},
- HlslImportData{"exp", "exp"},
- HlslImportData{"exp2", "exp2"},
- HlslImportData{"floor", "floor"},
- HlslImportData{"fract", "frac"},
- HlslImportData{"inverseSqrt", "rsqrt"},
- HlslImportData{"length", "length"},
- HlslImportData{"log", "log"},
- HlslImportData{"log2", "log2"},
- HlslImportData{"normalize", "normalize"},
- HlslImportData{"round", "round"},
- HlslImportData{"sin", "sin"},
- HlslImportData{"sinh", "sinh"},
- HlslImportData{"sqrt", "sqrt"},
- HlslImportData{"tan", "tan"},
- HlslImportData{"tanh", "tanh"}));
-
-using HlslImportData_DualParam_ScalarTest = TestParamHelper<HlslImportData>;
-TEST_P(HlslImportData_DualParam_ScalarTest, Float) {
- auto param = GetParam();
-
- auto* expr = Call(param.name, 1_f, 2_f);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f, 2.0f)");
-}
-INSTANTIATE_TEST_SUITE_P(HlslASTPrinterTest_Import,
- HlslImportData_DualParam_ScalarTest,
- testing::Values(HlslImportData{"atan2", "atan2"},
- HlslImportData{"distance", "distance"},
- HlslImportData{"max", "max"},
- HlslImportData{"min", "min"},
- HlslImportData{"pow", "pow"},
- HlslImportData{"step", "step"}));
-
-using HlslImportData_DualParam_VectorTest = TestParamHelper<HlslImportData>;
-TEST_P(HlslImportData_DualParam_VectorTest, Float) {
- auto param = GetParam();
-
- auto* expr = Call(param.name, Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(4_f, 5_f, 6_f));
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), std::string(param.hlsl_name) +
- "(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f))");
-}
-INSTANTIATE_TEST_SUITE_P(HlslASTPrinterTest_Import,
- HlslImportData_DualParam_VectorTest,
- testing::Values(HlslImportData{"atan2", "atan2"},
- HlslImportData{"cross", "cross"},
- HlslImportData{"distance", "distance"},
- HlslImportData{"max", "max"},
- HlslImportData{"min", "min"},
- HlslImportData{"pow", "pow"},
- HlslImportData{"reflect", "reflect"},
- HlslImportData{"step", "step"}));
-
-using HlslImportData_DualParam_Int_Test = TestParamHelper<HlslImportData>;
-TEST_P(HlslImportData_DualParam_Int_Test, IntScalar) {
- auto param = GetParam();
-
- auto* expr = Call(param.name, 1_i, 2_i);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1, 2)");
-}
-INSTANTIATE_TEST_SUITE_P(HlslASTPrinterTest_Import,
- HlslImportData_DualParam_Int_Test,
- testing::Values(HlslImportData{"max", "max"},
- HlslImportData{"min", "min"}));
-
-using HlslImportData_TripleParam_ScalarTest = TestParamHelper<HlslImportData>;
-TEST_P(HlslImportData_TripleParam_ScalarTest, Float) {
- auto param = GetParam();
-
- auto* expr = Call(param.name, 1_f, 2_f, 3_f);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f, 2.0f, 3.0f)");
-}
-INSTANTIATE_TEST_SUITE_P(HlslASTPrinterTest_Import,
- HlslImportData_TripleParam_ScalarTest,
- testing::Values(HlslImportData{"fma", "mad"},
- HlslImportData{"mix", "lerp"},
- HlslImportData{"clamp", "clamp"},
- HlslImportData{"smoothstep", "smoothstep"}));
-
-using HlslImportData_TripleParam_VectorTest = TestParamHelper<HlslImportData>;
-TEST_P(HlslImportData_TripleParam_VectorTest, Float) {
- auto param = GetParam();
-
- auto* expr = Call(param.name, Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(4_f, 5_f, 6_f),
- Call<vec3<f32>>(7_f, 8_f, 9_f));
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(
- out.str(),
- std::string(param.hlsl_name) +
- R"((float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f)))");
-}
-INSTANTIATE_TEST_SUITE_P(HlslASTPrinterTest_Import,
- HlslImportData_TripleParam_VectorTest,
- testing::Values(HlslImportData{"faceForward", "faceforward"},
- HlslImportData{"fma", "mad"},
- HlslImportData{"clamp", "clamp"},
- HlslImportData{"smoothstep", "smoothstep"}));
-
-using HlslImportData_TripleParam_Int_Test = TestParamHelper<HlslImportData>;
-TEST_P(HlslImportData_TripleParam_Int_Test, IntScalar) {
- auto param = GetParam();
-
- auto* expr = Call(param.name, 1_i, 2_i, 3_i);
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1, 2, 3)");
-}
-INSTANTIATE_TEST_SUITE_P(HlslASTPrinterTest_Import,
- HlslImportData_TripleParam_Int_Test,
- testing::Values(HlslImportData{"clamp", "clamp"}));
-
-TEST_F(HlslASTPrinterTest_Import, HlslImportData_Determinant) {
- GlobalVar("var", ty.mat3x3<f32>(), core::AddressSpace::kPrivate);
-
- auto* expr = Call("determinant", "var");
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), std::string("determinant(var)"));
-}
-
-TEST_F(HlslASTPrinterTest_Import, HlslImportData_QuantizeToF16_Scalar) {
- GlobalVar("v", Expr(2_f), core::AddressSpace::kPrivate);
-
- auto* expr = Call("quantizeToF16", "v");
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), std::string("f16tof32(f32tof16(v))"));
-}
-
-TEST_F(HlslASTPrinterTest_Import, HlslImportData_QuantizeToF16_Vector) {
- GlobalVar("v", Call<vec3<f32>>(2_f), core::AddressSpace::kPrivate);
-
- auto* expr = Call("quantizeToF16", "v");
- WrapInFunction(expr);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), std::string("f16tof32(f32tof16(v))"));
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/loop_test.cc b/src/tint/lang/hlsl/writer/ast_printer/loop_test.cc
deleted file mode 100644
index b855f98..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/loop_test.cc
+++ /dev/null
@@ -1,487 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
-
-using namespace tint::core::number_suffixes; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Loop = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_Loop) {
- auto* body = Block(Break());
- auto* continuing = Block();
- auto* l = Loop(body, continuing);
-
- Func("F", tint::Empty, ty.void_(), Vector{l}, Vector{Stage(ast::PipelineStage::kFragment)});
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(l)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( while (true) {
- break;
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_LoopWithContinuing) {
- Func("a_statement", {}, ty.void_(), {});
-
- auto* body = Block(Break());
- auto* continuing = Block(CallStmt(Call("a_statement")));
- auto* l = Loop(body, continuing);
-
- Func("F", tint::Empty, ty.void_(), Vector{l}, Vector{Stage(ast::PipelineStage::kFragment)});
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(l)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( while (true) {
- break;
- {
- a_statement();
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_LoopWithContinuing_BreakIf) {
- Func("a_statement", {}, ty.void_(), {});
-
- auto* body = Block(Break());
- auto* continuing = Block(CallStmt(Call("a_statement")), BreakIf(true));
- auto* l = Loop(body, continuing);
-
- Func("F", tint::Empty, ty.void_(), Vector{l}, Vector{Stage(ast::PipelineStage::kFragment)});
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(l)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( while (true) {
- break;
- {
- a_statement();
- if (true) { break; }
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_LoopNestedWithContinuing) {
- Func("a_statement", {}, ty.void_(), {});
-
- GlobalVar("lhs", ty.f32(), core::AddressSpace::kPrivate);
- GlobalVar("rhs", ty.f32(), core::AddressSpace::kPrivate);
-
- auto* body = Block(Break());
- auto* continuing = Block(CallStmt(Call("a_statement")));
- auto* inner = Loop(body, continuing);
-
- body = Block(inner);
-
- auto* lhs = Expr("lhs");
- auto* rhs = Expr("rhs");
-
- continuing = Block(Assign(lhs, rhs), BreakIf(true));
-
- auto* outer = Loop(body, continuing);
-
- Func("F", tint::Empty, ty.void_(), Vector{outer}, Vector{Stage(ast::PipelineStage::kFragment)});
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(outer)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( while (true) {
- while (true) {
- break;
- {
- a_statement();
- }
- }
- {
- lhs = rhs;
- if (true) { break; }
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_LoopWithVarUsedInContinuing) {
- // loop {
- // var lhs : f32 = 2.5;
- // var other : f32;
- // break;
- // continuing {
- // lhs = rhs
- // }
- // }
-
- GlobalVar("rhs", ty.f32(), core::AddressSpace::kPrivate);
-
- auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.5_f))), //
- Decl(Var("other", ty.f32())), //
- Break());
-
- auto* continuing = Block(Assign("lhs", "rhs"));
- auto* outer = Loop(body, continuing);
- WrapInFunction(outer);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(outer)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( while (true) {
- float lhs = 2.5f;
- float other = 0.0f;
- break;
- {
- lhs = rhs;
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_ForLoop) {
- // for(; ; ) {
- // return;
- // }
-
- auto* f = For(nullptr, nullptr, nullptr, Block(Return()));
- WrapInFunction(f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( {
- for(; ; ) {
- return;
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_ForLoopWithSimpleInit) {
- // for(var i : i32; ; ) {
- // return;
- // }
-
- auto* f = For(Decl(Var("i", ty.i32())), nullptr, nullptr, Block(Return()));
- WrapInFunction(f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( {
- for(int i = 0; ; ) {
- return;
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_ForLoopWithMultiStmtInit) {
- // let t = true;
- // for(var b = t && false; ; ) {
- // return;
- // }
-
- auto* t = Let("t", Expr(true));
- auto* multi_stmt = LogicalAnd(t, false);
- auto* f = For(Decl(Var("b", multi_stmt)), nullptr, nullptr, Block(Return()));
- WrapInFunction(t, f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( {
- bool tint_tmp = t;
- if (tint_tmp) {
- tint_tmp = false;
- }
- bool b = (tint_tmp);
- for(; ; ) {
- return;
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_ForLoopWithSimpleCond) {
- // for(; true; ) {
- // return;
- // }
-
- auto* f = For(nullptr, true, nullptr, Block(Return()));
- WrapInFunction(f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( {
- for(; true; ) {
- return;
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_ForLoopWithMultiStmtCond) {
- // let t = true;
- // for(; t && false; ) {
- // return;
- // }
-
- Func("a_statement", {}, ty.void_(), {});
- auto* t = Let("t", Expr(true));
- auto* multi_stmt = LogicalAnd(t, false);
- auto* f = For(nullptr, multi_stmt, nullptr, Block(CallStmt(Call("a_statement"))));
- WrapInFunction(t, f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( {
- while (true) {
- bool tint_tmp = t;
- if (tint_tmp) {
- tint_tmp = false;
- }
- if (!((tint_tmp))) { break; }
- a_statement();
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_ForLoopWithSimpleCont) {
- // for(; ; i = i + 1i) {
- // return;
- // }
-
- auto* v = Decl(Var("i", ty.i32()));
- auto* f = For(nullptr, nullptr, Assign("i", Add("i", 1_i)), Block(Return()));
- WrapInFunction(v, f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( {
- for(; ; i = (i + 1)) {
- return;
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_ForLoopWithMultiStmtCont) {
- // let t = true;
- // for(; ; i = t && false) {
- // return;
- // }
-
- auto* t = Let("t", Expr(true));
- auto* multi_stmt = LogicalAnd(t, false);
- auto* v = Decl(Var("i", ty.bool_()));
- auto* f = For(nullptr, nullptr, Assign("i", multi_stmt), //
- Block(Return()));
- WrapInFunction(t, v, f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( {
- while (true) {
- return;
- bool tint_tmp = t;
- if (tint_tmp) {
- tint_tmp = false;
- }
- i = (tint_tmp);
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_ForLoopWithSimpleInitCondCont) {
- // for(var i : i32; true; i = i + 1i) {
- // return;
- // }
-
- auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1_i)), Block(Return()));
- WrapInFunction(f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( {
- for(int i = 0; true; i = (i + 1)) {
- return;
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_ForLoopWithMultiStmtInitCondCont) {
- // let t = true;
- // for(var i = t && false; t && false; i = t && false) {
- // return;
- // }
-
- auto* t = Let("t", Expr(true));
- auto* multi_stmt_a = LogicalAnd(t, false);
- auto* multi_stmt_b = LogicalAnd(t, false);
- auto* multi_stmt_c = LogicalAnd(t, false);
-
- auto* f = For(Decl(Var("i", multi_stmt_a)), multi_stmt_b, Assign("i", multi_stmt_c), //
- Block(Return()));
- WrapInFunction(t, f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( {
- bool tint_tmp = t;
- if (tint_tmp) {
- tint_tmp = false;
- }
- bool i = (tint_tmp);
- while (true) {
- bool tint_tmp_1 = t;
- if (tint_tmp_1) {
- tint_tmp_1 = false;
- }
- if (!((tint_tmp_1))) { break; }
- return;
- bool tint_tmp_2 = t;
- if (tint_tmp_2) {
- tint_tmp_2 = false;
- }
- i = (tint_tmp_2);
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_While) {
- // while(true) {
- // return;
- // }
-
- auto* f = While(Expr(true), Block(Return()));
- WrapInFunction(f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( while(true) {
- return;
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_While_WithContinue) {
- // while(true) {
- // continue;
- // }
-
- auto* f = While(Expr(true), Block(Continue()));
- WrapInFunction(f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( while(true) {
- continue;
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Loop, Emit_WhileWithMultiStmtCond) {
- // let t = true;
- // while(t && false) {
- // return;
- // }
-
- Func("a_statement", {}, ty.void_(), {});
-
- auto* t = Let("t", Expr(true));
- auto* multi_stmt = LogicalAnd(t, false);
- auto* f = While(multi_stmt, Block(CallStmt(Call("a_statement"))));
- WrapInFunction(t, f);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(f)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( while (true) {
- bool tint_tmp = t;
- if (tint_tmp) {
- tint_tmp = false;
- }
- if (!((tint_tmp))) { break; }
- a_statement();
- }
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/member_accessor_test.cc b/src/tint/lang/hlsl/writer/ast_printer/member_accessor_test.cc
deleted file mode 100644
index f06ef68..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/member_accessor_test.cc
+++ /dev/null
@@ -1,2018 +0,0 @@
-// Copyright 2020 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 "gmock/gmock.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/lang/wgsl/ast/stage_attribute.h"
-
-using ::testing::HasSubstr;
-
-namespace tint::hlsl::writer {
-namespace {
-
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-using create_type_func_ptr = ast::Type (*)(const ProgramBuilder::TypesBuilder& ty);
-
-inline ast::Type ty_i32(const ProgramBuilder::TypesBuilder& ty) {
- return ty.i32();
-}
-inline ast::Type ty_u32(const ProgramBuilder::TypesBuilder& ty) {
- return ty.u32();
-}
-inline ast::Type ty_f32(const ProgramBuilder::TypesBuilder& ty) {
- return ty.f32();
-}
-inline ast::Type ty_f16(const ProgramBuilder::TypesBuilder& ty) {
- return ty.f16();
-}
-template <typename T>
-inline ast::Type ty_vec2(const ProgramBuilder::TypesBuilder& ty) {
- return ty.vec2<T>();
-}
-template <typename T>
-inline ast::Type ty_vec3(const ProgramBuilder::TypesBuilder& ty) {
- return ty.vec3<T>();
-}
-template <typename T>
-inline ast::Type ty_vec4(const ProgramBuilder::TypesBuilder& ty) {
- return ty.vec4<T>();
-}
-template <typename T>
-inline ast::Type ty_mat2x2(const ProgramBuilder::TypesBuilder& ty) {
- return ty.mat2x2<T>();
-}
-template <typename T>
-inline ast::Type ty_mat2x3(const ProgramBuilder::TypesBuilder& ty) {
- return ty.mat2x3<T>();
-}
-template <typename T>
-inline ast::Type ty_mat2x4(const ProgramBuilder::TypesBuilder& ty) {
- return ty.mat2x4<T>();
-}
-template <typename T>
-inline ast::Type ty_mat3x2(const ProgramBuilder::TypesBuilder& ty) {
- return ty.mat3x2<T>();
-}
-template <typename T>
-inline ast::Type ty_mat3x3(const ProgramBuilder::TypesBuilder& ty) {
- return ty.mat3x3<T>();
-}
-template <typename T>
-inline ast::Type ty_mat3x4(const ProgramBuilder::TypesBuilder& ty) {
- return ty.mat3x4<T>();
-}
-template <typename T>
-inline ast::Type ty_mat4x2(const ProgramBuilder::TypesBuilder& ty) {
- return ty.mat4x2<T>();
-}
-template <typename T>
-inline ast::Type ty_mat4x3(const ProgramBuilder::TypesBuilder& ty) {
- return ty.mat4x3<T>();
-}
-template <typename T>
-inline ast::Type ty_mat4x4(const ProgramBuilder::TypesBuilder& ty) {
- return ty.mat4x4<T>();
-}
-
-template <typename BASE>
-class HlslASTPrinterTest_MemberAccessorBase : public BASE {
- public:
- void SetupStorageBuffer(VectorRef<const ast::StructMember*> members) {
- ProgramBuilder& b = *this;
- auto* s = b.Structure("Data", members);
-
- b.GlobalVar("data", b.ty.Of(s), core::AddressSpace::kStorage, core::Access::kReadWrite,
- b.Group(1_a), b.Binding(0_a));
- }
-
- void SetupUniformBuffer(VectorRef<const ast::StructMember*> members) {
- ProgramBuilder& b = *this;
- auto* s = b.Structure("Data", members);
-
- b.GlobalVar("data", b.ty.Of(s), core::AddressSpace::kUniform, core::Access::kUndefined,
- b.Group(1_a), b.Binding(1_a));
- }
-
- void SetupFunction(VectorRef<const ast::Statement*> statements) {
- ProgramBuilder& b = *this;
- Vector attrs{
- b.Stage(ast::PipelineStage::kFragment),
- };
- b.Func("main", tint::Empty, b.ty.void_(), std::move(statements), std::move(attrs));
- }
-};
-
-using HlslASTPrinterTest_MemberAccessor = HlslASTPrinterTest_MemberAccessorBase<TestHelper>;
-
-template <typename T>
-using HlslASTPrinterTest_MemberAccessorWithParam =
- HlslASTPrinterTest_MemberAccessorBase<TestParamHelper<T>>;
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, EmitExpression_MemberAccessor) {
- auto* s = Structure("Data", Vector{Member("mem", ty.f32())});
- GlobalVar("str", ty.Of(s), core::AddressSpace::kPrivate);
-
- auto* expr = MemberAccessor("str", "mem");
- WrapInFunction(Var("expr", ty.f32(), expr));
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(struct Data {
- float mem;
-};
-
-static Data str = (Data)0;
-
-[numthreads(1, 1, 1)]
-void test_function() {
- float expr = str.mem;
- return;
-}
-)");
-}
-
-struct TypeCase {
- create_type_func_ptr member_type;
- std::string expected;
-};
-inline std::ostream& operator<<(std::ostream& out, TypeCase c) {
- return out << c.expected;
-}
-
-using HlslASTPrinterTest_MemberAccessor_StorageBufferLoad_ConstantOffset =
- HlslASTPrinterTest_MemberAccessorWithParam<TypeCase>;
-
-TEST_P(HlslASTPrinterTest_MemberAccessor_StorageBufferLoad_ConstantOffset, Test) {
- // struct Data {
- // a : i32,
- // b : <type>,
- // };
- // var<storage> data : Data;
- // data.b;
-
- auto p = GetParam();
-
- Enable(wgsl::Extension::kF16);
-
- SetupStorageBuffer(Vector{
- Member("a", ty.i32()),
- Member("b", p.member_type(ty)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", MemberAccessor("data", "b"))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(p.expected));
-}
-
-INSTANTIATE_TEST_SUITE_P(
- HlslASTPrinterTest_MemberAccessor,
- HlslASTPrinterTest_MemberAccessor_StorageBufferLoad_ConstantOffset,
- testing::Values(TypeCase{ty_u32, "data.Load(4u)"},
- TypeCase{ty_f32, "asfloat(data.Load(4u))"},
- TypeCase{ty_i32, "asint(data.Load(4u))"},
- TypeCase{ty_f16, "data.Load<float16_t>(4u)"},
- TypeCase{ty_vec2<u32>, "data.Load2(8u)"},
- TypeCase{ty_vec2<f32>, "asfloat(data.Load2(8u))"},
- TypeCase{ty_vec2<i32>, "asint(data.Load2(8u))"},
- TypeCase{ty_vec2<f16>, "data.Load<vector<float16_t, 2> >(4u)"},
- TypeCase{ty_vec3<u32>, "data.Load3(16u)"},
- TypeCase{ty_vec3<f32>, "asfloat(data.Load3(16u))"},
- TypeCase{ty_vec3<i32>, "asint(data.Load3(16u))"},
- TypeCase{ty_vec3<f16>, "data.Load<vector<float16_t, 3> >(8u)"},
- TypeCase{ty_vec4<u32>, "data.Load4(16u)"},
- TypeCase{ty_vec4<f32>, "asfloat(data.Load4(16u))"},
- TypeCase{ty_vec4<i32>, "asint(data.Load4(16u))"},
- TypeCase{ty_vec4<f16>, "data.Load<vector<float16_t, 4> >(8u)"},
- TypeCase{ty_mat2x2<f32>,
- "return float2x2(asfloat(data.Load2((offset + 0u))), "
- "asfloat(data.Load2((offset + 8u))));"},
- TypeCase{ty_mat2x3<f32>,
- "return float2x3(asfloat(data.Load3((offset + 0u))), "
- "asfloat(data.Load3((offset + 16u))));"},
- TypeCase{ty_mat2x4<f32>,
- "return float2x4(asfloat(data.Load4((offset + 0u))), "
- "asfloat(data.Load4((offset + 16u))));"},
- TypeCase{ty_mat3x2<f32>,
- "return float3x2(asfloat(data.Load2((offset + 0u))), "
- "asfloat(data.Load2((offset + 8u))), "
- "asfloat(data.Load2((offset + 16u))));"},
- TypeCase{ty_mat3x3<f32>,
- "return float3x3(asfloat(data.Load3((offset + 0u))), "
- "asfloat(data.Load3((offset + 16u))), "
- "asfloat(data.Load3((offset + 32u))));"},
- TypeCase{ty_mat3x4<f32>,
- "return float3x4(asfloat(data.Load4((offset + 0u))), "
- "asfloat(data.Load4((offset + 16u))), "
- "asfloat(data.Load4((offset + 32u))));"},
- TypeCase{ty_mat4x2<f32>,
- "return float4x2(asfloat(data.Load2((offset + 0u))), "
- "asfloat(data.Load2((offset + 8u))), "
- "asfloat(data.Load2((offset + 16u))), "
- "asfloat(data.Load2((offset + 24u))));"},
- TypeCase{ty_mat4x3<f32>,
- "return float4x3(asfloat(data.Load3((offset + 0u))), "
- "asfloat(data.Load3((offset + 16u))), "
- "asfloat(data.Load3((offset + 32u))), "
- "asfloat(data.Load3((offset + 48u))));"},
- TypeCase{ty_mat4x4<f32>,
- "return float4x4(asfloat(data.Load4((offset + 0u))), "
- "asfloat(data.Load4((offset + 16u))), "
- "asfloat(data.Load4((offset + 32u))), "
- "asfloat(data.Load4((offset + 48u))));"},
- TypeCase{ty_mat2x2<f16>,
- "return matrix<float16_t, 2, 2>("
- "data.Load<vector<float16_t, 2> >((offset + 0u)), "
- "data.Load<vector<float16_t, 2> >((offset + 4u)));"},
- TypeCase{ty_mat2x3<f16>,
- "return matrix<float16_t, 2, 3>("
- "data.Load<vector<float16_t, 3> >((offset + 0u)), "
- "data.Load<vector<float16_t, 3> >((offset + 8u)));"},
- TypeCase{ty_mat2x4<f16>,
- "return matrix<float16_t, 2, 4>("
- "data.Load<vector<float16_t, 4> >((offset + 0u)), "
- "data.Load<vector<float16_t, 4> >((offset + 8u)));"},
- TypeCase{ty_mat3x2<f16>,
- "return matrix<float16_t, 3, 2>("
- "data.Load<vector<float16_t, 2> >((offset + 0u)), "
- "data.Load<vector<float16_t, 2> >((offset + 4u)), "
- "data.Load<vector<float16_t, 2> >((offset + 8u)));"},
- TypeCase{ty_mat3x3<f16>,
- "return matrix<float16_t, 3, 3>("
- "data.Load<vector<float16_t, 3> >((offset + 0u)), "
- "data.Load<vector<float16_t, 3> >((offset + 8u)), "
- "data.Load<vector<float16_t, 3> >((offset + 16u)));"},
- TypeCase{ty_mat3x4<f16>,
- "return matrix<float16_t, 3, 4>("
- "data.Load<vector<float16_t, 4> >((offset + 0u)), "
- "data.Load<vector<float16_t, 4> >((offset + 8u)), "
- "data.Load<vector<float16_t, 4> >((offset + 16u)));"},
- TypeCase{ty_mat4x2<f16>,
- "return matrix<float16_t, 4, 2>("
- "data.Load<vector<float16_t, 2> >((offset + 0u)), "
- "data.Load<vector<float16_t, 2> >((offset + 4u)), "
- "data.Load<vector<float16_t, 2> >((offset + 8u)), "
- "data.Load<vector<float16_t, 2> >((offset + 12u)));"},
- TypeCase{ty_mat4x3<f16>,
- "return matrix<float16_t, 4, 3>("
- "data.Load<vector<float16_t, 3> >((offset + 0u)), "
- "data.Load<vector<float16_t, 3> >((offset + 8u)), "
- "data.Load<vector<float16_t, 3> >((offset + 16u)), "
- "data.Load<vector<float16_t, 3> >((offset + 24u)));"},
- TypeCase{ty_mat4x4<f16>,
- "return matrix<float16_t, 4, 4>("
- "data.Load<vector<float16_t, 4> >((offset + 0u)), "
- "data.Load<vector<float16_t, 4> >((offset + 8u)), "
- "data.Load<vector<float16_t, 4> >((offset + 16u)), "
- "data.Load<vector<float16_t, 4> >((offset + 24u)));"}));
-
-using HlslASTPrinterTest_MemberAccessor_StorageBufferLoad_DynamicOffset =
- HlslASTPrinterTest_MemberAccessorWithParam<TypeCase>;
-
-TEST_P(HlslASTPrinterTest_MemberAccessor_StorageBufferLoad_DynamicOffset, Test) {
- // struct Inner {
- // a : i32,
- // b : <type>,
- // c : vec4<i32>,
- // };
- // struct Data {
- // arr : array<Inner, 4i>,
- // }
- // var<storage> data : Data;
- // data.arr[i].b;
-
- auto p = GetParam();
-
- Enable(wgsl::Extension::kF16);
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.i32()),
- Member("b", p.member_type(ty)),
- Member("c", ty.vec4(ty.i32())),
- });
-
- SetupStorageBuffer(Vector{
- Member("arr", ty.array(ty.Of(inner), 4_i)),
- });
-
- auto* i = Var("i", Expr(2_i));
-
- SetupFunction(Vector{
- Decl(i),
- Decl(Var("x", MemberAccessor(IndexAccessor(MemberAccessor("data", "arr"), i), "b"))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(p.expected));
-}
-
-INSTANTIATE_TEST_SUITE_P(
- HlslASTPrinterTest_MemberAccessor,
- HlslASTPrinterTest_MemberAccessor_StorageBufferLoad_DynamicOffset,
- testing::Values(
- TypeCase{ty_u32, "data.Load(((32u * uint(i)) + 4u))"},
- TypeCase{ty_f32, "asfloat(data.Load(((32u * uint(i)) + 4u)))"},
- TypeCase{ty_i32, "asint(data.Load(((32u * uint(i)) + 4u)))"},
- TypeCase{ty_f16, "data.Load<float16_t>(((32u * uint(i)) + 4u))"},
- TypeCase{ty_vec2<u32>, "data.Load2(((32u * uint(i)) + 8u))"},
- TypeCase{ty_vec2<f32>, "asfloat(data.Load2(((32u * uint(i)) + 8u)))"},
- TypeCase{ty_vec2<i32>, "asint(data.Load2(((32u * uint(i)) + 8u)))"},
- TypeCase{ty_vec2<f16>, "data.Load<vector<float16_t, 2> >(((32u * uint(i)) + 4u))"},
- TypeCase{ty_vec3<u32>, "data.Load3(((48u * uint(i)) + 16u))"},
- TypeCase{ty_vec3<f32>, "asfloat(data.Load3(((48u * uint(i)) + 16u)))"},
- TypeCase{ty_vec3<i32>, "asint(data.Load3(((48u * uint(i)) + 16u)))"},
- TypeCase{ty_vec3<f16>, "data.Load<vector<float16_t, 3> >(((32u * uint(i)) + 8u))"},
- TypeCase{ty_vec4<u32>, "data.Load4(((48u * uint(i)) + 16u))"},
- TypeCase{ty_vec4<f32>, "asfloat(data.Load4(((48u * uint(i)) + 16u)))"},
- TypeCase{ty_vec4<i32>, "asint(data.Load4(((48u * uint(i)) + 16u)))"},
- TypeCase{ty_vec4<f16>, "data.Load<vector<float16_t, 4> >(((32u * uint(i)) + 8u))"},
- TypeCase{ty_mat2x2<f32>,
- "return float2x2(asfloat(data.Load2((offset + 0u))), "
- "asfloat(data.Load2((offset + 8u))));"},
- TypeCase{ty_mat2x3<f32>,
- "return float2x3(asfloat(data.Load3((offset + 0u))), "
- "asfloat(data.Load3((offset + 16u))));"},
- TypeCase{ty_mat2x4<f32>,
- "return float2x4(asfloat(data.Load4((offset + 0u))), "
- "asfloat(data.Load4((offset + 16u))));"},
- TypeCase{ty_mat3x2<f32>,
- "return float3x2(asfloat(data.Load2((offset + 0u))), "
- "asfloat(data.Load2((offset + 8u))), "
- "asfloat(data.Load2((offset + 16u))));"},
- TypeCase{ty_mat3x3<f32>,
- "return float3x3(asfloat(data.Load3((offset + 0u))), "
- "asfloat(data.Load3((offset + 16u))), "
- "asfloat(data.Load3((offset + 32u))));"},
- TypeCase{ty_mat3x4<f32>,
- "return float3x4(asfloat(data.Load4((offset + 0u))), "
- "asfloat(data.Load4((offset + 16u))), "
- "asfloat(data.Load4((offset + 32u))));"},
- TypeCase{ty_mat4x2<f32>,
- "return float4x2(asfloat(data.Load2((offset + 0u))), "
- "asfloat(data.Load2((offset + 8u))), "
- "asfloat(data.Load2((offset + 16u))), "
- "asfloat(data.Load2((offset + 24u))));"},
- TypeCase{ty_mat4x3<f32>,
- "return float4x3(asfloat(data.Load3((offset + 0u))), "
- "asfloat(data.Load3((offset + 16u))), "
- "asfloat(data.Load3((offset + 32u))), "
- "asfloat(data.Load3((offset + 48u))));"},
- TypeCase{ty_mat4x4<f32>,
- "return float4x4(asfloat(data.Load4((offset + 0u))), "
- "asfloat(data.Load4((offset + 16u))), "
- "asfloat(data.Load4((offset + 32u))), "
- "asfloat(data.Load4((offset + 48u))));"},
- TypeCase{ty_mat2x2<f16>,
- "return matrix<float16_t, 2, 2>("
- "data.Load<vector<float16_t, 2> >((offset + 0u)), "
- "data.Load<vector<float16_t, 2> >((offset + 4u)));"},
- TypeCase{ty_mat2x3<f16>,
- "return matrix<float16_t, 2, 3>("
- "data.Load<vector<float16_t, 3> >((offset + 0u)), "
- "data.Load<vector<float16_t, 3> >((offset + 8u)));"},
- TypeCase{ty_mat2x4<f16>,
- "return matrix<float16_t, 2, 4>("
- "data.Load<vector<float16_t, 4> >((offset + 0u)), "
- "data.Load<vector<float16_t, 4> >((offset + 8u)));"},
- TypeCase{ty_mat3x2<f16>,
- "return matrix<float16_t, 3, 2>("
- "data.Load<vector<float16_t, 2> >((offset + 0u)), "
- "data.Load<vector<float16_t, 2> >((offset + 4u)), "
- "data.Load<vector<float16_t, 2> >((offset + 8u)));"},
- TypeCase{ty_mat3x3<f16>,
- "return matrix<float16_t, 3, 3>("
- "data.Load<vector<float16_t, 3> >((offset + 0u)), "
- "data.Load<vector<float16_t, 3> >((offset + 8u)), "
- "data.Load<vector<float16_t, 3> >((offset + 16u)));"},
- TypeCase{ty_mat3x4<f16>,
- "return matrix<float16_t, 3, 4>("
- "data.Load<vector<float16_t, 4> >((offset + 0u)), "
- "data.Load<vector<float16_t, 4> >((offset + 8u)), "
- "data.Load<vector<float16_t, 4> >((offset + 16u)));"},
- TypeCase{ty_mat4x2<f16>,
- "return matrix<float16_t, 4, 2>("
- "data.Load<vector<float16_t, 2> >((offset + 0u)), "
- "data.Load<vector<float16_t, 2> >((offset + 4u)), "
- "data.Load<vector<float16_t, 2> >((offset + 8u)), "
- "data.Load<vector<float16_t, 2> >((offset + 12u)));"},
- TypeCase{ty_mat4x3<f16>,
- "return matrix<float16_t, 4, 3>("
- "data.Load<vector<float16_t, 3> >((offset + 0u)), "
- "data.Load<vector<float16_t, 3> >((offset + 8u)), "
- "data.Load<vector<float16_t, 3> >((offset + 16u)), "
- "data.Load<vector<float16_t, 3> >((offset + 24u)));"},
- TypeCase{ty_mat4x4<f16>,
- "return matrix<float16_t, 4, 4>("
- "data.Load<vector<float16_t, 4> >((offset + 0u)), "
- "data.Load<vector<float16_t, 4> >((offset + 8u)), "
- "data.Load<vector<float16_t, 4> >((offset + 16u)), "
- "data.Load<vector<float16_t, 4> >((offset + 24u)));"}));
-
-using HlslASTPrinterTest_MemberAccessor_UniformBufferLoad_ConstantOffset =
- HlslASTPrinterTest_MemberAccessorWithParam<TypeCase>;
-TEST_P(HlslASTPrinterTest_MemberAccessor_UniformBufferLoad_ConstantOffset, Test) {
- // struct Data {
- // a : i32,
- // b : <type>,
- // };
- // var<uniform> data : Data;
- // data.b;
-
- auto p = GetParam();
-
- Enable(wgsl::Extension::kF16);
-
- SetupUniformBuffer(Vector{
- Member("a", ty.i32()),
- Member("b", p.member_type(ty)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", MemberAccessor("data", "b"))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(p.expected));
-}
-
-INSTANTIATE_TEST_SUITE_P(
- HlslASTPrinterTest_MemberAccessor,
- HlslASTPrinterTest_MemberAccessor_UniformBufferLoad_ConstantOffset,
- testing::Values(TypeCase{ty_u32, "uint x = data[0].y;"},
- TypeCase{ty_f32, "float x = asfloat(data[0].y);"},
- TypeCase{ty_i32, "int x = asint(data[0].y);"},
- TypeCase{ty_f16, "float16_t x = float16_t(f16tof32(((data[0].y) & 0xFFFF)));"},
- TypeCase{ty_vec2<u32>, "uint2 x = data[0].zw;"},
- TypeCase{ty_vec2<f32>, "float2 x = asfloat(data[0].zw);"},
- TypeCase{ty_vec2<i32>, "int2 x = asint(data[0].zw);"},
- TypeCase{ty_vec2<f16>, R"(uint ubo_load = data[0].y;
- vector<float16_t, 2> x = vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16)));)"},
- TypeCase{ty_vec3<u32>, "uint3 x = data[1].xyz;"},
- TypeCase{ty_vec3<f32>, "float3 x = asfloat(data[1].xyz);"},
- TypeCase{ty_vec3<i32>, "int3 x = asint(data[1].xyz);"},
- TypeCase{ty_vec3<f16>, R"(uint2 ubo_load = data[0].zw;
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
- vector<float16_t, 3> x = vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]);)"},
- TypeCase{ty_vec4<u32>, "uint4 x = data[1];"},
- TypeCase{ty_vec4<f32>, "float4 x = asfloat(data[1]);"},
- TypeCase{ty_vec4<i32>, "int4 x = asint(data[1]);"},
- TypeCase{ty_vec4<f16>,
- R"(uint2 ubo_load = data[0].zw;
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
- vector<float16_t, 4> x = vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]);)"},
- TypeCase{ty_mat2x2<f32>, R"(float2x2 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load = data[scalar_offset / 4];
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset_1 / 4];
- return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-})"},
- TypeCase{ty_mat2x3<f32>, R"(float2x3 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- return float2x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz));
-})"},
- TypeCase{ty_mat2x4<f32>, R"(float2x4 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- return float2x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]));
-})"},
- TypeCase{ty_mat3x2<f32>, R"(float3x2 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load = data[scalar_offset / 4];
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset_1 / 4];
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_2 = data[scalar_offset_2 / 4];
- return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-})"},
- TypeCase{ty_mat3x3<f32>, R"(float3x3 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- const uint scalar_offset_2 = ((offset + 32u)) / 4;
- return float3x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz), asfloat(data[scalar_offset_2 / 4].xyz));
-})"},
- TypeCase{ty_mat3x4<f32>, R"(float3x4 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- const uint scalar_offset_2 = ((offset + 32u)) / 4;
- return float3x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]), asfloat(data[scalar_offset_2 / 4]));
-})"},
- TypeCase{ty_mat4x2<f32>, R"(float4x2 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load = data[scalar_offset / 4];
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset_1 / 4];
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_2 = data[scalar_offset_2 / 4];
- const uint scalar_offset_3 = ((offset + 24u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_3 / 4];
- return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-})"},
- TypeCase{ty_mat4x3<f32>, R"(float4x3 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- const uint scalar_offset_2 = ((offset + 32u)) / 4;
- const uint scalar_offset_3 = ((offset + 48u)) / 4;
- return float4x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz), asfloat(data[scalar_offset_2 / 4].xyz), asfloat(data[scalar_offset_3 / 4].xyz));
-})"},
- TypeCase{ty_mat4x4<f32>, R"(float4x4 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- const uint scalar_offset_2 = ((offset + 32u)) / 4;
- const uint scalar_offset_3 = ((offset + 48u)) / 4;
- return float4x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]), asfloat(data[scalar_offset_2 / 4]), asfloat(data[scalar_offset_3 / 4]));
-})"},
- TypeCase{ty_mat2x2<f16>,
- R"(matrix<float16_t, 2, 2> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
- const uint scalar_offset_1 = ((offset + 4u)) / 4;
- uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
- return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
-})"},
- TypeCase{ty_mat2x3<f16>,
- R"(matrix<float16_t, 2, 3> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
- return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
-})"},
- TypeCase{ty_mat2x4<f16>,
- R"(matrix<float16_t, 2, 4> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
- return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
-})"},
- TypeCase{ty_mat3x2<f16>,
- R"(matrix<float16_t, 3, 2> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
- const uint scalar_offset_1 = ((offset + 4u)) / 4;
- uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
- const uint scalar_offset_2 = ((offset + 8u)) / 4;
- uint ubo_load_2 = data[scalar_offset_2 / 4][scalar_offset_2 % 4];
- return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
-})"},
- TypeCase{ty_mat3x3<f16>,
- R"(matrix<float16_t, 3, 3> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_5 = data[scalar_offset_2 / 4];
- uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
- vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
- float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
- return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
-})"},
- TypeCase{ty_mat3x4<f16>,
- R"(matrix<float16_t, 3, 4> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_5 = data[scalar_offset_2 / 4];
- uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
- vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
- vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
- return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));)"},
- TypeCase{ty_mat4x2<f16>,
- R"(matrix<float16_t, 4, 2> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
- const uint scalar_offset_1 = ((offset + 4u)) / 4;
- uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
- const uint scalar_offset_2 = ((offset + 8u)) / 4;
- uint ubo_load_2 = data[scalar_offset_2 / 4][scalar_offset_2 % 4];
- const uint scalar_offset_3 = ((offset + 12u)) / 4;
- uint ubo_load_3 = data[scalar_offset_3 / 4][scalar_offset_3 % 4];
- return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
-})"},
- TypeCase{ty_mat4x3<f16>,
- R"(matrix<float16_t, 4, 3> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_5 = data[scalar_offset_2 / 4];
- uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
- vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
- float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
- const uint scalar_offset_3 = ((offset + 24u)) / 4;
- uint4 ubo_load_7 = data[scalar_offset_3 / 4];
- uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
- vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
- float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
- return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
-})"},
- TypeCase{ty_mat4x4<f16>,
- R"(matrix<float16_t, 4, 4> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_5 = data[scalar_offset_2 / 4];
- uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
- vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
- vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
- const uint scalar_offset_3 = ((offset + 24u)) / 4;
- uint4 ubo_load_7 = data[scalar_offset_3 / 4];
- uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
- vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
- vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
- return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
-})"}));
-
-using HlslASTPrinterTest_MemberAccessor_UniformBufferLoad_DynamicOffset =
- HlslASTPrinterTest_MemberAccessorWithParam<TypeCase>;
-
-TEST_P(HlslASTPrinterTest_MemberAccessor_UniformBufferLoad_DynamicOffset, Test) {
- // struct Inner {
- // a : i32,
- // b : <type>,
- // c : vec4<i32>,
- // };
- // struct Data {
- // arr : array<Inner, 4i>,
- // }
- // var<uniform> data : Data;
- // data.arr[i].b;
-
- auto p = GetParam();
-
- Enable(wgsl::Extension::kF16);
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.i32()),
- Member("b", p.member_type(ty)),
- Member("c", ty.vec4(ty.i32())),
- });
-
- SetupUniformBuffer(Vector{
- Member("arr", ty.array(ty.Of(inner), 4_i)),
- });
-
- auto* i = Var("i", Expr(2_i));
-
- SetupFunction(Vector{
- Decl(i),
- Decl(Var("x", MemberAccessor(IndexAccessor(MemberAccessor("data", "arr"), i), "b"))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(p.expected));
-}
-
-INSTANTIATE_TEST_SUITE_P(
- HlslASTPrinterTest_MemberAccessor,
- HlslASTPrinterTest_MemberAccessor_UniformBufferLoad_DynamicOffset,
- testing::Values(
- TypeCase{ty_u32, "x = data[scalar_offset / 4][scalar_offset % 4]"},
- TypeCase{ty_f32, "x = asfloat(data[scalar_offset / 4][scalar_offset % 4])"},
- TypeCase{ty_i32, "x = asint(data[scalar_offset / 4][scalar_offset % 4])"},
- TypeCase{ty_f16, R"(const uint scalar_offset_bytes = (((32u * uint(i)) + 4u));
- const uint scalar_offset_index = scalar_offset_bytes / 4;
- float16_t x = float16_t(f16tof32(((data[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));)"},
- TypeCase{ty_vec2<u32>, R"(uint4 ubo_load = data[scalar_offset / 4];
- uint2 x = ((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy);)"},
- TypeCase{ty_vec2<f32>, R"(uint4 ubo_load = data[scalar_offset / 4];
- float2 x = asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy));)"},
- TypeCase{ty_vec2<i32>, R"(uint4 ubo_load = data[scalar_offset / 4];
- int2 x = asint(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy));)"},
- TypeCase{ty_vec2<f16>, R"(const uint scalar_offset = (((32u * uint(i)) + 4u)) / 4;
- uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
- vector<float16_t, 2> x = vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16)));)"},
- TypeCase{ty_vec3<u32>, "x = data[scalar_offset / 4].xyz"},
- TypeCase{ty_vec3<f32>, "x = asfloat(data[scalar_offset / 4].xyz)"},
- TypeCase{ty_vec3<i32>, "x = asint(data[scalar_offset / 4].xyz)"},
- TypeCase{ty_vec3<f16>, R"(const uint scalar_offset = (((32u * uint(i)) + 8u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
- vector<float16_t, 3> x = vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]);)"},
- TypeCase{ty_vec4<u32>, "x = data[scalar_offset / 4]"},
- TypeCase{ty_vec4<f32>, "x = asfloat(data[scalar_offset / 4])"},
- TypeCase{ty_vec4<i32>, "x = asint(data[scalar_offset / 4])"},
- TypeCase{ty_vec4<f16>, R"(const uint scalar_offset = (((32u * uint(i)) + 8u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
- vector<float16_t, 4> x = vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]);)"},
- TypeCase{ty_mat2x2<f32>, R"(float2x2 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load = data[scalar_offset / 4];
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset_1 / 4];
- return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-})"},
- TypeCase{ty_mat2x3<f32>, R"(float2x3 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- return float2x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz));
-})"},
- TypeCase{ty_mat2x4<f32>, R"(float2x4 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- return float2x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]));
-})"},
- TypeCase{ty_mat3x2<f32>, R"(float3x2 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load = data[scalar_offset / 4];
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset_1 / 4];
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_2 = data[scalar_offset_2 / 4];
- return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-})"},
- TypeCase{ty_mat3x3<f32>, R"(float3x3 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- const uint scalar_offset_2 = ((offset + 32u)) / 4;
- return float3x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz), asfloat(data[scalar_offset_2 / 4].xyz));
-})"},
- TypeCase{ty_mat3x4<f32>, R"(float3x4 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- const uint scalar_offset_2 = ((offset + 32u)) / 4;
- return float3x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]), asfloat(data[scalar_offset_2 / 4]));
-})"},
- TypeCase{ty_mat4x2<f32>, R"(float4x2 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load = data[scalar_offset / 4];
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset_1 / 4];
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_2 = data[scalar_offset_2 / 4];
- const uint scalar_offset_3 = ((offset + 24u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_3 / 4];
- return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-})"},
- TypeCase{ty_mat4x3<f32>, R"(float4x3 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- const uint scalar_offset_2 = ((offset + 32u)) / 4;
- const uint scalar_offset_3 = ((offset + 48u)) / 4;
- return float4x3(asfloat(data[scalar_offset / 4].xyz), asfloat(data[scalar_offset_1 / 4].xyz), asfloat(data[scalar_offset_2 / 4].xyz), asfloat(data[scalar_offset_3 / 4].xyz));
-})"},
- TypeCase{ty_mat4x4<f32>, R"(float4x4 data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- const uint scalar_offset_1 = ((offset + 16u)) / 4;
- const uint scalar_offset_2 = ((offset + 32u)) / 4;
- const uint scalar_offset_3 = ((offset + 48u)) / 4;
- return float4x4(asfloat(data[scalar_offset / 4]), asfloat(data[scalar_offset_1 / 4]), asfloat(data[scalar_offset_2 / 4]), asfloat(data[scalar_offset_3 / 4]));
-})"},
- TypeCase{ty_mat2x2<f16>,
- R"(matrix<float16_t, 2, 2> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
- const uint scalar_offset_1 = ((offset + 4u)) / 4;
- uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
- return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
-})"},
- TypeCase{ty_mat2x3<f16>,
- R"(matrix<float16_t, 2, 3> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
- return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
-})"},
- TypeCase{ty_mat2x4<f16>,
- R"(matrix<float16_t, 2, 4> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
- return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
-})"},
- TypeCase{ty_mat3x2<f16>,
- R"(matrix<float16_t, 3, 2> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
- const uint scalar_offset_1 = ((offset + 4u)) / 4;
- uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
- const uint scalar_offset_2 = ((offset + 8u)) / 4;
- uint ubo_load_2 = data[scalar_offset_2 / 4][scalar_offset_2 % 4];
- return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
-})"},
- TypeCase{ty_mat3x3<f16>,
- R"(matrix<float16_t, 3, 3> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_5 = data[scalar_offset_2 / 4];
- uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
- vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
- float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
- return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
-})"},
- TypeCase{ty_mat3x4<f16>,
- R"(matrix<float16_t, 3, 4> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_5 = data[scalar_offset_2 / 4];
- uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
- vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
- vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
- return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
-})"},
- TypeCase{ty_mat4x2<f16>,
- R"(matrix<float16_t, 4, 2> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint ubo_load = data[scalar_offset / 4][scalar_offset % 4];
- const uint scalar_offset_1 = ((offset + 4u)) / 4;
- uint ubo_load_1 = data[scalar_offset_1 / 4][scalar_offset_1 % 4];
- const uint scalar_offset_2 = ((offset + 8u)) / 4;
- uint ubo_load_2 = data[scalar_offset_2 / 4][scalar_offset_2 % 4];
- const uint scalar_offset_3 = ((offset + 12u)) / 4;
- uint ubo_load_3 = data[scalar_offset_3 / 4][scalar_offset_3 % 4];
- return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
-})"},
- TypeCase{ty_mat4x3<f16>,
- R"(matrix<float16_t, 4, 3> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_5 = data[scalar_offset_2 / 4];
- uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
- vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
- float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
- const uint scalar_offset_3 = ((offset + 24u)) / 4;
- uint4 ubo_load_7 = data[scalar_offset_3 / 4];
- uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
- vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
- float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
- return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
-})"},
- TypeCase{ty_mat4x4<f16>,
- R"(matrix<float16_t, 4, 4> data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- uint4 ubo_load_1 = data[scalar_offset / 4];
- uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
- vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
- vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
- const uint scalar_offset_1 = ((offset + 8u)) / 4;
- uint4 ubo_load_3 = data[scalar_offset_1 / 4];
- uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
- vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
- vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
- const uint scalar_offset_2 = ((offset + 16u)) / 4;
- uint4 ubo_load_5 = data[scalar_offset_2 / 4];
- uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
- vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
- vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
- const uint scalar_offset_3 = ((offset + 24u)) / 4;
- uint4 ubo_load_7 = data[scalar_offset_3 / 4];
- uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
- vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
- vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
- return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
-})"}));
-
-using HlslASTPrinterTest_MemberAccessor_StorageBufferStore =
- HlslASTPrinterTest_MemberAccessorWithParam<TypeCase>;
-TEST_P(HlslASTPrinterTest_MemberAccessor_StorageBufferStore, Test) {
- // struct Data {
- // a : i32,
- // b : <type>,
- // };
- // var<storage> data : Data;
- // data.b = <type>();
-
- auto p = GetParam();
-
- Enable(wgsl::Extension::kF16);
-
- SetupStorageBuffer(Vector{
- Member("a", ty.i32()),
- Member("b", p.member_type(ty)),
- });
-
- SetupFunction(Vector{
- Decl(Var("value", p.member_type(ty), Call(p.member_type(ty)))),
- Assign(MemberAccessor("data", "b"), Expr("value")),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(p.expected));
-}
-
-INSTANTIATE_TEST_SUITE_P(
- HlslASTPrinterTest_MemberAccessor,
- HlslASTPrinterTest_MemberAccessor_StorageBufferStore,
- testing::Values(TypeCase{ty_u32, "data.Store(4u, asuint(value))"},
- TypeCase{ty_f32, "data.Store(4u, asuint(value))"},
- TypeCase{ty_i32, "data.Store(4u, asuint(value))"},
- TypeCase{ty_f16, "data.Store<float16_t>(4u, value)"},
- TypeCase{ty_vec2<u32>, "data.Store2(8u, asuint(value))"},
- TypeCase{ty_vec2<f32>, "data.Store2(8u, asuint(value))"},
- TypeCase{ty_vec2<i32>, "data.Store2(8u, asuint(value))"},
- TypeCase{ty_vec2<f16>, "data.Store<vector<float16_t, 2> >(4u, value)"},
- TypeCase{ty_vec3<u32>, "data.Store3(16u, asuint(value))"},
- TypeCase{ty_vec3<f32>, "data.Store3(16u, asuint(value))"},
- TypeCase{ty_vec3<i32>, "data.Store3(16u, asuint(value))"},
- TypeCase{ty_vec3<f16>, "data.Store<vector<float16_t, 3> >(8u, value)"},
- TypeCase{ty_vec4<u32>, "data.Store4(16u, asuint(value))"},
- TypeCase{ty_vec4<f32>, "data.Store4(16u, asuint(value))"},
- TypeCase{ty_vec4<i32>, "data.Store4(16u, asuint(value))"},
- TypeCase{ty_vec4<f16>, "data.Store<vector<float16_t, 4> >(8u, value)"},
- TypeCase{ty_mat2x2<f32>, R"(
-
-void data_store(uint offset, float2x2 value) {
- data.Store2((offset + 0u), asuint(value[0u]));
- data.Store2((offset + 8u), asuint(value[1u]));
-})"},
- TypeCase{ty_mat2x3<f32>, R"({
- data.Store3((offset + 0u), asuint(value[0u]));
- data.Store3((offset + 16u), asuint(value[1u]));
-})"},
- TypeCase{ty_mat2x4<f32>, R"({
- data.Store4((offset + 0u), asuint(value[0u]));
- data.Store4((offset + 16u), asuint(value[1u]));
-})"},
- TypeCase{ty_mat3x2<f32>, R"({
- data.Store2((offset + 0u), asuint(value[0u]));
- data.Store2((offset + 8u), asuint(value[1u]));
- data.Store2((offset + 16u), asuint(value[2u]));
-})"},
- TypeCase{ty_mat3x3<f32>, R"({
- data.Store3((offset + 0u), asuint(value[0u]));
- data.Store3((offset + 16u), asuint(value[1u]));
- data.Store3((offset + 32u), asuint(value[2u]));
-})"},
- TypeCase{ty_mat3x4<f32>, R"({
- data.Store4((offset + 0u), asuint(value[0u]));
- data.Store4((offset + 16u), asuint(value[1u]));
- data.Store4((offset + 32u), asuint(value[2u]));
-})"},
- TypeCase{ty_mat4x2<f32>, R"({
- data.Store2((offset + 0u), asuint(value[0u]));
- data.Store2((offset + 8u), asuint(value[1u]));
- data.Store2((offset + 16u), asuint(value[2u]));
- data.Store2((offset + 24u), asuint(value[3u]));
-})"},
- TypeCase{ty_mat4x3<f32>, R"({
- data.Store3((offset + 0u), asuint(value[0u]));
- data.Store3((offset + 16u), asuint(value[1u]));
- data.Store3((offset + 32u), asuint(value[2u]));
- data.Store3((offset + 48u), asuint(value[3u]));
-})"},
- TypeCase{ty_mat4x4<f32>, R"({
- data.Store4((offset + 0u), asuint(value[0u]));
- data.Store4((offset + 16u), asuint(value[1u]));
- data.Store4((offset + 32u), asuint(value[2u]));
- data.Store4((offset + 48u), asuint(value[3u]));
-})"},
- TypeCase{ty_mat2x2<f16>, R"({
- data.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
- data.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
-})"},
- TypeCase{ty_mat2x3<f16>, R"({
- data.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
- data.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
-})"},
- TypeCase{ty_mat2x4<f16>, R"({
- data.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
- data.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
-})"},
- TypeCase{ty_mat3x2<f16>, R"({
- data.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
- data.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
- data.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
-})"},
- TypeCase{ty_mat3x3<f16>, R"({
- data.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
- data.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
- data.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
-})"},
- TypeCase{ty_mat3x4<f16>, R"({
- data.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
- data.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
- data.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
-})"},
- TypeCase{ty_mat4x2<f16>, R"({
- data.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
- data.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
- data.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
- data.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
-})"},
- TypeCase{ty_mat4x3<f16>, R"({
- data.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
- data.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
- data.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
- data.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
-})"},
- TypeCase{ty_mat4x4<f16>, R"({
- data.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
- data.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
- data.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
- data.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
-})"}));
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, StorageBuffer_Store_Matrix_Empty) {
- // struct Data {
- // a : f32,
- // b : mat2x3<f32>,
- // };
- // var<storage> data : Data;
- // data.b = mat2x3<f32>();
-
- SetupStorageBuffer(Vector{
- Member("a", ty.i32()),
- Member("b", ty.mat2x3<f32>()),
- });
-
- SetupFunction(Vector{
- Assign(MemberAccessor("data", "b"), Call<mat2x3<f32>>()),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void data_store(uint offset, float2x3 value) {
- data.Store3((offset + 0u), asuint(value[0u]));
- data.Store3((offset + 16u), asuint(value[1u]));
-}
-
-void main() {
- data_store(16u, float2x3((0.0f).xxx, (0.0f).xxx));
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, StorageBuffer_Load_Matrix_F32_Single_Element) {
- // struct Data {
- // z : f32,
- // a : mat4x3<f32>,
- // };
- // var<storage> data : Data;
- // data.a[2i][1i];
-
- SetupStorageBuffer(Vector{
- Member("z", ty.f32()),
- Member("a", ty.mat4x3<f32>()),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", IndexAccessor(IndexAccessor(MemberAccessor("data", "a"), 2_i), 1_i))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void main() {
- float x = asfloat(data.Load(52u));
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, StorageBuffer_Load_Matrix_F16_Single_Element) {
- // struct Data {
- // z : f16,
- // a : mat4x3<f16>,
- // };
- // var<storage> data : Data;
- // data.a[2i][1i];
-
- Enable(wgsl::Extension::kF16);
-
- SetupStorageBuffer(Vector{
- Member("z", ty.f16()),
- Member("a", ty.mat4x3<f16>()),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", IndexAccessor(IndexAccessor(MemberAccessor("data", "a"), 2_i), 1_i))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void main() {
- float16_t x = data.Load<float16_t>(26u);
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, UniformBuffer_Load_Matrix_F32_Single_Element) {
- // struct Data {
- // z : f32,
- // a : mat4x3<f32>,
- // };
- // var<uniform> data : Data;
- // data.a[2i][1i];
-
- SetupUniformBuffer(Vector{
- Member("z", ty.f32()),
- Member("a", ty.mat4x3<f32>()),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", IndexAccessor(IndexAccessor(MemberAccessor("data", "a"), 2_i), 1_i))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(cbuffer cbuffer_data : register(b1, space1) {
- uint4 data[5];
-};
-
-void main() {
- float x = asfloat(data[3].y);
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, UniformBuffer_Load_Matrix_F16_Single_Element) {
- // struct Data {
- // z : f16,
- // a : mat4x3<f16>,
- // };
- // var<uniform> data : Data;
- // data.a[2i][1i];
-
- Enable(wgsl::Extension::kF16);
-
- SetupUniformBuffer(Vector{
- Member("z", ty.f16()),
- Member("a", ty.mat4x3<f16>()),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", IndexAccessor(IndexAccessor(MemberAccessor("data", "a"), 2_i), 1_i))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(cbuffer cbuffer_data : register(b1, space1) {
- uint4 data[3];
-};
-
-void main() {
- float16_t x = float16_t(f16tof32(((data[1].z >> 16) & 0xFFFF)));
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor,
- EmitExpression_IndexAccessor_StorageBuffer_Load_I32_FromArray) {
- // struct Data {
- // z : f32,
- // a : array<i32, 5i>,
- // };
- // var<storage> data : Data;
- // data.a[2];
-
- SetupStorageBuffer(Vector{
- Member("z", ty.f32()),
- Member("a", ty.array<i32, 5>()),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", IndexAccessor(MemberAccessor("data", "a"), 2_i))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void main() {
- int x = asint(data.Load(12u));
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor,
- EmitExpression_IndexAccessor_UniformBuffer_Load_Vec4_I32_FromArray) {
- // struct Data {
- // z : f32,
- // a : array<vec4<i32>, 5i>,
- // };
- // var<uniform> data : Data;
- // data.a[2];
-
- SetupUniformBuffer(Vector{
- Member("z", ty.f32()),
- Member("a", ty.array<vec4<i32>, 5>()),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", IndexAccessor(MemberAccessor("data", "a"), 2_i))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(cbuffer cbuffer_data : register(b1, space1) {
- uint4 data[6];
-};
-
-void main() {
- int4 x = asint(data[3]);
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor,
- EmitExpression_IndexAccessor_StorageBuffer_Load_Struct_FromArray) {
- // struct Inner {
- // @size(16i) @align(16i)
- // v : i32,
- // };
- // struct Data {
- // z : f32,
- // a : array<Inner, 5i>,
- // };
- // var<storage> data : Data;
- // data.a[2i];
-
- auto* elem_type =
- Structure("Inner", Vector{
- Member("v", ty.i32(), Vector{MemberSize(16_i), MemberAlign(16_i)}),
- });
-
- SetupStorageBuffer(Vector{
- Member("z", ty.f32()),
- Member("a", ty.array(ty.Of(elem_type), 5_i)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", IndexAccessor(MemberAccessor("data", "a"), 2_i))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(struct Inner {
- int v;
-};
-
-RWByteAddressBuffer data : register(u0, space1);
-
-Inner data_load(uint offset) {
- Inner tint_symbol = {asint(data.Load((offset + 0u)))};
- return tint_symbol;
-}
-
-void main() {
- Inner x = data_load(48u);
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor,
- EmitExpression_IndexAccessor_UniformBuffer_Load_Struct_FromArray) {
- // struct Inner {
- // @size(16i) @align(16i)
- // v : i32,
- // };
- // struct Data {
- // z : f32,
- // a : array<Inner, 5i>,
- // };
- // var<uniform> data : Data;
- // data.a[2i];
-
- auto* elem_type =
- Structure("Inner", Vector{
- Member("v", ty.i32(), Vector{MemberSize(16_i), MemberAlign(16_i)}),
- });
-
- SetupUniformBuffer(Vector{
- Member("z", ty.f32()),
- Member("a", ty.array(ty.Of(elem_type), 5_i)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", IndexAccessor(MemberAccessor("data", "a"), 2_i))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(struct Inner {
- int v;
-};
-
-cbuffer cbuffer_data : register(b1, space1) {
- uint4 data[6];
-};
-
-Inner data_load(uint offset) {
- const uint scalar_offset = ((offset + 0u)) / 4;
- Inner tint_symbol = {asint(data[scalar_offset / 4][scalar_offset % 4])};
- return tint_symbol;
-}
-
-void main() {
- Inner x = data_load(48u);
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor,
- EmitExpression_IndexAccessor_StorageBuffer_Load_I32_FromArray_ExprIdx) {
- // struct Data {
- // z : f32,
- // a : array<i32, 5i>,
- // };
- // var<storage> data : Data;
- // data.a[(2i + 4i) - 3i];
-
- SetupStorageBuffer(Vector{
- Member("z", ty.f32()),
- Member("a", ty.array<i32, 5>()),
- });
-
- SetupFunction(Vector{
- Decl(Var("a", Expr(2_i))),
- Decl(Var("b", Expr(4_i))),
- Decl(Var("c", Expr(3_i))),
- Decl(Var("x", IndexAccessor(MemberAccessor("data", "a"), Sub(Add("a", "b"), "c")))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void main() {
- int a = 2;
- int b = 4;
- int c = 3;
- int x = asint(data.Load((4u + (4u * uint(((a + b) - c))))));
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor,
- EmitExpression_IndexAccessor_UniformBuffer_Load_Vec4_I32_FromArray_ExprIdx) {
- // struct Data {
- // z : f32,
- // a : array<vec4<i32>, 5i>,
- // };
- // var<uniform> data : Data;
- // data.a[(2i + 4i) - 3i];
-
- SetupUniformBuffer(Vector{
- Member("z", ty.f32()),
- Member("a", ty.array<vec4<i32>, 5>()),
- });
-
- SetupFunction(Vector{
- Decl(Var("a", Expr(2_i))),
- Decl(Var("b", Expr(4_i))),
- Decl(Var("c", Expr(3_i))),
- Decl(Var("x", IndexAccessor(MemberAccessor("data", "a"), Sub(Add("a", "b"), "c")))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(cbuffer cbuffer_data : register(b1, space1) {
- uint4 data[6];
-};
-
-void main() {
- int a = 2;
- int b = 4;
- int c = 3;
- const uint scalar_offset = ((16u + (16u * uint(((a + b) - c))))) / 4;
- int4 x = asint(data[scalar_offset / 4]);
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, StorageBuffer_Store_ToArray) {
- // struct Data {
- // a : array<i32, 5i>,
- // };
- // var<storage> data : Data;
- // data.a[2i] = 2i;
-
- SetupStorageBuffer(Vector{
- Member("z", ty.f32()),
- Member("a", ty.array<i32, 5>()),
- });
-
- SetupFunction(Vector{
- Assign(IndexAccessor(MemberAccessor("data", "a"), 2_i), 2_i),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void main() {
- data.Store(12u, asuint(2));
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
- // struct Inner {
- // a : vec3<i32>,
- // b : vec3<f32>,
- // };
- // struct Data {
- // c : array<Inner, 4u>,
- // };
- //
- // var<storage> data : Data;
- // data.c[2i].b
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.vec3<i32>()),
- Member("b", ty.vec3<f32>()),
- });
-
- SetupStorageBuffer(Vector{
- Member("c", ty.array(ty.Of(inner), 4_u)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void main() {
- float3 x = asfloat(data.Load3(80u));
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, UniformBuffer_Load_MultiLevel) {
- // struct Inner {
- // a : vec3<i32>,
- // b : vec3<f32>,
- // };
- // struct Data {
- // var c : array<Inner, 4u>,
- // };
- //
- // var<storage> data : Data;
- // data.c[2i].b
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.vec3<i32>()),
- Member("b", ty.vec3<f32>()),
- });
-
- SetupUniformBuffer(Vector{
- Member("c", ty.array(ty.Of(inner), 4_u)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x", MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(cbuffer cbuffer_data : register(b1, space1) {
- uint4 data[8];
-};
-
-void main() {
- float3 x = asfloat(data[5].xyz);
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, StorageBuffer_Load_MultiLevel_Swizzle) {
- // struct Inner {
- // a : vec3<i32>,
- // b : vec3<f32>,
- // };
- // struct Data {
- // var c : array<Inner, 4u>,
- // };
- //
- // var<storage> data : Data;
- // data.c[2i].b.yx
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.vec3<i32>()),
- Member("b", ty.vec3<f32>()),
- });
-
- SetupStorageBuffer(Vector{
- Member("c", ty.array(ty.Of(inner), 4_u)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x",
- MemberAccessor(
- MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "yx"))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void main() {
- float2 x = asfloat(data.Load3(80u)).yx;
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, UniformBuffer_Load_MultiLevel_Swizzle) {
- // struct Inner {
- // a : vec3<i32>,
- // b : vec3<f32>,
- // };
- // struct Data {
- // var c : array<Inner, 4u>,
- // };
- //
- // var<uniform> data : Data;
- // data.c[2i].b.yx
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.vec3<i32>()),
- Member("b", ty.vec3<f32>()),
- });
-
- SetupUniformBuffer(Vector{
- Member("c", ty.array(ty.Of(inner), 4_u)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x",
- MemberAccessor(
- MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "yx"))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(cbuffer cbuffer_data : register(b1, space1) {
- uint4 data[8];
-};
-
-void main() {
- float2 x = asfloat(data[5].xyz).yx;
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor,
- StorageBuffer_Load_MultiLevel_Swizzle_SingleLetter) { // NOLINT
- // struct Inner {
- // a : vec3<i32>,
- // b : vec3<f32>,
- // };
- // struct Data {
- // var c : array<Inner, 4u>,
- // };
- //
- // var<storage> data : Data;
- // data.c[2i].b.g
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.vec3<i32>()),
- Member("b", ty.vec3<f32>()),
- });
-
- SetupStorageBuffer(Vector{
- Member("c", ty.array(ty.Of(inner), 4_u)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x",
- MemberAccessor(
- MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "g"))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void main() {
- float x = asfloat(data.Load(84u));
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor,
- UniformBuffer_Load_MultiLevel_Swizzle_SingleLetter) { // NOLINT
- // struct Inner {
- // a : vec3<i32>,
- // b : vec3<f32>,
- // };
- // struct Data {
- // var c : array<Inner, 4u>,
- // };
- //
- // var<uniform> data : Data;
- // data.c[2i].b.g
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.vec3<i32>()),
- Member("b", ty.vec3<f32>()),
- });
-
- SetupUniformBuffer(Vector{
- Member("c", ty.array(ty.Of(inner), 4_u)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x",
- MemberAccessor(
- MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "g"))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(cbuffer cbuffer_data : register(b1, space1) {
- uint4 data[8];
-};
-
-void main() {
- float x = asfloat(data[5].y);
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, StorageBuffer_Load_MultiLevel_Index) {
- // struct Inner {
- // a : vec3<i32>,
- // b : vec3<f32>,
- // };
- // struct Data {
- // var c : array<Inner, 4u>,
- // };
- //
- // var<storage> data : Data;
- // data.c[2i].b[1i]
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.vec3<i32>()),
- Member("b", ty.vec3<f32>()),
- });
-
- SetupStorageBuffer(Vector{
- Member("c", ty.array(ty.Of(inner), 4_u)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x",
- IndexAccessor(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
- 1_i))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void main() {
- float x = asfloat(data.Load(84u));
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, UniformBuffer_Load_MultiLevel_Index) {
- // struct Inner {
- // a : vec3<i32>,
- // b : vec3<f32>,
- // };
- // struct Data {
- // var c : array<Inner, 4u>,
- // };
- //
- // var<uniform> data : Data;
- // data.c[2i].b[1i]
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.vec3<i32>()),
- Member("b", ty.vec3<f32>()),
- });
-
- SetupUniformBuffer(Vector{
- Member("c", ty.array(ty.Of(inner), 4_u)),
- });
-
- SetupFunction(Vector{
- Decl(Var("x",
- IndexAccessor(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
- 1_i))),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(cbuffer cbuffer_data : register(b1, space1) {
- uint4 data[8];
-};
-
-void main() {
- float x = asfloat(data[5].y);
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
- // struct Inner {
- // a : vec3<i32>,
- // b : vec3<f32>,
- // };
- // struct Data {
- // var c : array<Inner, 4u>,
- // };
- //
- // var<storage> data : Pre;
- // data.c[2i].b = vec3<f32>(1_f, 2_f, 3_f);
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.vec3<i32>()),
- Member("b", ty.vec3<f32>()),
- });
-
- SetupStorageBuffer(Vector{
- Member("c", ty.array(ty.Of(inner), 4_u)),
- });
-
- SetupFunction(Vector{
- Assign(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
- Call<vec3<f32>>(1_f, 2_f, 3_f)),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void main() {
- data.Store3(80u, asuint(float3(1.0f, 2.0f, 3.0f)));
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, StorageBuffer_Store_Swizzle_SingleLetter) {
- // struct Inner {
- // a : vec3<i32>,
- // b : vec3<f32>,
- // };
- // struct Data {
- // var c : array<Inner, 4u>,
- // };
- //
- // var<storage> data : Pre;
- // data.c[2i].b.y = 1.f;
-
- auto* inner = Structure("Inner", Vector{
- Member("a", ty.vec3<i32>()),
- Member("b", ty.vec3<f32>()),
- });
-
- SetupStorageBuffer(Vector{
- Member("c", ty.array(ty.Of(inner), 4_u)),
- });
-
- SetupFunction(Vector{
- Assign(MemberAccessor(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
- "y"),
- Expr(1_f)),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- auto* expected =
- R"(RWByteAddressBuffer data : register(u0, space1);
-
-void main() {
- data.Store(84u, asuint(1.0f));
- return;
-}
-)";
- EXPECT_EQ(gen.Result(), expected);
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, Swizzle_xyz) {
- auto* var = Var("my_vec", ty.vec4<f32>(), Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f));
- auto* expr = MemberAccessor("my_vec", "xyz");
- WrapInFunction(var, expr);
-
- ASTPrinter& gen = SanitizeAndBuild();
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("my_vec.xyz"));
-}
-
-TEST_F(HlslASTPrinterTest_MemberAccessor, Swizzle_gbr) {
- auto* var = Var("my_vec", ty.vec4<f32>(), Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f));
- auto* expr = MemberAccessor("my_vec", "gbr");
- WrapInFunction(var, expr);
-
- ASTPrinter& gen = SanitizeAndBuild();
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("my_vec.gbr"));
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/module_constant_test.cc b/src/tint/lang/hlsl/writer/ast_printer/module_constant_test.cc
deleted file mode 100644
index 17559d3..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/module_constant_test.cc
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/lang/wgsl/ast/id_attribute.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-using HlslASTPrinterTest_ModuleConstant = TestHelper;
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_AInt) {
- auto* var = GlobalConst("G", Expr(1_a));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- int l = 1;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_AFloat) {
- auto* var = GlobalConst("G", Expr(1._a));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float l = 1.0f;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_i32) {
- auto* var = GlobalConst("G", Expr(1_i));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- int l = 1;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_u32) {
- auto* var = GlobalConst("G", Expr(1_u));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- uint l = 1u;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_f32) {
- auto* var = GlobalConst("G", Expr(1_f));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float l = 1.0f;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* var = GlobalConst("G", Expr(1_h));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float16_t l = float16_t(1.0h);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_vec3_AInt) {
- auto* var = GlobalConst("G", Call<vec3<Infer>>(1_a, 2_a, 3_a));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- int3 l = int3(1, 2, 3);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_vec3_AFloat) {
- auto* var = GlobalConst("G", Call<vec3<Infer>>(1._a, 2._a, 3._a));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float3 l = float3(1.0f, 2.0f, 3.0f);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_vec3_f32) {
- auto* var = GlobalConst("G", Call<vec3<f32>>(1_f, 2_f, 3_f));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float3 l = float3(1.0f, 2.0f, 3.0f);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_vec3_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* var = GlobalConst("G", Call<vec3<f16>>(1_h, 2_h, 3_h));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- vector<float16_t, 3> l = vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h));
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_mat2x3_AFloat) {
- auto* var = GlobalConst("G", Call<mat2x3<Infer>>(1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_mat2x3_f32) {
- auto* var = GlobalConst("G", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_mat2x3_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* var = GlobalConst("G", Call<mat2x3<f16>>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- matrix<float16_t, 2, 3> l = matrix<float16_t, 2, 3>(vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h)), vector<float16_t, 3>(float16_t(4.0h), float16_t(5.0h), float16_t(6.0h)));
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_arr_f32) {
- auto* var = GlobalConst("G", Call<array<f32, 3>>(1_f, 2_f, 3_f));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float l[3] = {1.0f, 2.0f, 3.0f};
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_ModuleConstant, Emit_GlobalConst_arr_vec2_bool) {
- auto* var = GlobalConst("G", Call<array<vec2<bool>, 3>>( //
- Call<vec2<bool>>(true, false), //
- Call<vec2<bool>>(false, true), //
- Call<vec2<bool>>(true, true)));
- Func("f", tint::Empty, ty.void_(), Vector{Decl(Let("l", Expr(var)))});
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- bool2 l[3] = {bool2(true, false), bool2(false, true), (true).xx};
-}
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/return_test.cc b/src/tint/lang/hlsl/writer/ast_printer/return_test.cc
deleted file mode 100644
index 8cb83da..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/return_test.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-
-using namespace tint::core::number_suffixes; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Return = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Return, Emit_Return) {
- auto* r = Return();
- WrapInFunction(r);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(r)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), " return;\n");
-}
-
-TEST_F(HlslASTPrinterTest_Return, Emit_ReturnWithValue) {
- auto* r = Return(123_i);
- Func("f", tint::Empty, ty.i32(), Vector{r});
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(r)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), " return 123;\n");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/sanitizer_test.cc b/src/tint/lang/hlsl/writer/ast_printer/sanitizer_test.cc
deleted file mode 100644
index 72bfc3b..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/sanitizer_test.cc
+++ /dev/null
@@ -1,325 +0,0 @@
-// Copyright 2021 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/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/lang/wgsl/ast/call_statement.h"
-#include "src/tint/lang/wgsl/ast/stage_attribute.h"
-#include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-using HlslSanitizerTest = TestHelper;
-
-TEST_F(HlslSanitizerTest, Call_ArrayLength) {
- auto* s = Structure("my_struct", Vector{Member(0, "a", ty.array<f32>())});
- GlobalVar("b", ty.Of(s), core::AddressSpace::kStorage, core::Access::kRead, Binding(1_a),
- Group(2_a));
-
- Func("a_func", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("len", ty.u32(), Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- auto got = gen.Result();
- auto* expect = R"(ByteAddressBuffer b : register(t1, space2);
-
-void a_func() {
- uint tint_symbol_1 = 0u;
- b.GetDimensions(tint_symbol_1);
- uint tint_symbol_2 = ((tint_symbol_1 - 0u) / 4u);
- uint len = tint_symbol_2;
- return;
-}
-)";
- EXPECT_EQ(expect, got);
-}
-
-TEST_F(HlslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
- auto* s = Structure("my_struct", Vector{
- Member(0, "z", ty.f32()),
- Member(4, "a", ty.array<f32>()),
- });
- GlobalVar("b", ty.Of(s), core::AddressSpace::kStorage, core::Access::kRead, Binding(1_a),
- Group(2_a));
-
- Func("a_func", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("len", ty.u32(), Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- auto got = gen.Result();
- auto* expect = R"(ByteAddressBuffer b : register(t1, space2);
-
-void a_func() {
- uint tint_symbol_1 = 0u;
- b.GetDimensions(tint_symbol_1);
- uint tint_symbol_2 = ((tint_symbol_1 - 4u) / 4u);
- uint len = tint_symbol_2;
- return;
-}
-)";
-
- EXPECT_EQ(expect, got);
-}
-
-TEST_F(HlslSanitizerTest, Call_ArrayLength_ViaLets) {
- auto* s = Structure("my_struct", Vector{Member(0, "a", ty.array<f32>())});
- GlobalVar("b", ty.Of(s), core::AddressSpace::kStorage, core::Access::kRead, Binding(1_a),
- Group(2_a));
-
- auto* p = Let("p", AddressOf("b"));
- auto* p2 = Let("p2", AddressOf(MemberAccessor(Deref(p), "a")));
-
- Func("a_func", tint::Empty, ty.void_(),
- Vector{
- Decl(p),
- Decl(p2),
- Decl(Var("len", ty.u32(), Call("arrayLength", p2))),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- auto got = gen.Result();
- auto* expect = R"(ByteAddressBuffer b : register(t1, space2);
-
-void a_func() {
- uint tint_symbol_1 = 0u;
- b.GetDimensions(tint_symbol_1);
- uint tint_symbol_2 = ((tint_symbol_1 - 0u) / 4u);
- uint len = tint_symbol_2;
- return;
-}
-)";
-
- EXPECT_EQ(expect, got);
-}
-
-TEST_F(HlslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniform) {
- auto* s = Structure("my_struct", Vector{Member(0, "a", ty.array<f32>())});
- GlobalVar("b", ty.Of(s), core::AddressSpace::kStorage, core::Access::kRead, Binding(1_a),
- Group(2_a));
- GlobalVar("c", ty.Of(s), core::AddressSpace::kStorage, core::Access::kRead, Binding(2_a),
- Group(2_a));
-
- Func("a_func", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("len", ty.u32(),
- Add(Call("arrayLength", AddressOf(MemberAccessor("b", "a"))),
- Call("arrayLength", AddressOf(MemberAccessor("c", "a")))))),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- Options options;
- options.array_length_from_uniform.ubo_binding = {3, 4};
- options.array_length_from_uniform.bindpoint_to_size_index.emplace(BindingPoint{2, 2}, 7u);
- ASTPrinter& gen = SanitizeAndBuild(options);
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- auto got = gen.Result();
- auto* expect = R"(cbuffer cbuffer_tint_array_lengths : register(b4, space3) {
- uint4 tint_array_lengths[2];
-};
-ByteAddressBuffer b : register(t1, space2);
-ByteAddressBuffer c : register(t2, space2);
-
-void a_func() {
- uint tint_symbol_1 = 0u;
- b.GetDimensions(tint_symbol_1);
- uint tint_symbol_2 = ((tint_symbol_1 - 0u) / 4u);
- uint len = (tint_symbol_2 + ((tint_array_lengths[1].w - 0u) / 4u));
- return;
-}
-)";
- EXPECT_EQ(expect, got);
-}
-
-TEST_F(HlslSanitizerTest, PromoteArrayInitializerToConstVar) {
- auto* array_init = Call<array<i32, 4>>(1_i, 2_i, 3_i, 4_i);
-
- Func("main", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("idx", Expr(3_i))),
- Decl(Var("pos", ty.i32(), IndexAccessor(array_init, "idx"))),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- auto got = gen.Result();
- auto* expect = R"(void main() {
- int idx = 3;
- int tint_symbol[4] = {1, 2, 3, 4};
- int pos = tint_symbol[idx];
- return;
-}
-)";
- EXPECT_EQ(expect, got);
-}
-
-TEST_F(HlslSanitizerTest, PromoteStructInitializerToConstVar) {
- auto* runtime_value = Var("runtime_value", Expr(3_f));
- auto* str = Structure("S", Vector{
- Member("a", ty.i32()),
- Member("b", ty.vec3<f32>()),
- Member("c", ty.i32()),
- });
- auto* struct_init = Call(ty.Of(str), 1_i, Call<vec3<f32>>(2_f, runtime_value, 4_f), 4_i);
- auto* struct_access = MemberAccessor(struct_init, "b");
- auto* pos = Var("pos", ty.vec3<f32>(), struct_access);
-
- Func("main", tint::Empty, ty.void_(),
- Vector{
- Decl(runtime_value),
- Decl(pos),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- auto got = gen.Result();
- auto* expect = R"(struct S {
- int a;
- float3 b;
- int c;
-};
-
-void main() {
- float runtime_value = 3.0f;
- S tint_symbol = {1, float3(2.0f, runtime_value, 4.0f), 4};
- float3 pos = tint_symbol.b;
- return;
-}
-)";
- EXPECT_EQ(expect, got);
-}
-
-TEST_F(HlslSanitizerTest, SimplifyPointersBasic) {
- // var v : i32;
- // let p : ptr<function, i32> = &v;
- // let x : i32 = *p;
- auto* v = Var("v", ty.i32());
- auto* p = Let("p", ty.ptr<function, i32>(), AddressOf(v));
- auto* x = Var("x", ty.i32(), Deref(p));
-
- Func("main", tint::Empty, ty.void_(),
- Vector{
- Decl(v),
- Decl(p),
- Decl(x),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- auto got = gen.Result();
- auto* expect = R"(void main() {
- int v = 0;
- int x = v;
- return;
-}
-)";
- EXPECT_EQ(expect, got);
-}
-
-TEST_F(HlslSanitizerTest, SimplifyPointersComplexChain) {
- // var a : array<mat4x4<f32>, 4u>;
- // let ap : ptr<function, array<mat4x4<f32>, 4u>> = &a;
- // let mp : ptr<function, mat4x4<f32>> = &(*ap)[3i];
- // let vp : ptr<function, vec4<f32>> = &(*mp)[2i];
- // let v : vec4<f32> = *vp;
- auto* a = Var("a", ty.array(ty.mat4x4<f32>(), 4_u));
- auto* ap = Let("ap", ty.ptr<function, array<mat4x4<f32>, 4>>(), AddressOf(a));
- auto* mp = Let("mp", ty.ptr<function, mat4x4<f32>>(), AddressOf(IndexAccessor(Deref(ap), 3_i)));
- auto* vp = Let("vp", ty.ptr<function, vec4<f32>>(), AddressOf(IndexAccessor(Deref(mp), 2_i)));
- auto* v = Var("v", ty.vec4<f32>(), Deref(vp));
-
- Func("main", tint::Empty, ty.void_(),
- Vector{
- Decl(a),
- Decl(ap),
- Decl(mp),
- Decl(vp),
- Decl(v),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- auto got = gen.Result();
- auto* expect = R"(void main() {
- float4x4 a[4] = (float4x4[4])0;
- float4 v = a[3][2];
- return;
-}
-)";
- EXPECT_EQ(expect, got);
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/switch_test.cc b/src/tint/lang/hlsl/writer/ast_printer/switch_test.cc
deleted file mode 100644
index 1f18804..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/switch_test.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-
-using namespace tint::core::number_suffixes; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Switch = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Switch, Emit_Switch) {
- GlobalVar("cond", ty.i32(), core::AddressSpace::kPrivate);
- auto* s = Switch( //
- Expr("cond"), //
- Case(CaseSelector(5_i), Block(Break())), //
- DefaultCase());
- WrapInFunction(s);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(s)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( switch(cond) {
- case 5: {
- break;
- }
- default: {
- break;
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Switch, Emit_Switch_MixedDefault) {
- GlobalVar("cond", ty.i32(), core::AddressSpace::kPrivate);
- auto* s = Switch( //
- Expr("cond"), //
- Case(Vector{CaseSelector(5_i), DefaultCaseSelector()}, Block(Break())));
- WrapInFunction(s);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(s)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( switch(cond) {
- case 5:
- default: {
- break;
- }
- }
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Switch, Emit_Switch_OnlyDefaultCase_NoSideEffectsCondition) {
- // var<private> cond : i32;
- // var<private> a : i32;
- // fn test() {
- // switch(cond) {
- // default: {
- // a = 42;
- // }
- // }
- // }
- GlobalVar("cond", ty.i32(), core::AddressSpace::kPrivate);
- GlobalVar("a", ty.i32(), core::AddressSpace::kPrivate);
- auto* s = Switch( //
- Expr("cond"), //
- DefaultCase(Block(Assign(Expr("a"), Expr(42_i)))));
- WrapInFunction(s);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(s)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( do {
- a = 42;
- } while (false);
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Switch, Emit_Switch_OnlyDefaultCase_SideEffectsCondition) {
- // var<private> global : i32;
- // fn bar() -> i32 {
- // global = 84;
- // return global;
- // }
- //
- // var<private> a : i32;
- // fn test() {
- // switch(bar()) {
- // default: {
- // a = 42;
- // }
- // }
- // }
- GlobalVar("global", ty.i32(), core::AddressSpace::kPrivate);
- Func("bar", {}, ty.i32(),
- Vector{ //
- Assign("global", Expr(84_i)), //
- Return("global")});
-
- GlobalVar("a", ty.i32(), core::AddressSpace::kPrivate);
- auto* s = Switch( //
- Call("bar"), //
- DefaultCase(Block(Assign(Expr("a"), Expr(42_i)))));
- WrapInFunction(s);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(s)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"( bar();
- do {
- a = 42;
- } while (false);
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/type_test.cc b/src/tint/lang/hlsl/writer/ast_printer/type_test.cc
deleted file mode 100644
index ee40355..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/type_test.cc
+++ /dev/null
@@ -1,606 +0,0 @@
-// Copyright 2020 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 "gmock/gmock.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/sampler.h"
-#include "src/tint/lang/core/type/storage_texture.h"
-#include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/lang/wgsl/ast/call_statement.h"
-#include "src/tint/lang/wgsl/ast/stage_attribute.h"
-#include "src/tint/utils/text/string_stream.h"
-
-using ::testing::HasSubstr;
-
-using namespace tint::core::number_suffixes; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_Type = TestHelper;
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_Array) {
- auto arr = ty.array<bool, 4>();
- ast::Type ty = GlobalVar("G", arr, core::AddressSpace::kPrivate)->type;
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), core::AddressSpace::kUndefined,
- core::Access::kReadWrite, "ary"))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "bool ary[4]");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_ArrayOfArray) {
- auto arr = ty.array(ty.array<bool, 4>(), 5_u);
- ast::Type ty = GlobalVar("G", arr, core::AddressSpace::kPrivate)->type;
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), core::AddressSpace::kUndefined,
- core::Access::kReadWrite, "ary"))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "bool ary[5][4]");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_ArrayOfArrayOfArray) {
- auto arr = ty.array(ty.array(ty.array<bool, 4>(), 5_u), 6_u);
- ast::Type ty = GlobalVar("G", arr, core::AddressSpace::kPrivate)->type;
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), core::AddressSpace::kUndefined,
- core::Access::kReadWrite, "ary"))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "bool ary[6][5][4]");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_Array_WithoutName) {
- auto arr = ty.array<bool, 4>();
- ast::Type ty = GlobalVar("G", arr, core::AddressSpace::kPrivate)->type;
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), core::AddressSpace::kUndefined,
- core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "bool[4]");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_Bool) {
- auto* bool_ = create<core::type::Bool>();
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, bool_, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "bool");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_F16) {
- auto* f16 = create<core::type::F16>();
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, f16, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "float16_t");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_F32) {
- auto* f32 = create<core::type::F32>();
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, f32, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "float");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_I32) {
- auto* i32 = create<core::type::I32>();
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, i32, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "int");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_Matrix_F16) {
- auto* f16 = create<core::type::F16>();
- auto* vec3 = create<core::type::Vector>(f16, 3u);
- auto* mat2x3 = create<core::type::Matrix>(vec3, 2u);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, mat2x3, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "matrix<float16_t, 2, 3>");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_Matrix_F32) {
- auto* f32 = create<core::type::F32>();
- auto* vec3 = create<core::type::Vector>(f32, 3u);
- auto* mat2x3 = create<core::type::Matrix>(vec3, 2u);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, mat2x3, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "float2x3");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_StructDecl) {
- auto* s = Structure("S", Vector{
- Member("a", ty.i32()),
- Member("b", ty.f32()),
- });
- GlobalVar("g", ty.Of(s), core::AddressSpace::kPrivate);
-
- ASTPrinter& gen = Build();
-
- tint::TextGenerator::TextBuffer buf;
- auto* str = program->TypeOf(s)->As<core::type::Struct>();
- ASSERT_TRUE(gen.EmitStructType(&buf, str)) << gen.Diagnostics();
- EXPECT_EQ(buf.String(), R"(struct S {
- int a;
- float b;
-};
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_StructDecl_OmittedIfStorageBuffer) {
- auto* s = Structure("S", Vector{
- Member("a", ty.i32()),
- Member("b", ty.f32()),
- });
- GlobalVar("g", ty.Of(s), core::AddressSpace::kStorage, core::Access::kReadWrite, Binding(0_a),
- Group(0_a));
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), "RWByteAddressBuffer g : register(u0);\n");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_Struct) {
- auto* s = Structure("S", Vector{
- Member("a", ty.i32()),
- Member("b", ty.f32()),
- });
- GlobalVar("g", ty.Of(s), core::AddressSpace::kPrivate);
-
- ASTPrinter& gen = Build();
-
- auto* str = program->TypeOf(s)->As<core::type::Struct>();
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, str, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "S");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_Struct_NameCollision) {
- auto* s = Structure("S", Vector{
- Member("double", ty.i32()),
- Member("float", ty.f32()),
- });
- GlobalVar("g", ty.Of(s), core::AddressSpace::kPrivate);
-
- ASTPrinter& gen = SanitizeAndBuild();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(R"(struct S {
- int tint_symbol;
- float tint_symbol_1;
-};
-)"));
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_Struct_WithOffsetAttributes) {
- auto* s = Structure("S", Vector{
- Member("a", ty.i32(), Vector{MemberOffset(0_a)}),
- Member("b", ty.f32(), Vector{MemberOffset(8_a)}),
- });
- GlobalVar("g", ty.Of(s), core::AddressSpace::kPrivate);
-
- ASTPrinter& gen = Build();
-
- tint::TextGenerator::TextBuffer buf;
- auto* str = program->TypeOf(s)->As<core::type::Struct>();
- ASSERT_TRUE(gen.EmitStructType(&buf, str)) << gen.Diagnostics();
- EXPECT_EQ(buf.String(), R"(struct S {
- int a;
- float b;
-};
-)");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_U32) {
- auto* u32 = create<core::type::U32>();
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, u32, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "uint");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_Vector) {
- auto* f32 = create<core::type::F32>();
- auto* vec3 = create<core::type::Vector>(f32, 3u);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, vec3, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "float3");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitType_Void) {
- auto* void_ = create<core::type::Void>();
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, void_, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "void");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitSampler) {
- auto* sampler = create<core::type::Sampler>(core::type::SamplerKind::kSampler);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, sampler, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "SamplerState");
-}
-
-TEST_F(HlslASTPrinterTest_Type, EmitSamplerComparison) {
- auto* sampler = create<core::type::Sampler>(core::type::SamplerKind::kComparisonSampler);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(
- gen.EmitType(out, sampler, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "SamplerComparisonState");
-}
-
-struct HlslDepthTextureData {
- core::type::TextureDimension dim;
- std::string result;
-};
-inline std::ostream& operator<<(std::ostream& out, HlslDepthTextureData data) {
- StringStream str;
- str << data.dim;
- out << str.str();
- return out;
-}
-using HlslDepthTexturesTest = TestParamHelper<HlslDepthTextureData>;
-TEST_P(HlslDepthTexturesTest, Emit) {
- auto params = GetParam();
-
- auto t = ty.depth_texture(params.dim);
-
- GlobalVar("tex", t, Binding(1_a), Group(2_a));
-
- Func("main", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("v", Call("textureDimensions", "tex"))),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(params.result));
-}
-INSTANTIATE_TEST_SUITE_P(
- HlslASTPrinterTest_Type,
- HlslDepthTexturesTest,
- testing::Values(HlslDepthTextureData{core::type::TextureDimension::k2d,
- "Texture2D tex : register(t1, space2);"},
- HlslDepthTextureData{core::type::TextureDimension::k2dArray,
- "Texture2DArray tex : register(t1, space2);"},
- HlslDepthTextureData{core::type::TextureDimension::kCube,
- "TextureCube tex : register(t1, space2);"},
- HlslDepthTextureData{core::type::TextureDimension::kCubeArray,
- "TextureCubeArray tex : register(t1, space2);"}));
-
-using HlslDepthMultisampledTexturesTest = TestHelper;
-TEST_F(HlslDepthMultisampledTexturesTest, Emit) {
- auto t = ty.depth_multisampled_texture(core::type::TextureDimension::k2d);
-
- GlobalVar("tex", t, Binding(1_a), Group(2_a));
-
- Func("main", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("v", Call("textureDimensions", "tex"))),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("Texture2DMS<float4> tex : register(t1, space2);"));
-}
-
-enum class TextureDataType { F32, U32, I32 };
-struct HlslSampledTextureData {
- core::type::TextureDimension dim;
- TextureDataType datatype;
- std::string result;
-};
-inline std::ostream& operator<<(std::ostream& out, HlslSampledTextureData data) {
- StringStream str;
- str << data.dim;
- out << str.str();
- return out;
-}
-using HlslSampledTexturesTest = TestParamHelper<HlslSampledTextureData>;
-TEST_P(HlslSampledTexturesTest, Emit) {
- auto params = GetParam();
-
- ast::Type datatype;
- switch (params.datatype) {
- case TextureDataType::F32:
- datatype = ty.f32();
- break;
- case TextureDataType::U32:
- datatype = ty.u32();
- break;
- case TextureDataType::I32:
- datatype = ty.i32();
- break;
- }
- ast::Type t = ty.sampled_texture(params.dim, datatype);
-
- GlobalVar("tex", t, Binding(1_a), Group(2_a));
-
- Func("main", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("v", Call("textureDimensions", "tex"))),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(params.result));
-}
-INSTANTIATE_TEST_SUITE_P(HlslASTPrinterTest_Type,
- HlslSampledTexturesTest,
- testing::Values(
- HlslSampledTextureData{
- core::type::TextureDimension::k1d,
- TextureDataType::F32,
- "Texture1D<float4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::k2d,
- TextureDataType::F32,
- "Texture2D<float4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::k2dArray,
- TextureDataType::F32,
- "Texture2DArray<float4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::k3d,
- TextureDataType::F32,
- "Texture3D<float4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::kCube,
- TextureDataType::F32,
- "TextureCube<float4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::kCubeArray,
- TextureDataType::F32,
- "TextureCubeArray<float4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::k1d,
- TextureDataType::U32,
- "Texture1D<uint4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::k2d,
- TextureDataType::U32,
- "Texture2D<uint4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::k2dArray,
- TextureDataType::U32,
- "Texture2DArray<uint4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::k3d,
- TextureDataType::U32,
- "Texture3D<uint4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::kCube,
- TextureDataType::U32,
- "TextureCube<uint4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::kCubeArray,
- TextureDataType::U32,
- "TextureCubeArray<uint4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::k1d,
- TextureDataType::I32,
- "Texture1D<int4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::k2d,
- TextureDataType::I32,
- "Texture2D<int4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::k2dArray,
- TextureDataType::I32,
- "Texture2DArray<int4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::k3d,
- TextureDataType::I32,
- "Texture3D<int4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::kCube,
- TextureDataType::I32,
- "TextureCube<int4> tex : register(t1, space2);",
- },
- HlslSampledTextureData{
- core::type::TextureDimension::kCubeArray,
- TextureDataType::I32,
- "TextureCubeArray<int4> tex : register(t1, space2);",
- }));
-
-TEST_F(HlslASTPrinterTest_Type, EmitMultisampledTexture) {
- auto* f32 = create<core::type::F32>();
- auto* s = create<core::type::MultisampledTexture>(core::type::TextureDimension::k2d, f32);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitType(out, s, core::AddressSpace::kUndefined, core::Access::kReadWrite, ""))
- << gen.Diagnostics();
- EXPECT_EQ(out.str(), "Texture2DMS<float4>");
-}
-
-struct HlslStorageTextureData {
- core::type::TextureDimension dim;
- core::TexelFormat imgfmt;
- std::string result;
-};
-inline std::ostream& operator<<(std::ostream& out, HlslStorageTextureData data) {
- StringStream str;
- str << data.dim;
- out << str.str();
- return out;
-}
-using HlslStorageTexturesTest = TestParamHelper<HlslStorageTextureData>;
-TEST_P(HlslStorageTexturesTest, Emit) {
- auto params = GetParam();
-
- auto t = ty.storage_texture(params.dim, params.imgfmt, core::Access::kWrite);
-
- GlobalVar("tex", t,
- Vector{
- Group(2_a),
- Binding(1_a),
- });
-
- Func("main", tint::Empty, ty.void_(),
- Vector{
- Decl(Var("v", Call("textureDimensions", "tex"))),
- },
- Vector{
- Stage(ast::PipelineStage::kFragment),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(params.result));
-}
-INSTANTIATE_TEST_SUITE_P(
- HlslASTPrinterTest_Type,
- HlslStorageTexturesTest,
- testing::Values(
- HlslStorageTextureData{core::type::TextureDimension::k1d, core::TexelFormat::kRgba8Unorm,
- "RWTexture1D<float4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k2d, core::TexelFormat::kRgba16Float,
- "RWTexture2D<float4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k2dArray, core::TexelFormat::kR32Float,
- "RWTexture2DArray<float4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k3d, core::TexelFormat::kRg32Float,
- "RWTexture3D<float4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k1d, core::TexelFormat::kRgba32Float,
- "RWTexture1D<float4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k2d, core::TexelFormat::kRgba16Uint,
- "RWTexture2D<uint4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k2dArray, core::TexelFormat::kR32Uint,
- "RWTexture2DArray<uint4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k3d, core::TexelFormat::kRg32Uint,
- "RWTexture3D<uint4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k1d, core::TexelFormat::kRgba32Uint,
- "RWTexture1D<uint4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k2d, core::TexelFormat::kRgba16Sint,
- "RWTexture2D<int4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k2dArray, core::TexelFormat::kR32Sint,
- "RWTexture2DArray<int4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k3d, core::TexelFormat::kRg32Sint,
- "RWTexture3D<int4> tex : register(u1, space2);"},
- HlslStorageTextureData{core::type::TextureDimension::k1d, core::TexelFormat::kRgba32Sint,
- "RWTexture1D<int4> tex : register(u1, space2);"}));
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/unary_op_test.cc b/src/tint/lang/hlsl/writer/ast_printer/unary_op_test.cc
deleted file mode 100644
index 3e841aa..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/unary_op_test.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2020 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/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/utils/text/string_stream.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslUnaryOpTest = TestHelper;
-
-TEST_F(HlslUnaryOpTest, AddressOf) {
- GlobalVar("expr", ty.f32(), core::AddressSpace::kPrivate);
- auto* op = create<ast::UnaryOpExpression>(core::UnaryOp::kAddressOf, Expr("expr"));
- WrapInFunction(op);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "expr");
-}
-
-TEST_F(HlslUnaryOpTest, Complement) {
- GlobalVar("expr", ty.u32(), core::AddressSpace::kPrivate);
- auto* op = create<ast::UnaryOpExpression>(core::UnaryOp::kComplement, Expr("expr"));
- WrapInFunction(op);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "~(expr)");
-}
-
-TEST_F(HlslUnaryOpTest, Indirection) {
- GlobalVar("G", ty.f32(), core::AddressSpace::kPrivate);
- auto* p = Let("expr", create<ast::UnaryOpExpression>(core::UnaryOp::kAddressOf, Expr("G")));
- auto* op = create<ast::UnaryOpExpression>(core::UnaryOp::kIndirection, Expr("expr"));
- WrapInFunction(p, op);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "expr");
-}
-
-TEST_F(HlslUnaryOpTest, Not) {
- GlobalVar("expr", ty.bool_(), core::AddressSpace::kPrivate);
- auto* op = create<ast::UnaryOpExpression>(core::UnaryOp::kNot, Expr("expr"));
- WrapInFunction(op);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "!(expr)");
-}
-
-TEST_F(HlslUnaryOpTest, Negation) {
- GlobalVar("expr", ty.i32(), core::AddressSpace::kPrivate);
- auto* op = create<ast::UnaryOpExpression>(core::UnaryOp::kNegation, Expr("expr"));
- WrapInFunction(op);
-
- ASTPrinter& gen = Build();
-
- StringStream out;
- ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.Diagnostics();
- EXPECT_EQ(out.str(), "-(expr)");
-}
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/variable_decl_statement_test.cc b/src/tint/lang/hlsl/writer/ast_printer/variable_decl_statement_test.cc
deleted file mode 100644
index e546046..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/variable_decl_statement_test.cc
+++ /dev/null
@@ -1,589 +0,0 @@
-// Copyright 2020 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/wgsl/ast/variable_decl_statement.h"
-#include "gmock/gmock.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/helper_test.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-using ::testing::HasSubstr;
-
-using HlslASTPrinterTest_VariableDecl = TestHelper;
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement) {
- auto* var = Var("a", ty.f32());
- auto* stmt = Decl(var);
- WrapInFunction(stmt);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), " float a = 0.0f;\n");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Let) {
- auto* var = Let("a", ty.f32(), Call<f32>());
- auto* stmt = Decl(var);
- WrapInFunction(stmt);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), " float a = 0.0f;\n");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const) {
- auto* var = Const("a", ty.f32(), Call<f32>());
- auto* stmt = Decl(var);
- WrapInFunction(stmt);
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), ""); // Not a mistake - 'const' is inlined
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_AInt) {
- auto* C = Const("C", Expr(1_a));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- int l = 1;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_AFloat) {
- auto* C = Const("C", Expr(1._a));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float l = 1.0f;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_i32) {
- auto* C = Const("C", Expr(1_i));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- int l = 1;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_u32) {
- auto* C = Const("C", Expr(1_u));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- uint l = 1u;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_f32) {
- auto* C = Const("C", Expr(1_f));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float l = 1.0f;
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* C = Const("C", Expr(1_h));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float16_t l = float16_t(1.0h);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AInt) {
- auto* C = Const("C", Call<vec3<Infer>>(1_a, 2_a, 3_a));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- int3 l = int3(1, 2, 3);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AFloat) {
- auto* C = Const("C", Call<vec3<Infer>>(1._a, 2._a, 3._a));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float3 l = float3(1.0f, 2.0f, 3.0f);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f32) {
- auto* C = Const("C", Call<vec3<f32>>(1_f, 2_f, 3_f));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float3 l = float3(1.0f, 2.0f, 3.0f);
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* C = Const("C", Call<vec3<f16>>(1_h, 2_h, 3_h));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- vector<float16_t, 3> l = vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h));
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
- auto* C = Const("C", Call<mat2x3<Infer>>(1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f32) {
- auto* C = Const("C", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f16) {
- Enable(wgsl::Extension::kF16);
-
- auto* C = Const("C", Call<mat2x3<f16>>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- matrix<float16_t, 2, 3> l = matrix<float16_t, 2, 3>(vector<float16_t, 3>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h)), vector<float16_t, 3>(float16_t(4.0h), float16_t(5.0h), float16_t(6.0h)));
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_f32) {
- auto* C = Const("C", Call(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float l[3] = {1.0f, 2.0f, 3.0f};
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
- auto* C = Const("C", Call<array<vec2<bool>, 3>>( //
- Call<vec2<bool>>(true, false), //
- Call<vec2<bool>>(false, true), //
- Call<vec2<bool>>(true, true)));
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- bool2 l[3] = {bool2(true, false), bool2(false, true), (true).xx};
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Array) {
- auto* var = Var("a", ty.array<f32, 5>());
-
- WrapInFunction(var, Expr("a"));
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(" float a[5] = (float[5])0;\n"));
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Private) {
- GlobalVar("a", ty.f32(), core::AddressSpace::kPrivate);
-
- WrapInFunction(Expr("a"));
-
- ASTPrinter& gen = Build();
-
- gen.IncrementIndent();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr(" static float a = 0.0f;\n"));
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_F32) {
- auto* var = Var("a", ty.vec3<f32>(), Call<vec3<f32>>());
-
- auto* stmt = Decl(var);
- WrapInFunction(stmt);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(float3 a = (0.0f).xxx;
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_F16) {
- Enable(wgsl::Extension::kF16);
-
- auto* var = Var("a", ty.vec3<f16>(), Call<vec3<f16>>());
-
- auto* stmt = Decl(var);
- WrapInFunction(stmt);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(), R"(vector<float16_t, 3> a = (float16_t(0.0h)).xxx;
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_F32) {
- auto* var = Var("a", ty.mat2x3<f32>(), Call<mat2x3<f32>>());
-
- auto* stmt = Decl(var);
- WrapInFunction(stmt);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.Diagnostics();
- EXPECT_EQ(gen.Result(),
- R"(float2x3 a = float2x3((0.0f).xxx, (0.0f).xxx);
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_F16) {
- Enable(wgsl::Extension::kF16);
-
- auto* var = Var("a", ty.mat2x3<f16>(), Call<mat2x3<f16>>());
-
- auto* stmt = Decl(var);
- WrapInFunction(stmt);
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.Diagnostics();
- EXPECT_EQ(
- gen.Result(),
- R"(matrix<float16_t, 2, 3> a = matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_Mat) {
- auto* C = Const("C", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
-
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float2x3 l = float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_Struct_of_Mat) {
- Structure("S", Vector{Member("m", ty.mat2x3<f32>())});
- auto* C = Const("C", Call("S", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f)));
-
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(struct S {
- float2x3 m;
-};
-
-void f() {
- S l = {float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f))};
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_Struct_of_Struct_of_Mat) {
- Structure("S", Vector{Member("m", ty.mat2x3<f32>())});
- Structure("S2", Vector{Member("s", ty("S"))});
- auto* C = Const("C", Call("S2", Call("S", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f))));
-
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(struct S {
- float2x3 m;
-};
-struct S2 {
- S s;
-};
-
-void f() {
- S2 l = {{float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f))}};
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_Struct_of_Array_of_Mat) {
- Structure("S", Vector{Member("m", ty.array(ty.mat2x3<f32>(), 1_u))});
-
- auto* C = Const("C", Call("S", Call(ty.array(ty.mat2x3<f32>(), 1_u),
- Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f))));
-
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(struct S {
- float2x3 m[1];
-};
-
-void f() {
- S l = {{float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f))}};
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_Array_of_Mat) {
- auto* C = Const("C", Call(ty.array(ty.mat2x3<f32>(), 1_u),
- Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f)));
-
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(void f() {
- float2x3 l[1] = {float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f))};
-}
-)");
-}
-
-TEST_F(HlslASTPrinterTest_VariableDecl, Emit_VariableDeclStatement_Const_Array_of_Struct_of_Mat) {
- Structure("S", Vector{Member("m", ty.mat2x3<f32>())});
-
- auto* C = Const("C", Call(ty.array(ty("S"), 1_u),
- Call(ty("S"), Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f))));
-
- Func("f", tint::Empty, ty.void_(),
- Vector{
- Decl(C),
- Decl(Let("l", Expr(C))),
- });
-
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-
- EXPECT_EQ(gen.Result(), R"(struct S {
- float2x3 m;
-};
-
-void f() {
- S l[1] = {{float2x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f))}};
-}
-)");
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_printer/workgroup_var_test.cc b/src/tint/lang/hlsl/writer/ast_printer/workgroup_var_test.cc
deleted file mode 100644
index c8990a5..0000000
--- a/src/tint/lang/hlsl/writer/ast_printer/workgroup_var_test.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2021 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 "gmock/gmock.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/helper_test.h"
-#include "src/tint/lang/wgsl/ast/id_attribute.h"
-#include "src/tint/lang/wgsl/ast/stage_attribute.h"
-
-using ::testing::HasSubstr;
-
-using namespace tint::core::number_suffixes; // NOLINT
-
-namespace tint::hlsl::writer {
-namespace {
-
-using HlslASTPrinterTest_WorkgroupVar = TestHelper;
-
-TEST_F(HlslASTPrinterTest_WorkgroupVar, Basic) {
- GlobalVar("wg", ty.f32(), core::AddressSpace::kWorkgroup);
-
- Func("main", tint::Empty, ty.void_(), Vector{Assign("wg", 1.2_f)},
- Vector{
- Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(1_i),
- });
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("groupshared float wg;\n"));
-}
-
-TEST_F(HlslASTPrinterTest_WorkgroupVar, Aliased) {
- auto* alias = Alias("F32", ty.f32());
-
- GlobalVar("wg", ty.Of(alias), core::AddressSpace::kWorkgroup);
-
- Func("main", tint::Empty, ty.void_(), Vector{Assign("wg", 1.2_f)},
- Vector{
- Stage(ast::PipelineStage::kCompute),
- WorkgroupSize(1_i),
- });
- ASTPrinter& gen = Build();
-
- ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
- EXPECT_THAT(gen.Result(), HasSubstr("groupshared float wg;\n"));
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_raise/BUILD.bazel b/src/tint/lang/hlsl/writer/ast_raise/BUILD.bazel
deleted file mode 100644
index 4eaab70..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/BUILD.bazel
+++ /dev/null
@@ -1,173 +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.
-
-################################################################################
-# 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 = "ast_raise",
- srcs = [
- "calculate_array_length.cc",
- "decompose_memory_access.cc",
- "localize_struct_array_assignment.cc",
- "num_workgroups_from_uniform.cc",
- "pixel_local.cc",
- "truncate_interstage_variables.cc",
- ],
- hdrs = [
- "calculate_array_length.h",
- "decompose_memory_access.h",
- "localize_struct_array_assignment.h",
- "num_workgroups_from_uniform.h",
- "pixel_local.h",
- "truncate_interstage_variables.h",
- ],
- deps = [
- "//src/tint/api/common",
- "//src/tint/lang/core",
- "//src/tint/lang/core/constant",
- "//src/tint/lang/core/type",
- "//src/tint/lang/wgsl",
- "//src/tint/lang/wgsl/ast",
- "//src/tint/lang/wgsl/ast/transform",
- "//src/tint/lang/wgsl/program",
- "//src/tint/lang/wgsl/resolver",
- "//src/tint/lang/wgsl/sem",
- "//src/tint/utils",
- "//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/rtti",
- "//src/tint/utils/symbol",
- "//src/tint/utils/text",
- "//src/utils",
- ],
- copts = COPTS,
- visibility = ["//visibility:public"],
-)
-cc_library(
- name = "test",
- alwayslink = True,
- srcs = [
- "calculate_array_length_test.cc",
- "decompose_memory_access_test.cc",
- "localize_struct_array_assignment_test.cc",
- "num_workgroups_from_uniform_test.cc",
- "pixel_local_test.cc",
- "truncate_interstage_variables_test.cc",
- ],
- 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/ast/transform",
- "//src/tint/lang/wgsl/program",
- "//src/tint/lang/wgsl/sem",
- "//src/tint/lang/wgsl/writer/ir_to_program",
- "//src/tint/utils",
- "//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/rtti",
- "//src/tint/utils/symbol",
- "//src/tint/utils/text",
- "@gtest",
- "//src/utils",
- ] + select({
- ":tint_build_hlsl_writer": [
- "//src/tint/lang/hlsl/writer/ast_raise",
- ],
- "//conditions:default": [],
- }) + select({
- ":tint_build_wgsl_reader": [
- "//src/tint/lang/wgsl/reader",
- ],
- "//conditions:default": [],
- }) + select({
- ":tint_build_wgsl_reader_and_tint_build_wgsl_writer": [
- "//src/tint/lang/wgsl/ast/transform:test",
- ],
- "//conditions:default": [],
- }) + select({
- ":tint_build_wgsl_writer": [
- "//src/tint/lang/wgsl/writer",
- ],
- "//conditions:default": [],
- }),
- copts = COPTS,
- visibility = ["//visibility:public"],
-)
-
-alias(
- name = "tint_build_hlsl_writer",
- actual = "//src/tint:tint_build_hlsl_writer_true",
-)
-
-alias(
- name = "tint_build_wgsl_reader",
- actual = "//src/tint:tint_build_wgsl_reader_true",
-)
-
-alias(
- name = "tint_build_wgsl_writer",
- actual = "//src/tint:tint_build_wgsl_writer_true",
-)
-
-selects.config_setting_group(
- name = "tint_build_hlsl_writer_and_tint_build_wgsl_reader_and_tint_build_wgsl_writer",
- match_all = [
- ":tint_build_hlsl_writer",
- ":tint_build_wgsl_reader",
- ":tint_build_wgsl_writer",
- ],
-)
-selects.config_setting_group(
- name = "tint_build_wgsl_reader_and_tint_build_wgsl_writer",
- match_all = [
- ":tint_build_wgsl_reader",
- ":tint_build_wgsl_writer",
- ],
-)
-
diff --git a/src/tint/lang/hlsl/writer/ast_raise/BUILD.cfg b/src/tint/lang/hlsl/writer/ast_raise/BUILD.cfg
deleted file mode 100644
index dd6ef8b..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/BUILD.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "condition": "tint_build_hlsl_writer",
- "test": {
- "condition": "tint_build_wgsl_reader && tint_build_wgsl_writer",
- }
-}
diff --git a/src/tint/lang/hlsl/writer/ast_raise/BUILD.cmake b/src/tint/lang/hlsl/writer/ast_raise/BUILD.cmake
deleted file mode 100644
index 37d704d..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/BUILD.cmake
+++ /dev/null
@@ -1,154 +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.
-
-################################################################################
-# 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_HLSL_WRITER)
-################################################################################
-# Target: tint_lang_hlsl_writer_ast_raise
-# Kind: lib
-# Condition: TINT_BUILD_HLSL_WRITER
-################################################################################
-tint_add_target(tint_lang_hlsl_writer_ast_raise lib
- lang/hlsl/writer/ast_raise/calculate_array_length.cc
- lang/hlsl/writer/ast_raise/calculate_array_length.h
- lang/hlsl/writer/ast_raise/decompose_memory_access.cc
- lang/hlsl/writer/ast_raise/decompose_memory_access.h
- lang/hlsl/writer/ast_raise/localize_struct_array_assignment.cc
- lang/hlsl/writer/ast_raise/localize_struct_array_assignment.h
- lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc
- lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.h
- lang/hlsl/writer/ast_raise/pixel_local.cc
- lang/hlsl/writer/ast_raise/pixel_local.h
- lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
- lang/hlsl/writer/ast_raise/truncate_interstage_variables.h
-)
-
-tint_target_add_dependencies(tint_lang_hlsl_writer_ast_raise lib
- tint_api_common
- tint_lang_core
- tint_lang_core_constant
- tint_lang_core_type
- tint_lang_wgsl
- tint_lang_wgsl_ast
- tint_lang_wgsl_ast_transform
- tint_lang_wgsl_program
- tint_lang_wgsl_resolver
- tint_lang_wgsl_sem
- tint_utils
- tint_utils_containers
- tint_utils_diagnostic
- tint_utils_ice
- tint_utils_macros
- tint_utils_math
- tint_utils_memory
- tint_utils_rtti
- tint_utils_symbol
- tint_utils_text
-)
-
-tint_target_add_external_dependencies(tint_lang_hlsl_writer_ast_raise lib
- "src_utils"
-)
-
-endif(TINT_BUILD_HLSL_WRITER)
-if(TINT_BUILD_HLSL_WRITER AND TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
-################################################################################
-# Target: tint_lang_hlsl_writer_ast_raise_test
-# Kind: test
-# Condition: TINT_BUILD_HLSL_WRITER AND TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER
-################################################################################
-tint_add_target(tint_lang_hlsl_writer_ast_raise_test test
- lang/hlsl/writer/ast_raise/calculate_array_length_test.cc
- lang/hlsl/writer/ast_raise/decompose_memory_access_test.cc
- lang/hlsl/writer/ast_raise/localize_struct_array_assignment_test.cc
- lang/hlsl/writer/ast_raise/num_workgroups_from_uniform_test.cc
- lang/hlsl/writer/ast_raise/pixel_local_test.cc
- lang/hlsl/writer/ast_raise/truncate_interstage_variables_test.cc
-)
-
-tint_target_add_dependencies(tint_lang_hlsl_writer_ast_raise_test test
- 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_transform
- tint_lang_wgsl_program
- tint_lang_wgsl_sem
- tint_lang_wgsl_writer_ir_to_program
- tint_utils
- tint_utils_containers
- tint_utils_diagnostic
- tint_utils_ice
- tint_utils_macros
- tint_utils_math
- tint_utils_memory
- tint_utils_rtti
- tint_utils_symbol
- tint_utils_text
-)
-
-tint_target_add_external_dependencies(tint_lang_hlsl_writer_ast_raise_test test
- "gtest"
- "src_utils"
-)
-
-if(TINT_BUILD_HLSL_WRITER)
- tint_target_add_dependencies(tint_lang_hlsl_writer_ast_raise_test test
- tint_lang_hlsl_writer_ast_raise
- )
-endif(TINT_BUILD_HLSL_WRITER)
-
-if(TINT_BUILD_WGSL_READER)
- tint_target_add_dependencies(tint_lang_hlsl_writer_ast_raise_test test
- tint_lang_wgsl_reader
- )
-endif(TINT_BUILD_WGSL_READER)
-
-if(TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
- tint_target_add_dependencies(tint_lang_hlsl_writer_ast_raise_test test
- tint_lang_wgsl_ast_transform_test
- )
-endif(TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
-
-if(TINT_BUILD_WGSL_WRITER)
- tint_target_add_dependencies(tint_lang_hlsl_writer_ast_raise_test test
- tint_lang_wgsl_writer
- )
-endif(TINT_BUILD_WGSL_WRITER)
-
-endif(TINT_BUILD_HLSL_WRITER AND TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
\ No newline at end of file
diff --git a/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn b/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn
deleted file mode 100644
index f59e28b..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn
+++ /dev/null
@@ -1,141 +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.
-
-################################################################################
-# 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/dawn_overrides_with_defaults.gni")
-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_hlsl_writer) {
- libtint_source_set("ast_raise") {
- sources = [
- "calculate_array_length.cc",
- "calculate_array_length.h",
- "decompose_memory_access.cc",
- "decompose_memory_access.h",
- "localize_struct_array_assignment.cc",
- "localize_struct_array_assignment.h",
- "num_workgroups_from_uniform.cc",
- "num_workgroups_from_uniform.h",
- "pixel_local.cc",
- "pixel_local.h",
- "truncate_interstage_variables.cc",
- "truncate_interstage_variables.h",
- ]
- deps = [
- "${dawn_root}/src/utils:utils",
- "${tint_src_dir}/api/common",
- "${tint_src_dir}/lang/core",
- "${tint_src_dir}/lang/core/constant",
- "${tint_src_dir}/lang/core/type",
- "${tint_src_dir}/lang/wgsl",
- "${tint_src_dir}/lang/wgsl/ast",
- "${tint_src_dir}/lang/wgsl/ast/transform",
- "${tint_src_dir}/lang/wgsl/program",
- "${tint_src_dir}/lang/wgsl/resolver",
- "${tint_src_dir}/lang/wgsl/sem",
- "${tint_src_dir}/utils",
- "${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/rtti",
- "${tint_src_dir}/utils/symbol",
- "${tint_src_dir}/utils/text",
- ]
- }
-}
-if (tint_build_unittests) {
- if (tint_build_hlsl_writer && tint_build_wgsl_reader &&
- tint_build_wgsl_writer) {
- tint_unittests_source_set("unittests") {
- sources = [
- "calculate_array_length_test.cc",
- "decompose_memory_access_test.cc",
- "localize_struct_array_assignment_test.cc",
- "num_workgroups_from_uniform_test.cc",
- "pixel_local_test.cc",
- "truncate_interstage_variables_test.cc",
- ]
- deps = [
- "${dawn_root}/src/utils:utils",
- "${tint_src_dir}:gmock_and_gtest",
- "${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/transform",
- "${tint_src_dir}/lang/wgsl/program",
- "${tint_src_dir}/lang/wgsl/sem",
- "${tint_src_dir}/lang/wgsl/writer/ir_to_program",
- "${tint_src_dir}/utils",
- "${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/rtti",
- "${tint_src_dir}/utils/symbol",
- "${tint_src_dir}/utils/text",
- ]
-
- if (tint_build_hlsl_writer) {
- deps += [ "${tint_src_dir}/lang/hlsl/writer/ast_raise" ]
- }
-
- if (tint_build_wgsl_reader) {
- deps += [ "${tint_src_dir}/lang/wgsl/reader" ]
- }
-
- if (tint_build_wgsl_reader && tint_build_wgsl_writer) {
- deps += [ "${tint_src_dir}/lang/wgsl/ast/transform:unittests" ]
- }
-
- if (tint_build_wgsl_writer) {
- deps += [ "${tint_src_dir}/lang/wgsl/writer" ]
- }
- }
- }
-}
diff --git a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc b/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc
deleted file mode 100644
index 4f37291..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc
+++ /dev/null
@@ -1,262 +0,0 @@
-// Copyright 2021 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/hlsl/writer/ast_raise/calculate_array_length.h"
-
-#include <unordered_map>
-#include <utility>
-
-#include "src/tint/lang/core/type/reference.h"
-#include "src/tint/lang/wgsl/ast/call_statement.h"
-#include "src/tint/lang/wgsl/ast/disable_validation_attribute.h"
-#include "src/tint/lang/wgsl/ast/transform/simplify_pointers.h"
-#include "src/tint/lang/wgsl/program/clone_context.h"
-#include "src/tint/lang/wgsl/program/program_builder.h"
-#include "src/tint/lang/wgsl/resolver/resolve.h"
-#include "src/tint/lang/wgsl/sem/block_statement.h"
-#include "src/tint/lang/wgsl/sem/call.h"
-#include "src/tint/lang/wgsl/sem/function.h"
-#include "src/tint/lang/wgsl/sem/statement.h"
-#include "src/tint/lang/wgsl/sem/struct.h"
-#include "src/tint/lang/wgsl/sem/variable.h"
-#include "src/tint/utils/containers/map.h"
-#include "src/tint/utils/math/hash.h"
-#include "src/tint/utils/rtti/switch.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::CalculateArrayLength);
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::CalculateArrayLength::BufferSizeIntrinsic);
-
-namespace tint::hlsl::writer {
-namespace {
-
-using namespace tint::core::fluent_types; // NOLINT
-using namespace tint::core::number_suffixes; // NOLINT
-
-bool ShouldRun(const Program& program) {
- for (auto* fn : program.AST().Functions()) {
- if (auto* sem_fn = program.Sem().Get(fn)) {
- for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
- if (builtin->Fn() == wgsl::BuiltinFn::kArrayLength) {
- return true;
- }
- }
- }
- }
- return false;
-}
-
-/// ArrayUsage describes a runtime array usage.
-/// It is used as a key by the array_length_by_usage map.
-struct ArrayUsage {
- ast::BlockStatement const* const block;
- sem::Variable const* const buffer;
- bool operator==(const ArrayUsage& rhs) const {
- return block == rhs.block && buffer == rhs.buffer;
- }
- struct Hasher {
- inline std::size_t operator()(const ArrayUsage& u) const { return Hash(u.block, u.buffer); }
- };
-};
-
-} // namespace
-
-CalculateArrayLength::BufferSizeIntrinsic::BufferSizeIntrinsic(GenerationID pid, ast::NodeID nid)
- : Base(pid, nid, tint::Empty) {}
-CalculateArrayLength::BufferSizeIntrinsic::~BufferSizeIntrinsic() = default;
-std::string CalculateArrayLength::BufferSizeIntrinsic::InternalName() const {
- return "intrinsic_buffer_size";
-}
-
-const CalculateArrayLength::BufferSizeIntrinsic* CalculateArrayLength::BufferSizeIntrinsic::Clone(
- ast::CloneContext& ctx) const {
- return ctx.dst->ASTNodes().Create<CalculateArrayLength::BufferSizeIntrinsic>(
- ctx.dst->ID(), ctx.dst->AllocateNodeID());
-}
-
-CalculateArrayLength::CalculateArrayLength() = default;
-CalculateArrayLength::~CalculateArrayLength() = default;
-
-ast::transform::Transform::ApplyResult CalculateArrayLength::Apply(const Program& src,
- const ast::transform::DataMap&,
- ast::transform::DataMap&) const {
- if (!ShouldRun(src)) {
- return SkipTransform;
- }
-
- ProgramBuilder b;
- program::CloneContext ctx{&b, &src, /* auto_clone_symbols */ true};
- auto& sem = src.Sem();
-
- // get_buffer_size_intrinsic() emits the function decorated with
- // BufferSizeIntrinsic that is transformed by the HLSL writer into a call to
- // [RW]ByteAddressBuffer.GetDimensions().
- std::unordered_map<const core::type::Reference*, Symbol> buffer_size_intrinsics;
- auto get_buffer_size_intrinsic = [&](const core::type::Reference* buffer_type) {
- return tint::GetOrAdd(buffer_size_intrinsics, buffer_type, [&] {
- auto name = b.Sym();
- auto type = CreateASTTypeFor(ctx, buffer_type);
- auto* disable_validation = b.Disable(ast::DisabledValidation::kFunctionParameter);
- b.Func(name,
- Vector{
- b.Param("buffer",
- b.ty.ptr(buffer_type->AddressSpace(), type, buffer_type->Access()),
- Vector{disable_validation}),
- b.Param("result", b.ty.ptr<function, u32>()),
- },
- b.ty.void_(), nullptr,
- Vector{
- b.ASTNodes().Create<BufferSizeIntrinsic>(b.ID(), b.AllocateNodeID()),
- });
-
- return name;
- });
- };
-
- std::unordered_map<ArrayUsage, Symbol, ArrayUsage::Hasher> array_length_by_usage;
-
- // Find all the arrayLength() calls...
- for (auto* node : src.ASTNodes().Objects()) {
- if (auto* call_expr = node->As<ast::CallExpression>()) {
- auto* call = sem.Get(call_expr)->UnwrapMaterialize()->As<sem::Call>();
- if (auto* builtin = call->Target()->As<sem::BuiltinFn>()) {
- if (builtin->Fn() == wgsl::BuiltinFn::kArrayLength) {
- // We're dealing with an arrayLength() call
-
- if (auto* call_stmt = call->Stmt()->Declaration()->As<ast::CallStatement>()) {
- if (call_stmt->expr == call_expr) {
- // arrayLength() is used as a statement.
- // The argument expression must be side-effect free, so just drop the
- // statement.
- RemoveStatement(ctx, call_stmt);
- continue;
- }
- }
-
- // A runtime-sized array can only appear as the store type of a variable, or the
- // last element of a structure (which cannot itself be nested). Given that we
- // require SimplifyPointers, we can assume that the arrayLength() call has one
- // of two forms:
- // arrayLength(&struct_var.array_member)
- // arrayLength(&array_var)
- auto* arg = call_expr->args[0];
- auto* address_of = arg->As<ast::UnaryOpExpression>();
- if (DAWN_UNLIKELY(!address_of || address_of->op != core::UnaryOp::kAddressOf)) {
- TINT_ICE()
- << "arrayLength() expected address-of, got " << arg->TypeInfo().name;
- }
- auto* storage_buffer_expr = address_of->expr;
- if (auto* accessor = storage_buffer_expr->As<ast::MemberAccessorExpression>()) {
- storage_buffer_expr = accessor->object;
- }
- auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr);
- if (DAWN_UNLIKELY(!storage_buffer_sem)) {
- TINT_ICE() << "expected form of arrayLength argument to be &array_var or "
- "&struct_var.array_member";
- }
- if (DAWN_UNLIKELY(storage_buffer_sem->Type()->Is<core::type::Pointer>())) {
- TINT_ICE()
- << "storage buffer variable should not be a pointer. These should have "
- "been removed by the SimplifyPointers transform";
- }
- auto* storage_buffer_var = storage_buffer_sem->Variable();
- auto* storage_buffer_type =
- storage_buffer_sem->Type()->As<core::type::Reference>();
-
- // Generate BufferSizeIntrinsic for this storage type if we haven't already
- auto buffer_size = get_buffer_size_intrinsic(storage_buffer_type);
-
- // Find the current statement block
- auto* block = call->Stmt()->Block()->Declaration();
-
- auto array_length =
- tint::GetOrAdd(array_length_by_usage, {block, storage_buffer_var}, [&] {
- // First time this array length is used for this block.
- // Let's calculate it.
-
- // Construct the variable that'll hold the result of
- // RWByteAddressBuffer.GetDimensions()
- auto* buffer_size_result =
- b.Decl(b.Var(b.Sym(), b.ty.u32(), b.Expr(0_u)));
-
- // Call storage_buffer.GetDimensions(&buffer_size_result)
- auto* call_get_dims = b.CallStmt(b.Call(
- // BufferSizeIntrinsic(X, ARGS...) is
- // translated to:
- // X.GetDimensions(ARGS..) by the writer
- buffer_size, b.AddressOf(ctx.Clone(storage_buffer_expr)),
- b.AddressOf(b.Expr(buffer_size_result->variable->name->symbol))));
-
- // Calculate actual array length
- // total_storage_buffer_size - array_offset
- // array_length = ----------------------------------------
- // array_stride
- auto name = b.Sym();
- const ast::Expression* total_size =
- b.Expr(buffer_size_result->variable);
-
- const core::type::Array* array_type = Switch(
- storage_buffer_type->StoreType(),
- [&](const core::type::Struct* str) {
- // The variable is a struct, so subtract the byte offset of
- // the array member.
- auto* array_member_sem = str->Members().Back();
- total_size = b.Sub(total_size, u32(array_member_sem->Offset()));
- return array_member_sem->Type()->As<core::type::Array>();
- },
- [&](const core::type::Array* arr) { return arr; });
-
- if (DAWN_UNLIKELY(!array_type)) {
- TINT_ICE() << "expected form of arrayLength argument to be "
- "&array_var or &struct_var.array_member";
- }
-
- uint32_t array_stride = array_type->Size();
- auto* array_length_var = b.Decl(
- b.Let(name, b.ty.u32(), b.Div(total_size, u32(array_stride))));
-
- // Insert the array length calculations at the top of the block
- ctx.InsertBefore(block->statements, block->statements[0],
- buffer_size_result);
- ctx.InsertBefore(block->statements, block->statements[0],
- call_get_dims);
- ctx.InsertBefore(block->statements, block->statements[0],
- array_length_var);
- return name;
- });
-
- // Replace the call to arrayLength() with the array length variable
- ctx.Replace(call_expr, b.Expr(array_length));
- }
- }
- }
- }
-
- ctx.Clone();
- return resolver::Resolve(b);
-}
-
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.h b/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.h
deleted file mode 100644
index fc822f4..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2021 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_LANG_HLSL_WRITER_AST_RAISE_CALCULATE_ARRAY_LENGTH_H_
-#define SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_CALCULATE_ARRAY_LENGTH_H_
-
-#include <string>
-
-#include "src/tint/lang/wgsl/ast/internal_attribute.h"
-#include "src/tint/lang/wgsl/ast/transform/transform.h"
-
-namespace tint::hlsl::writer {
-
-/// CalculateArrayLength is a transform used to replace calls to arrayLength()
-/// with a value calculated from the size of the storage buffer.
-///
-/// @note Depends on the following transforms to have been run first:
-/// * SimplifyPointers
-class CalculateArrayLength final
- : public Castable<CalculateArrayLength, ast::transform::Transform> {
- public:
- /// BufferSizeIntrinsic is an InternalAttribute that's applied to intrinsic
- /// functions used to obtain the runtime size of a storage buffer.
- class BufferSizeIntrinsic final : public Castable<BufferSizeIntrinsic, ast::InternalAttribute> {
- public:
- /// Constructor
- /// @param generation_id the identifier of the program that owns this node
- /// @param nid the unique node identifier
- BufferSizeIntrinsic(GenerationID generation_id, ast::NodeID nid);
- /// Destructor
- ~BufferSizeIntrinsic() override;
-
- /// @return "buffer_size"
- std::string InternalName() const override;
-
- /// Performs a deep clone of this object using the program::CloneContext `ctx`.
- /// @param ctx the clone context
- /// @return the newly cloned object
- const BufferSizeIntrinsic* Clone(ast::CloneContext& ctx) const override;
- };
-
- /// Constructor
- CalculateArrayLength();
- /// Destructor
- ~CalculateArrayLength() override;
-
- /// @copydoc ast::transform::Transform::Apply
- ApplyResult Apply(const Program& program,
- const ast::transform::DataMap& inputs,
- ast::transform::DataMap& outputs) const override;
-};
-
-} // namespace tint::hlsl::writer
-
-#endif // SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_CALCULATE_ARRAY_LENGTH_H_
diff --git a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length_test.cc b/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length_test.cc
deleted file mode 100644
index 60e769b..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length_test.cc
+++ /dev/null
@@ -1,607 +0,0 @@
-// Copyright 2021 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/hlsl/writer/ast_raise/calculate_array_length.h"
-
-#include "src/tint/lang/wgsl/ast/transform/helper_test.h"
-#include "src/tint/lang/wgsl/ast/transform/simplify_pointers.h"
-#include "src/tint/lang/wgsl/ast/transform/unshadow.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using CalculateArrayLengthTest = ast::transform::TransformTest;
-using Unshadow = ast::transform::Unshadow;
-using SimplifyPointers = ast::transform::SimplifyPointers;
-
-TEST_F(CalculateArrayLengthTest, ShouldRunEmptyModule) {
- auto* src = R"()";
-
- EXPECT_FALSE(ShouldRun<CalculateArrayLength>(src));
-}
-
-TEST_F(CalculateArrayLengthTest, ShouldRunNoArrayLength) {
- auto* src = R"(
-struct SB {
- x : i32,
- arr : array<i32>,
-};
-
-@group(0) @binding(0) var<storage, read> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
-}
-)";
-
- EXPECT_FALSE(ShouldRun<CalculateArrayLength>(src));
-}
-
-TEST_F(CalculateArrayLengthTest, ShouldRunWithArrayLength) {
- auto* src = R"(
-struct SB {
- x : i32,
- arr : array<i32>,
-};
-
-@group(0) @binding(0) var<storage, read> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var len : u32 = arrayLength(&sb.arr);
-}
-)";
-
- EXPECT_TRUE(ShouldRun<CalculateArrayLength>(src));
-}
-
-TEST_F(CalculateArrayLengthTest, BasicArray) {
- auto* src = R"(
-@group(0) @binding(0) var<storage, read> sb : array<i32>;
-
-@compute @workgroup_size(1)
-fn main() {
- var len : u32 = arrayLength(&sb);
-}
-)";
-
- auto* expect = R"(
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<i32>, read>, result : ptr<function, u32>)
-
-@group(0) @binding(0) var<storage, read> sb : array<i32>;
-
-@compute @workgroup_size(1)
-fn main() {
- var tint_symbol_1 : u32 = 0u;
- tint_symbol(&(sb), &(tint_symbol_1));
- let tint_symbol_2 : u32 = (tint_symbol_1 / 4u);
- var len : u32 = tint_symbol_2;
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(CalculateArrayLengthTest, BasicInStruct) {
- auto* src = R"(
-struct SB {
- x : i32,
- arr : array<i32>,
-};
-
-@group(0) @binding(0) var<storage, read> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var len : u32 = arrayLength(&sb.arr);
-}
-)";
-
- auto* expect = R"(
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read>, result : ptr<function, u32>)
-
-struct SB {
- x : i32,
- arr : array<i32>,
-}
-
-@group(0) @binding(0) var<storage, read> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var tint_symbol_1 : u32 = 0u;
- tint_symbol(&(sb), &(tint_symbol_1));
- let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
- var len : u32 = tint_symbol_2;
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(CalculateArrayLengthTest, BasicInStruct_ViaPointerDot) {
- auto* src = R"(
-struct SB {
- x : i32,
- arr : array<i32>,
-};
-
-@group(0) @binding(0) var<storage, read> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- let p = &sb;
- var len : u32 = arrayLength(&p.arr);
-}
-)";
-
- auto* expect = R"(
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read>, result : ptr<function, u32>)
-
-struct SB {
- x : i32,
- arr : array<i32>,
-}
-
-@group(0) @binding(0) var<storage, read> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var tint_symbol_1 : u32 = 0u;
- tint_symbol(&(sb), &(tint_symbol_1));
- let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
- var len : u32 = tint_symbol_2;
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(CalculateArrayLengthTest, ArrayOfStruct) {
- auto* src = R"(
-struct S {
- f : f32,
-}
-
-@group(0) @binding(0) var<storage, read> arr : array<S>;
-
-@compute @workgroup_size(1)
-fn main() {
- let len = arrayLength(&arr);
-}
-)";
- auto* expect = R"(
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<S>, read>, result : ptr<function, u32>)
-
-struct S {
- f : f32,
-}
-
-@group(0) @binding(0) var<storage, read> arr : array<S>;
-
-@compute @workgroup_size(1)
-fn main() {
- var tint_symbol_1 : u32 = 0u;
- tint_symbol(&(arr), &(tint_symbol_1));
- let tint_symbol_2 : u32 = (tint_symbol_1 / 4u);
- let len = tint_symbol_2;
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(CalculateArrayLengthTest, ArrayOfArrayOfStruct) {
- auto* src = R"(
-struct S {
- f : f32,
-}
-
-@group(0) @binding(0) var<storage, read> arr : array<array<S, 4>>;
-
-@compute @workgroup_size(1)
-fn main() {
- let len = arrayLength(&arr);
-}
-)";
- auto* expect = R"(
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<array<S, 4u>>, read>, result : ptr<function, u32>)
-
-struct S {
- f : f32,
-}
-
-@group(0) @binding(0) var<storage, read> arr : array<array<S, 4>>;
-
-@compute @workgroup_size(1)
-fn main() {
- var tint_symbol_1 : u32 = 0u;
- tint_symbol(&(arr), &(tint_symbol_1));
- let tint_symbol_2 : u32 = (tint_symbol_1 / 16u);
- let len = tint_symbol_2;
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(CalculateArrayLengthTest, InSameBlock) {
- auto* src = R"(
-@group(0) @binding(0) var<storage, read> sb : array<i32>;;
-
-@compute @workgroup_size(1)
-fn main() {
- var a : u32 = arrayLength(&sb);
- var b : u32 = arrayLength(&sb);
- var c : u32 = arrayLength(&sb);
-}
-)";
-
- auto* expect = R"(
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<i32>, read>, result : ptr<function, u32>)
-
-@group(0) @binding(0) var<storage, read> sb : array<i32>;
-
-@compute @workgroup_size(1)
-fn main() {
- var tint_symbol_1 : u32 = 0u;
- tint_symbol(&(sb), &(tint_symbol_1));
- let tint_symbol_2 : u32 = (tint_symbol_1 / 4u);
- var a : u32 = tint_symbol_2;
- var b : u32 = tint_symbol_2;
- var c : u32 = tint_symbol_2;
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(CalculateArrayLengthTest, InSameBlock_Struct) {
- auto* src = R"(
-struct SB {
- x : i32,
- arr : array<i32>,
-};
-
-@group(0) @binding(0) var<storage, read> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var a : u32 = arrayLength(&sb.arr);
- var b : u32 = arrayLength(&sb.arr);
- var c : u32 = arrayLength(&sb.arr);
-}
-)";
-
- auto* expect = R"(
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read>, result : ptr<function, u32>)
-
-struct SB {
- x : i32,
- arr : array<i32>,
-}
-
-@group(0) @binding(0) var<storage, read> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var tint_symbol_1 : u32 = 0u;
- tint_symbol(&(sb), &(tint_symbol_1));
- let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
- var a : u32 = tint_symbol_2;
- var b : u32 = tint_symbol_2;
- var c : u32 = tint_symbol_2;
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(CalculateArrayLengthTest, Nested) {
- auto* src = R"(
-struct SB {
- x : i32,
- arr : array<i32>,
-};
-
-@group(0) @binding(0) var<storage, read> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- if (true) {
- var len : u32 = arrayLength(&sb.arr);
- } else {
- if (true) {
- var len : u32 = arrayLength(&sb.arr);
- }
- }
-}
-)";
-
- auto* expect = R"(
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read>, result : ptr<function, u32>)
-
-struct SB {
- x : i32,
- arr : array<i32>,
-}
-
-@group(0) @binding(0) var<storage, read> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- if (true) {
- var tint_symbol_1 : u32 = 0u;
- tint_symbol(&(sb), &(tint_symbol_1));
- let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
- var len : u32 = tint_symbol_2;
- } else {
- if (true) {
- var tint_symbol_3 : u32 = 0u;
- tint_symbol(&(sb), &(tint_symbol_3));
- let tint_symbol_4 : u32 = ((tint_symbol_3 - 4u) / 4u);
- var len : u32 = tint_symbol_4;
- }
- }
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(CalculateArrayLengthTest, MultipleStorageBuffers) {
- auto* src = R"(
-struct SB1 {
- x : i32,
- arr1 : array<i32>,
-};
-
-struct SB2 {
- x : i32,
- arr2 : array<vec4<f32>>,
-};
-
-@group(0) @binding(0) var<storage, read> sb1 : SB1;
-
-@group(0) @binding(1) var<storage, read> sb2 : SB2;
-
-@group(0) @binding(2) var<storage, read> sb3 : array<i32>;
-
-@compute @workgroup_size(1)
-fn main() {
- var len1 : u32 = arrayLength(&(sb1.arr1));
- var len2 : u32 = arrayLength(&(sb2.arr2));
- var len3 : u32 = arrayLength(&sb3);
- var x : u32 = (len1 + len2 + len3);
-}
-)";
-
- auto* expect = R"(
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB1, read>, result : ptr<function, u32>)
-
-@internal(intrinsic_buffer_size)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB2, read>, result : ptr<function, u32>)
-
-@internal(intrinsic_buffer_size)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<i32>, read>, result : ptr<function, u32>)
-
-struct SB1 {
- x : i32,
- arr1 : array<i32>,
-}
-
-struct SB2 {
- x : i32,
- arr2 : array<vec4<f32>>,
-}
-
-@group(0) @binding(0) var<storage, read> sb1 : SB1;
-
-@group(0) @binding(1) var<storage, read> sb2 : SB2;
-
-@group(0) @binding(2) var<storage, read> sb3 : array<i32>;
-
-@compute @workgroup_size(1)
-fn main() {
- var tint_symbol_1 : u32 = 0u;
- tint_symbol(&(sb1), &(tint_symbol_1));
- let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
- var tint_symbol_4 : u32 = 0u;
- tint_symbol_3(&(sb2), &(tint_symbol_4));
- let tint_symbol_5 : u32 = ((tint_symbol_4 - 16u) / 16u);
- var tint_symbol_7 : u32 = 0u;
- tint_symbol_6(&(sb3), &(tint_symbol_7));
- let tint_symbol_8 : u32 = (tint_symbol_7 / 4u);
- var len1 : u32 = tint_symbol_2;
- var len2 : u32 = tint_symbol_5;
- var len3 : u32 = tint_symbol_8;
- var x : u32 = ((len1 + len2) + len3);
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(CalculateArrayLengthTest, Shadowing) {
- auto* src = R"(
-struct SB {
- x : i32,
- arr : array<i32>,
-};
-
-@group(0) @binding(0) var<storage, read> a : SB;
-@group(0) @binding(1) var<storage, read> b : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- let x = &a;
- var a : u32 = arrayLength(&a.arr);
- {
- var b : u32 = arrayLength(&((*x).arr));
- }
-}
-)";
-
- auto* expect =
- R"(
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB, read>, result : ptr<function, u32>)
-
-struct SB {
- x : i32,
- arr : array<i32>,
-}
-
-@group(0) @binding(0) var<storage, read> a : SB;
-
-@group(0) @binding(1) var<storage, read> b : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var tint_symbol_1 : u32 = 0u;
- tint_symbol(&(a), &(tint_symbol_1));
- let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
- var a_1 : u32 = tint_symbol_2;
- {
- var tint_symbol_3 : u32 = 0u;
- tint_symbol(&(a), &(tint_symbol_3));
- let tint_symbol_4 : u32 = ((tint_symbol_3 - 4u) / 4u);
- var b_1 : u32 = tint_symbol_4;
- }
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(CalculateArrayLengthTest, OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main() {
- var len1 : u32 = arrayLength(&(sb1.arr1));
- var len2 : u32 = arrayLength(&(sb2.arr2));
- var len3 : u32 = arrayLength(&sb3);
- var x : u32 = (len1 + len2 + len3);
-}
-
-@group(0) @binding(0) var<storage, read> sb1 : SB1;
-
-struct SB1 {
- x : i32,
- arr1 : array<i32>,
-};
-
-@group(0) @binding(1) var<storage, read> sb2 : SB2;
-
-struct SB2 {
- x : i32,
- arr2 : array<vec4<f32>>,
-};
-
-@group(0) @binding(2) var<storage, read> sb3 : array<i32>;
-)";
-
- auto* expect = R"(
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB1, read>, result : ptr<function, u32>)
-
-@internal(intrinsic_buffer_size)
-fn tint_symbol_3(@internal(disable_validation__function_parameter) buffer : ptr<storage, SB2, read>, result : ptr<function, u32>)
-
-@internal(intrinsic_buffer_size)
-fn tint_symbol_6(@internal(disable_validation__function_parameter) buffer : ptr<storage, array<i32>, read>, result : ptr<function, u32>)
-
-@compute @workgroup_size(1)
-fn main() {
- var tint_symbol_1 : u32 = 0u;
- tint_symbol(&(sb1), &(tint_symbol_1));
- let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
- var tint_symbol_4 : u32 = 0u;
- tint_symbol_3(&(sb2), &(tint_symbol_4));
- let tint_symbol_5 : u32 = ((tint_symbol_4 - 16u) / 16u);
- var tint_symbol_7 : u32 = 0u;
- tint_symbol_6(&(sb3), &(tint_symbol_7));
- let tint_symbol_8 : u32 = (tint_symbol_7 / 4u);
- var len1 : u32 = tint_symbol_2;
- var len2 : u32 = tint_symbol_5;
- var len3 : u32 = tint_symbol_8;
- var x : u32 = ((len1 + len2) + len3);
-}
-
-@group(0) @binding(0) var<storage, read> sb1 : SB1;
-
-struct SB1 {
- x : i32,
- arr1 : array<i32>,
-}
-
-@group(0) @binding(1) var<storage, read> sb2 : SB2;
-
-struct SB2 {
- x : i32,
- arr2 : array<vec4<f32>>,
-}
-
-@group(0) @binding(2) var<storage, read> sb3 : array<i32>;
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc b/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc
deleted file mode 100644
index 7059698..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc
+++ /dev/null
@@ -1,1002 +0,0 @@
-// Copyright 2021 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/hlsl/writer/ast_raise/decompose_memory_access.h"
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include "src/tint/lang/core/fluent_types.h"
-#include "src/tint/lang/core/type/array.h"
-#include "src/tint/lang/core/type/atomic.h"
-#include "src/tint/lang/core/type/reference.h"
-#include "src/tint/lang/core/unary_op.h"
-#include "src/tint/lang/wgsl/ast/assignment_statement.h"
-#include "src/tint/lang/wgsl/ast/call_statement.h"
-#include "src/tint/lang/wgsl/ast/disable_validation_attribute.h"
-#include "src/tint/lang/wgsl/program/clone_context.h"
-#include "src/tint/lang/wgsl/program/program_builder.h"
-#include "src/tint/lang/wgsl/resolver/resolve.h"
-#include "src/tint/lang/wgsl/sem/call.h"
-#include "src/tint/lang/wgsl/sem/member_accessor_expression.h"
-#include "src/tint/lang/wgsl/sem/statement.h"
-#include "src/tint/lang/wgsl/sem/struct.h"
-#include "src/tint/lang/wgsl/sem/variable.h"
-#include "src/tint/utils/containers/map.h"
-#include "src/tint/utils/math/hash.h"
-#include "src/tint/utils/memory/block_allocator.h"
-#include "src/tint/utils/rtti/switch.h"
-#include "src/tint/utils/text/string_stream.h"
-
-using namespace tint::core::number_suffixes; // NOLINT
-using namespace tint::core::fluent_types; // NOLINT
-
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::DecomposeMemoryAccess);
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::DecomposeMemoryAccess::Intrinsic);
-
-namespace tint::hlsl::writer {
-
-namespace {
-
-bool ShouldRun(const Program& program) {
- for (auto* decl : program.AST().GlobalDeclarations()) {
- if (auto* var = program.Sem().Get<sem::Variable>(decl)) {
- if (var->AddressSpace() == core::AddressSpace::kStorage ||
- var->AddressSpace() == core::AddressSpace::kUniform) {
- return true;
- }
- }
- }
- return false;
-}
-
-/// Offset is a simple Expression builder interface, used to build byte
-/// offsets for storage and uniform buffer accesses.
-struct Offset : Castable<Offset> {
- /// @returns builds and returns the Expression in `ctx.dst`
- virtual const ast::Expression* Build(program::CloneContext& ctx) const = 0;
-};
-
-/// OffsetExpr is an implementation of Offset that clones and casts the given
-/// expression to `u32`.
-struct OffsetExpr : Offset {
- const ast::Expression* const expr = nullptr;
-
- explicit OffsetExpr(const ast::Expression* e) : expr(e) {}
-
- const ast::Expression* Build(program::CloneContext& ctx) const override {
- auto* type = ctx.src->Sem().GetVal(expr)->Type()->UnwrapRef();
- auto* res = ctx.Clone(expr);
- if (!type->Is<core::type::U32>()) {
- res = ctx.dst->Call<u32>(res);
- }
- return res;
- }
-};
-
-/// OffsetLiteral is an implementation of Offset that constructs a u32 literal
-/// value.
-struct OffsetLiteral final : Castable<OffsetLiteral, Offset> {
- uint32_t const literal = 0;
-
- explicit OffsetLiteral(uint32_t lit) : literal(lit) {}
-
- const ast::Expression* Build(program::CloneContext& ctx) const override {
- return ctx.dst->Expr(u32(literal));
- }
-};
-
-/// OffsetBinOp is an implementation of Offset that constructs a binary-op of
-/// two Offsets.
-struct OffsetBinOp : Offset {
- core::BinaryOp op;
- Offset const* lhs = nullptr;
- Offset const* rhs = nullptr;
-
- const ast::Expression* Build(program::CloneContext& ctx) const override {
- return ctx.dst->create<ast::BinaryExpression>(op, lhs->Build(ctx), rhs->Build(ctx));
- }
-};
-
-/// LoadStoreKey is the unordered map key to a load or store intrinsic.
-struct LoadStoreKey {
- core::type::Type const* el_ty = nullptr; // element type
- Symbol const buffer; // buffer name
- bool operator==(const LoadStoreKey& rhs) const {
- return el_ty == rhs.el_ty && buffer == rhs.buffer;
- }
- struct Hasher {
- inline std::size_t operator()(const LoadStoreKey& u) const {
- return Hash(u.el_ty, u.buffer);
- }
- };
-};
-
-/// AtomicKey is the unordered map key to an atomic intrinsic.
-struct AtomicKey {
- core::type::Type const* el_ty = nullptr; // element type
- wgsl::BuiltinFn const op; // atomic op
- Symbol const buffer; // buffer name
- bool operator==(const AtomicKey& rhs) const {
- return el_ty == rhs.el_ty && op == rhs.op && buffer == rhs.buffer;
- }
- struct Hasher {
- inline std::size_t operator()(const AtomicKey& u) const {
- return Hash(u.el_ty, u.op, u.buffer);
- }
- };
-};
-
-bool IntrinsicDataTypeFor(const core::type::Type* ty,
- DecomposeMemoryAccess::Intrinsic::DataType& out) {
- if (ty->Is<core::type::I32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kI32;
- return true;
- }
- if (ty->Is<core::type::U32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kU32;
- return true;
- }
- if (ty->Is<core::type::F32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kF32;
- return true;
- }
- if (ty->Is<core::type::F16>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kF16;
- return true;
- }
- if (auto* vec = ty->As<core::type::Vector>()) {
- switch (vec->Width()) {
- case 2:
- if (vec->Type()->Is<core::type::I32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec2I32;
- return true;
- }
- if (vec->Type()->Is<core::type::U32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec2U32;
- return true;
- }
- if (vec->Type()->Is<core::type::F32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec2F32;
- return true;
- }
- if (vec->Type()->Is<core::type::F16>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec2F16;
- return true;
- }
- break;
- case 3:
- if (vec->Type()->Is<core::type::I32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec3I32;
- return true;
- }
- if (vec->Type()->Is<core::type::U32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec3U32;
- return true;
- }
- if (vec->Type()->Is<core::type::F32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec3F32;
- return true;
- }
- if (vec->Type()->Is<core::type::F16>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec3F16;
- return true;
- }
- break;
- case 4:
- if (vec->Type()->Is<core::type::I32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec4I32;
- return true;
- }
- if (vec->Type()->Is<core::type::U32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec4U32;
- return true;
- }
- if (vec->Type()->Is<core::type::F32>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec4F32;
- return true;
- }
- if (vec->Type()->Is<core::type::F16>()) {
- out = DecomposeMemoryAccess::Intrinsic::DataType::kVec4F16;
- return true;
- }
- break;
- }
- return false;
- }
-
- return false;
-}
-
-/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function to
-/// load the type @p ty from the uniform or storage buffer with name @p buffer.
-DecomposeMemoryAccess::Intrinsic* IntrinsicLoadFor(ast::Builder* builder,
- const core::type::Type* ty,
- core::AddressSpace address_space,
- const Symbol& buffer) {
- DecomposeMemoryAccess::Intrinsic::DataType type;
- if (!IntrinsicDataTypeFor(ty, type)) {
- return nullptr;
- }
- return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
- builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kLoad, type,
- address_space, builder->Expr(buffer));
-}
-
-/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function to
-/// store the type @p ty to the storage buffer with name @p buffer.
-DecomposeMemoryAccess::Intrinsic* IntrinsicStoreFor(ast::Builder* builder,
- const core::type::Type* ty,
- const Symbol& buffer) {
- DecomposeMemoryAccess::Intrinsic::DataType type;
- if (!IntrinsicDataTypeFor(ty, type)) {
- return nullptr;
- }
- return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
- builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kStore,
- type, core::AddressSpace::kStorage, builder->Expr(buffer));
-}
-
-/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function for
-/// the atomic op and the type @p ty.
-DecomposeMemoryAccess::Intrinsic* IntrinsicAtomicFor(ast::Builder* builder,
- wgsl::BuiltinFn ity,
- const core::type::Type* ty,
- const Symbol& buffer) {
- auto op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
- switch (ity) {
- case wgsl::BuiltinFn::kAtomicLoad:
- op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
- break;
- case wgsl::BuiltinFn::kAtomicStore:
- op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicStore;
- break;
- case wgsl::BuiltinFn::kAtomicAdd:
- op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAdd;
- break;
- case wgsl::BuiltinFn::kAtomicSub:
- op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicSub;
- break;
- case wgsl::BuiltinFn::kAtomicMax:
- op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMax;
- break;
- case wgsl::BuiltinFn::kAtomicMin:
- op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMin;
- break;
- case wgsl::BuiltinFn::kAtomicAnd:
- op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAnd;
- break;
- case wgsl::BuiltinFn::kAtomicOr:
- op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicOr;
- break;
- case wgsl::BuiltinFn::kAtomicXor:
- op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicXor;
- break;
- case wgsl::BuiltinFn::kAtomicExchange:
- op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicExchange;
- break;
- case wgsl::BuiltinFn::kAtomicCompareExchangeWeak:
- op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicCompareExchangeWeak;
- break;
- default:
- TINT_ICE() << "invalid IntrinsicType for DecomposeMemoryAccess::Intrinsic: "
- << ty->TypeInfo().name;
- }
-
- DecomposeMemoryAccess::Intrinsic::DataType type;
- if (!IntrinsicDataTypeFor(ty, type)) {
- return nullptr;
- }
- return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
- builder->ID(), builder->AllocateNodeID(), op, type, core::AddressSpace::kStorage,
- builder->Expr(buffer));
-}
-
-/// BufferAccess describes a single storage or uniform buffer access
-struct BufferAccess {
- sem::GlobalVariable const* var = nullptr; // Storage or uniform buffer variable
- Offset const* offset = nullptr; // The byte offset on var
- core::type::Type const* type = nullptr; // The type of the access
- explicit operator bool() const { return var != nullptr; } // Returns true if valid
-};
-
-/// Store describes a single storage or uniform buffer write
-struct Store {
- const ast::AssignmentStatement* assignment; // The AST assignment statement
- BufferAccess target; // The target for the write
-};
-
-} // namespace
-
-/// PIMPL state for the transform
-struct DecomposeMemoryAccess::State {
- /// The clone context
- program::CloneContext& ctx;
- /// Alias to `*ctx.dst`
- ast::Builder& b;
- /// Map of AST expression to storage or uniform buffer access
- /// This map has entries added when encountered, and removed when outer
- /// expressions chain the access.
- /// Subset of #expression_order, as expressions are not removed from
- /// #expression_order.
- std::unordered_map<const ast::Expression*, BufferAccess> accesses;
- /// The visited order of AST expressions (superset of #accesses)
- std::vector<const ast::Expression*> expression_order;
- /// [buffer-type, element-type] -> load function name
- std::unordered_map<LoadStoreKey, Symbol, LoadStoreKey::Hasher> load_funcs;
- /// [buffer-type, element-type] -> store function name
- std::unordered_map<LoadStoreKey, Symbol, LoadStoreKey::Hasher> store_funcs;
- /// [buffer-type, element-type, atomic-op] -> load function name
- std::unordered_map<AtomicKey, Symbol, AtomicKey::Hasher> atomic_funcs;
- /// List of storage or uniform buffer writes
- std::vector<Store> stores;
- /// Allocations for offsets
- BlockAllocator<Offset> offsets_;
-
- /// Constructor
- /// @param context the program::CloneContext
- explicit State(program::CloneContext& context) : ctx(context), b(*ctx.dst) {}
-
- /// @param offset the offset value to wrap in an Offset
- /// @returns an Offset for the given literal value
- const Offset* ToOffset(uint32_t offset) { return offsets_.Create<OffsetLiteral>(offset); }
-
- /// @param expr the expression to convert to an Offset
- /// @returns an Offset for the given Expression
- const Offset* ToOffset(const ast::Expression* expr) {
- if (auto* lit = expr->As<ast::IntLiteralExpression>()) {
- if (lit->value >= 0) {
- return offsets_.Create<OffsetLiteral>(static_cast<uint32_t>(lit->value));
- }
- }
- return offsets_.Create<OffsetExpr>(expr);
- }
-
- /// @param offset the Offset that is returned
- /// @returns the given offset (pass-through)
- const Offset* ToOffset(const Offset* offset) { return offset; }
-
- /// @param lhs_ the left-hand side of the add expression
- /// @param rhs_ the right-hand side of the add expression
- /// @return an Offset that is a sum of lhs and rhs, performing basic constant
- /// folding if possible
- template <typename LHS, typename RHS>
- const Offset* Add(LHS&& lhs_, RHS&& rhs_) {
- auto* lhs = ToOffset(std::forward<LHS>(lhs_));
- auto* rhs = ToOffset(std::forward<RHS>(rhs_));
- auto* lhs_lit = tint::As<OffsetLiteral>(lhs);
- auto* rhs_lit = tint::As<OffsetLiteral>(rhs);
- if (lhs_lit && lhs_lit->literal == 0) {
- return rhs;
- }
- if (rhs_lit && rhs_lit->literal == 0) {
- return lhs;
- }
- if (lhs_lit && rhs_lit) {
- if (static_cast<uint64_t>(lhs_lit->literal) + static_cast<uint64_t>(rhs_lit->literal) <=
- 0xffffffff) {
- return offsets_.Create<OffsetLiteral>(lhs_lit->literal + rhs_lit->literal);
- }
- }
- auto* out = offsets_.Create<OffsetBinOp>();
- out->op = core::BinaryOp::kAdd;
- out->lhs = lhs;
- out->rhs = rhs;
- return out;
- }
-
- /// @param lhs_ the left-hand side of the multiply expression
- /// @param rhs_ the right-hand side of the multiply expression
- /// @return an Offset that is the multiplication of lhs and rhs, performing
- /// basic constant folding if possible
- template <typename LHS, typename RHS>
- const Offset* Mul(LHS&& lhs_, RHS&& rhs_) {
- auto* lhs = ToOffset(std::forward<LHS>(lhs_));
- auto* rhs = ToOffset(std::forward<RHS>(rhs_));
- auto* lhs_lit = tint::As<OffsetLiteral>(lhs);
- auto* rhs_lit = tint::As<OffsetLiteral>(rhs);
- if (lhs_lit && lhs_lit->literal == 0) {
- return offsets_.Create<OffsetLiteral>(0u);
- }
- if (rhs_lit && rhs_lit->literal == 0) {
- return offsets_.Create<OffsetLiteral>(0u);
- }
- if (lhs_lit && lhs_lit->literal == 1) {
- return rhs;
- }
- if (rhs_lit && rhs_lit->literal == 1) {
- return lhs;
- }
- if (lhs_lit && rhs_lit) {
- return offsets_.Create<OffsetLiteral>(lhs_lit->literal * rhs_lit->literal);
- }
- auto* out = offsets_.Create<OffsetBinOp>();
- out->op = core::BinaryOp::kMultiply;
- out->lhs = lhs;
- out->rhs = rhs;
- return out;
- }
-
- /// AddAccess() adds the `expr -> access` map item to #accesses, and `expr`
- /// to #expression_order.
- /// @param expr the expression that performs the access
- /// @param access the access
- void AddAccess(const ast::Expression* expr, const BufferAccess& access) {
- TINT_ASSERT(access.type);
- accesses.emplace(expr, access);
- expression_order.emplace_back(expr);
- }
-
- /// TakeAccess() removes the `node` item from #accesses (if it exists),
- /// returning the BufferAccess. If #accesses does not hold an item for
- /// `node`, an invalid BufferAccess is returned.
- /// @param node the expression that performed an access
- /// @return the BufferAccess for the given expression
- BufferAccess TakeAccess(const ast::Expression* node) {
- auto lhs_it = accesses.find(node);
- if (lhs_it == accesses.end()) {
- return {};
- }
- auto access = lhs_it->second;
- accesses.erase(node);
- return access;
- }
-
- /// LoadFunc() returns a symbol to an intrinsic function that loads an element of type @p el_ty
- /// from a storage or uniform buffer with name @p buffer.
- /// The emitted function has the signature:
- /// `fn load(offset : u32) -> el_ty`
- /// @param el_ty the storage or uniform buffer element type
- /// @param address_space either kUniform or kStorage
- /// @param buffer the symbol of the storage or uniform buffer variable, owned by the target
- /// ProgramBuilder.
- /// @return the name of the function that performs the load
- Symbol LoadFunc(const core::type::Type* el_ty,
- core::AddressSpace address_space,
- const Symbol& buffer) {
- return tint::GetOrAdd(load_funcs, LoadStoreKey{el_ty, buffer}, [&] {
- Vector params{b.Param("offset", b.ty.u32())};
-
- auto name = b.Symbols().New(buffer.Name() + "_load");
-
- if (auto* intrinsic = IntrinsicLoadFor(ctx.dst, el_ty, address_space, buffer)) {
- auto el_ast_ty = CreateASTTypeFor(ctx, el_ty);
- b.Func(name, params, el_ast_ty, nullptr,
- Vector{
- intrinsic,
- b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
- });
- } else if (auto* arr_ty = el_ty->As<core::type::Array>()) {
- // fn load_func(buffer : buf_ty, offset : u32) -> array<T, N> {
- // var arr : array<T, N>;
- // for (var i = 0u; i < array_count; i = i + 1) {
- // arr[i] = el_load_func(buffer, offset + i * array_stride)
- // }
- // return arr;
- // }
- auto load = LoadFunc(arr_ty->ElemType()->UnwrapRef(), address_space, buffer);
- auto* arr = b.Var(b.Symbols().New("arr"), CreateASTTypeFor(ctx, arr_ty));
- auto* i = b.Var(b.Symbols().New("i"), b.Expr(0_u));
- auto* for_init = b.Decl(i);
- auto arr_cnt = arr_ty->ConstantCount();
- if (DAWN_UNLIKELY(!arr_cnt)) {
- // Non-constant counts should not be possible:
- // * Override-expression counts can only be applied to workgroup arrays, and
- // this method only handles storage and uniform.
- // * Runtime-sized arrays are not loadable.
- TINT_ICE() << "unexpected non-constant array count";
- }
- auto* for_cond = b.create<ast::BinaryExpression>(
- core::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_cnt.value())));
- auto* for_cont = b.Assign(i, b.Add(i, 1_u));
- auto* arr_el = b.IndexAccessor(arr, i);
- auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
- auto* el_val = b.Call(load, el_offset);
- auto* for_loop =
- b.For(for_init, for_cond, for_cont, b.Block(b.Assign(arr_el, el_val)));
-
- b.Func(name, params, CreateASTTypeFor(ctx, arr_ty),
- Vector{
- b.Decl(arr),
- for_loop,
- b.Return(arr),
- });
- } else {
- Vector<const ast::Expression*, 8> values;
- if (auto* mat_ty = el_ty->As<core::type::Matrix>()) {
- auto* vec_ty = mat_ty->ColumnType();
- Symbol load = LoadFunc(vec_ty, address_space, buffer);
- for (uint32_t i = 0; i < mat_ty->Columns(); i++) {
- auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
- values.Push(b.Call(load, offset));
- }
- } else if (auto* str = el_ty->As<core::type::Struct>()) {
- for (auto* member : str->Members()) {
- auto* offset = b.Add("offset", u32(member->Offset()));
- Symbol load = LoadFunc(member->Type()->UnwrapRef(), address_space, buffer);
- values.Push(b.Call(load, offset));
- }
- }
- b.Func(name, params, CreateASTTypeFor(ctx, el_ty),
- Vector{
- b.Return(b.Call(CreateASTTypeFor(ctx, el_ty), values)),
- });
- }
- return name;
- });
- }
-
- /// StoreFunc() returns a symbol to an intrinsic function that stores an element of type @p
- /// el_ty to the storage buffer @p buffer. The function has the signature:
- /// `fn store(offset : u32, value : el_ty)`
- /// @param el_ty the storage buffer element type
- /// @param buffer the symbol of the storage buffer variable, owned by the target ProgramBuilder.
- /// @return the name of the function that performs the store
- Symbol StoreFunc(const core::type::Type* el_ty, const Symbol& buffer) {
- return tint::GetOrAdd(store_funcs, LoadStoreKey{el_ty, buffer}, [&] {
- Vector params{
- b.Param("offset", b.ty.u32()),
- b.Param("value", CreateASTTypeFor(ctx, el_ty)),
- };
-
- auto name = b.Symbols().New(buffer.Name() + "_store");
-
- if (auto* intrinsic = IntrinsicStoreFor(ctx.dst, el_ty, buffer)) {
- b.Func(name, params, b.ty.void_(), nullptr,
- Vector{
- intrinsic,
- b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
- });
- } else {
- auto body = Switch<Vector<const ast::Statement*, 8>>(
- el_ty, //
- [&](const core::type::Array* arr_ty) {
- // fn store_func(buffer : buf_ty, offset : u32, value : el_ty) {
- // var array = value; // No dynamic indexing on constant arrays
- // for (var i = 0u; i < array_count; i = i + 1) {
- // arr[i] = el_store_func(buffer, offset + i * array_stride,
- // value[i])
- // }
- // return arr;
- // }
- auto* array = b.Var(b.Symbols().New("array"), b.Expr("value"));
- auto store = StoreFunc(arr_ty->ElemType()->UnwrapRef(), buffer);
- auto* i = b.Var(b.Symbols().New("i"), b.Expr(0_u));
- auto* for_init = b.Decl(i);
- auto arr_cnt = arr_ty->ConstantCount();
- if (DAWN_UNLIKELY(!arr_cnt)) {
- // Non-constant counts should not be possible:
- // * Override-expression counts can only be applied to workgroup
- // arrays, and this method only handles storage and uniform.
- // * Runtime-sized arrays are not storable.
- TINT_ICE() << "unexpected non-constant array count";
- }
- auto* for_cond = b.create<ast::BinaryExpression>(
- core::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_cnt.value())));
- auto* for_cont = b.Assign(i, b.Add(i, 1_u));
- auto* arr_el = b.IndexAccessor(array, i);
- auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
- auto* store_stmt = b.CallStmt(b.Call(store, el_offset, arr_el));
- auto* for_loop = b.For(for_init, for_cond, for_cont, b.Block(store_stmt));
-
- return Vector{b.Decl(array), for_loop};
- },
- [&](const core::type::Matrix* mat_ty) {
- auto* vec_ty = mat_ty->ColumnType();
- Symbol store = StoreFunc(vec_ty, buffer);
- Vector<const ast::Statement*, 4> stmts;
- for (uint32_t i = 0; i < mat_ty->Columns(); i++) {
- auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
- auto* element = b.IndexAccessor("value", u32(i));
- auto* call = b.Call(store, offset, element);
- stmts.Push(b.CallStmt(call));
- }
- return stmts;
- },
- [&](const core::type::Struct* str) {
- Vector<const ast::Statement*, 8> stmts;
- for (auto* member : str->Members()) {
- auto* offset = b.Add("offset", u32(member->Offset()));
- auto* element = b.MemberAccessor("value", ctx.Clone(member->Name()));
- Symbol store = StoreFunc(member->Type()->UnwrapRef(), buffer);
- auto* call = b.Call(store, offset, element);
- stmts.Push(b.CallStmt(call));
- }
- return stmts;
- });
-
- b.Func(name, params, b.ty.void_(), body);
- }
-
- return name;
- });
- }
-
- /// AtomicFunc() returns a symbol to an builtin function that performs an atomic operation on
- /// the storage buffer @p buffer. The function has the signature:
- // `fn atomic_op(offset : u32, ...) -> T`
- /// @param el_ty the storage buffer element type
- /// @param builtin the atomic builtin
- /// @param buffer the symbol of the storage buffer variable, owned by the target ProgramBuilder.
- /// @return the name of the function that performs the load
- Symbol AtomicFunc(const core::type::Type* el_ty,
- const sem::BuiltinFn* builtin,
- const Symbol& buffer) {
- auto fn = builtin->Fn();
- return tint::GetOrAdd(atomic_funcs, AtomicKey{el_ty, fn, buffer}, [&] {
- // The first parameter to all WGSL atomics is the expression to the
- // atomic. This is replaced with two parameters: the buffer and offset.
- Vector params{b.Param("offset", b.ty.u32())};
-
- // Other parameters are copied as-is:
- for (size_t i = 1; i < builtin->Parameters().Length(); i++) {
- auto* param = builtin->Parameters()[i];
- auto ty = CreateASTTypeFor(ctx, param->Type());
- params.Push(b.Param("param_" + std::to_string(i), ty));
- }
-
- auto* atomic = IntrinsicAtomicFor(ctx.dst, fn, el_ty, buffer);
- if (DAWN_UNLIKELY(!atomic)) {
- TINT_ICE() << "IntrinsicAtomicFor() returned nullptr for fn " << fn << " and type "
- << el_ty->TypeInfo().name;
- }
-
- ast::Type ret_ty = CreateASTTypeFor(ctx, builtin->ReturnType());
-
- auto name = b.Symbols().New(buffer.Name() + builtin->str());
- b.Func(name, std::move(params), ret_ty, nullptr,
- Vector{
- atomic,
- b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
- });
- return name;
- });
- }
-};
-
-DecomposeMemoryAccess::Intrinsic::Intrinsic(GenerationID pid,
- ast::NodeID nid,
- Op o,
- DataType ty,
- core::AddressSpace as,
- const ast::IdentifierExpression* buf)
- : Base(pid, nid, Vector{buf}), op(o), type(ty), address_space(as) {}
-DecomposeMemoryAccess::Intrinsic::~Intrinsic() = default;
-std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
- StringStream ss;
- switch (op) {
- case Op::kLoad:
- ss << "intrinsic_load_";
- break;
- case Op::kStore:
- ss << "intrinsic_store_";
- break;
- case Op::kAtomicLoad:
- ss << "intrinsic_atomic_load_";
- break;
- case Op::kAtomicStore:
- ss << "intrinsic_atomic_store_";
- break;
- case Op::kAtomicAdd:
- ss << "intrinsic_atomic_add_";
- break;
- case Op::kAtomicSub:
- ss << "intrinsic_atomic_sub_";
- break;
- case Op::kAtomicMax:
- ss << "intrinsic_atomic_max_";
- break;
- case Op::kAtomicMin:
- ss << "intrinsic_atomic_min_";
- break;
- case Op::kAtomicAnd:
- ss << "intrinsic_atomic_and_";
- break;
- case Op::kAtomicOr:
- ss << "intrinsic_atomic_or_";
- break;
- case Op::kAtomicXor:
- ss << "intrinsic_atomic_xor_";
- break;
- case Op::kAtomicExchange:
- ss << "intrinsic_atomic_exchange_";
- break;
- case Op::kAtomicCompareExchangeWeak:
- ss << "intrinsic_atomic_compare_exchange_weak_";
- break;
- }
- ss << address_space << "_";
- switch (type) {
- case DataType::kU32:
- ss << "u32";
- break;
- case DataType::kF32:
- ss << "f32";
- break;
- case DataType::kI32:
- ss << "i32";
- break;
- case DataType::kF16:
- ss << "f16";
- break;
- case DataType::kVec2U32:
- ss << "vec2_u32";
- break;
- case DataType::kVec2F32:
- ss << "vec2_f32";
- break;
- case DataType::kVec2I32:
- ss << "vec2_i32";
- break;
- case DataType::kVec2F16:
- ss << "vec2_f16";
- break;
- case DataType::kVec3U32:
- ss << "vec3_u32";
- break;
- case DataType::kVec3F32:
- ss << "vec3_f32";
- break;
- case DataType::kVec3I32:
- ss << "vec3_i32";
- break;
- case DataType::kVec3F16:
- ss << "vec3_f16";
- break;
- case DataType::kVec4U32:
- ss << "vec4_u32";
- break;
- case DataType::kVec4F32:
- ss << "vec4_f32";
- break;
- case DataType::kVec4I32:
- ss << "vec4_i32";
- break;
- case DataType::kVec4F16:
- ss << "vec4_f16";
- break;
- }
- return ss.str();
-}
-
-const DecomposeMemoryAccess::Intrinsic* DecomposeMemoryAccess::Intrinsic::Clone(
- ast::CloneContext& ctx) const {
- auto buf = ctx.Clone(Buffer());
- return ctx.dst->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
- ctx.dst->ID(), ctx.dst->AllocateNodeID(), op, type, address_space, buf);
-}
-
-bool DecomposeMemoryAccess::Intrinsic::IsAtomic() const {
- return op != Op::kLoad && op != Op::kStore;
-}
-
-const ast::IdentifierExpression* DecomposeMemoryAccess::Intrinsic::Buffer() const {
- return dependencies[0];
-}
-
-DecomposeMemoryAccess::DecomposeMemoryAccess() = default;
-DecomposeMemoryAccess::~DecomposeMemoryAccess() = default;
-
-ast::transform::Transform::ApplyResult DecomposeMemoryAccess::Apply(
- const Program& src,
- const ast::transform::DataMap&,
- ast::transform::DataMap&) const {
- if (!ShouldRun(src)) {
- return SkipTransform;
- }
-
- auto& sem = src.Sem();
- ProgramBuilder b;
- program::CloneContext ctx{&b, &src, /* auto_clone_symbols */ true};
- State state(ctx);
-
- // Scan the AST nodes for storage and uniform buffer accesses. Complex
- // expression chains (e.g. `storage_buffer.foo.bar[20].x`) are handled by
- // maintaining an offset chain via the `state.TakeAccess()`,
- // `state.AddAccess()` methods.
- //
- // Inner-most expression nodes are guaranteed to be visited first because AST
- // nodes are fully immutable and require their children to be constructed
- // first so their pointer can be passed to the parent's initializer.
- for (auto* node : src.ASTNodes().Objects()) {
- if (auto* ident = node->As<ast::IdentifierExpression>()) {
- // X
- if (auto* sem_ident = sem.GetVal(ident)) {
- if (auto* user = sem_ident->UnwrapLoad()->As<sem::VariableUser>()) {
- if (auto* global = user->Variable()->As<sem::GlobalVariable>()) {
- if (global->AddressSpace() == core::AddressSpace::kStorage ||
- global->AddressSpace() == core::AddressSpace::kUniform) {
- // Variable to a storage or uniform buffer
- state.AddAccess(ident, {
- global,
- state.ToOffset(0u),
- global->Type()->UnwrapRef(),
- });
- }
- }
- }
- }
- continue;
- }
-
- if (auto* accessor = node->As<ast::MemberAccessorExpression>()) {
- // X.Y
- auto* accessor_sem = sem.Get(accessor)->UnwrapLoad();
- if (auto* swizzle = accessor_sem->As<sem::Swizzle>()) {
- if (swizzle->Indices().Length() == 1) {
- if (auto access = state.TakeAccess(accessor->object)) {
- auto* vec_ty = access.type->As<core::type::Vector>();
- auto* offset = state.Mul(vec_ty->Type()->Size(), swizzle->Indices()[0u]);
- state.AddAccess(accessor, {
- access.var,
- state.Add(access.offset, offset),
- vec_ty->Type(),
- });
- }
- }
- } else {
- if (auto access = state.TakeAccess(accessor->object)) {
- auto* str_ty = access.type->As<core::type::Struct>();
- auto* member = str_ty->FindMember(accessor->member->symbol);
- auto offset = member->Offset();
- state.AddAccess(accessor, {
- access.var,
- state.Add(access.offset, offset),
- member->Type(),
- });
- }
- }
- continue;
- }
-
- if (auto* accessor = node->As<ast::IndexAccessorExpression>()) {
- if (auto access = state.TakeAccess(accessor->object)) {
- // X[Y]
- if (auto* arr = access.type->As<core::type::Array>()) {
- auto* offset = state.Mul(arr->Stride(), accessor->index);
- state.AddAccess(accessor, {
- access.var,
- state.Add(access.offset, offset),
- arr->ElemType(),
- });
- continue;
- }
- if (auto* vec_ty = access.type->As<core::type::Vector>()) {
- auto* offset = state.Mul(vec_ty->Type()->Size(), accessor->index);
- state.AddAccess(accessor, {
- access.var,
- state.Add(access.offset, offset),
- vec_ty->Type(),
- });
- continue;
- }
- if (auto* mat_ty = access.type->As<core::type::Matrix>()) {
- auto* offset = state.Mul(mat_ty->ColumnStride(), accessor->index);
- state.AddAccess(accessor, {
- access.var,
- state.Add(access.offset, offset),
- mat_ty->ColumnType(),
- });
- continue;
- }
- }
- }
-
- if (auto* op = node->As<ast::UnaryOpExpression>()) {
- if (op->op == core::UnaryOp::kAddressOf) {
- // &X
- if (auto access = state.TakeAccess(op->expr)) {
- // HLSL does not support pointers, so just take the access from the
- // reference and place it on the pointer.
- state.AddAccess(op, access);
- continue;
- }
- }
- }
-
- if (auto* assign = node->As<ast::AssignmentStatement>()) {
- // X = Y
- // Move the LHS access to a store.
- if (auto lhs = state.TakeAccess(assign->lhs)) {
- state.stores.emplace_back(Store{assign, lhs});
- }
- }
-
- if (auto* call_expr = node->As<ast::CallExpression>()) {
- auto* call = sem.Get(call_expr)->UnwrapMaterialize()->As<sem::Call>();
- if (auto* builtin = call->Target()->As<sem::BuiltinFn>()) {
- if (builtin->Fn() == wgsl::BuiltinFn::kArrayLength) {
- // arrayLength(X)
- // Don't convert X into a load, this builtin actually requires the real pointer.
- state.TakeAccess(call_expr->args[0]);
- continue;
- }
- if (builtin->IsAtomic()) {
- if (auto access = state.TakeAccess(call_expr->args[0])) {
- // atomic___(X)
- ctx.Replace(call_expr, [=, &ctx, &state] {
- auto* offset = access.offset->Build(ctx);
- auto* el_ty =
- access.type->UnwrapRef()->As<core::type::Atomic>()->Type();
- auto buffer = ctx.Clone(access.var->Declaration()->name->symbol);
- Symbol func = state.AtomicFunc(el_ty, builtin, buffer);
-
- Vector<const ast::Expression*, 8> args{offset};
- for (size_t i = 1; i < call_expr->args.Length(); i++) {
- auto* arg = call_expr->args[i];
- args.Push(ctx.Clone(arg));
- }
- return ctx.dst->Call(func, args);
- });
- }
- }
- }
- }
- }
-
- // All remaining accesses are loads, transform these into calls to the
- // corresponding load function
- // TODO(crbug.com/tint/1784): Use `sem::Load`s instead of maintaining `state.expression_order`.
- for (auto* expr : state.expression_order) {
- auto access_it = state.accesses.find(expr);
- if (access_it == state.accesses.end()) {
- continue;
- }
- BufferAccess access = access_it->second;
- ctx.Replace(expr, [=, &ctx, &state] {
- auto* offset = access.offset->Build(ctx);
- auto* el_ty = access.type->UnwrapRef();
- auto buffer = ctx.Clone(access.var->Declaration()->name->symbol);
- Symbol func = state.LoadFunc(el_ty, access.var->AddressSpace(), buffer);
- return ctx.dst->Call(func, offset);
- });
- }
-
- // And replace all storage and uniform buffer assignments with stores
- for (auto store : state.stores) {
- ctx.Replace(store.assignment, [=, &ctx, &state] {
- auto* offset = store.target.offset->Build(ctx);
- auto* el_ty = store.target.type->UnwrapRef();
- auto* value = store.assignment->rhs;
- auto buffer = ctx.Clone(store.target.var->Declaration()->name->symbol);
- Symbol func = state.StoreFunc(el_ty, buffer);
- auto* call = ctx.dst->Call(func, offset, ctx.Clone(value));
- return ctx.dst->CallStmt(call);
- });
- }
-
- ctx.Clone();
- return resolver::Resolve(b);
-}
-
-} // namespace tint::hlsl::writer
-
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::Offset);
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::OffsetLiteral);
diff --git a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.h b/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.h
deleted file mode 100644
index 37f04d3..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.h
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2021 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_LANG_HLSL_WRITER_AST_RAISE_DECOMPOSE_MEMORY_ACCESS_H_
-#define SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_DECOMPOSE_MEMORY_ACCESS_H_
-
-#include <string>
-
-#include "src/tint/lang/wgsl/ast/internal_attribute.h"
-#include "src/tint/lang/wgsl/ast/transform/transform.h"
-
-namespace tint::hlsl::writer {
-
-/// DecomposeMemoryAccess is a transform used to replace storage and uniform buffer accesses with a
-/// combination of load, store or atomic functions on primitive types.
-class DecomposeMemoryAccess final
- : public Castable<DecomposeMemoryAccess, ast::transform::Transform> {
- public:
- /// Intrinsic is an InternalAttribute that's used to decorate a stub function so that the HLSL
- /// transforms this into calls to
- /// `[RW]ByteAddressBuffer.Load[N]()` or `[RW]ByteAddressBuffer.Store[N]()`,
- /// with a possible cast.
- class Intrinsic final : public Castable<Intrinsic, ast::InternalAttribute> {
- public:
- /// Intrinsic op
- enum class Op {
- kLoad,
- kStore,
- kAtomicLoad,
- kAtomicStore,
- kAtomicAdd,
- kAtomicSub,
- kAtomicMax,
- kAtomicMin,
- kAtomicAnd,
- kAtomicOr,
- kAtomicXor,
- kAtomicExchange,
- kAtomicCompareExchangeWeak,
- };
-
- /// Intrinsic data type
- enum class DataType {
- kU32,
- kF32,
- kI32,
- kF16,
- kVec2U32,
- kVec2F32,
- kVec2I32,
- kVec2F16,
- kVec3U32,
- kVec3F32,
- kVec3I32,
- kVec3F16,
- kVec4U32,
- kVec4F32,
- kVec4I32,
- kVec4F16,
- };
-
- /// Constructor
- /// @param pid the identifier of the program that owns this node
- /// @param nid the unique node identifier
- /// @param o the op of the intrinsic
- /// @param type the data type of the intrinsic
- /// @param address_space the address space of the buffer
- /// @param buffer the storage or uniform buffer identifier
- Intrinsic(GenerationID pid,
- ast::NodeID nid,
- Op o,
- DataType type,
- core::AddressSpace address_space,
- const ast::IdentifierExpression* buffer);
- /// Destructor
- ~Intrinsic() override;
-
- /// @return a short description of the internal attribute which will be
- /// displayed as `@internal(<name>)`
- std::string InternalName() const override;
-
- /// Performs a deep clone of this object using the program::CloneContext `ctx`.
- /// @param ctx the clone context
- /// @return the newly cloned object
- const Intrinsic* Clone(ast::CloneContext& ctx) const override;
-
- /// @return true if op is atomic
- bool IsAtomic() const;
-
- /// @return the buffer that this intrinsic operates on
- const ast::IdentifierExpression* Buffer() const;
-
- /// The op of the intrinsic
- const Op op;
-
- /// The type of the intrinsic
- const DataType type;
-
- /// The address space of the buffer this intrinsic operates on
- const core::AddressSpace address_space;
- };
-
- /// Constructor
- DecomposeMemoryAccess();
- /// Destructor
- ~DecomposeMemoryAccess() override;
-
- /// @copydoc ast::transform::Transform::Apply
- ApplyResult Apply(const Program& program,
- const ast::transform::DataMap& inputs,
- ast::transform::DataMap& outputs) const override;
-
- private:
- struct State;
-};
-
-} // namespace tint::hlsl::writer
-
-#endif // SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_DECOMPOSE_MEMORY_ACCESS_H_
diff --git a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access_test.cc b/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access_test.cc
deleted file mode 100644
index d9addc3..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access_test.cc
+++ /dev/null
@@ -1,4033 +0,0 @@
-// Copyright 2021 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/hlsl/writer/ast_raise/decompose_memory_access.h"
-#include "src/tint/lang/wgsl/ast/transform/helper_test.h"
-#include "src/tint/lang/wgsl/ast/transform/simplify_pointers.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using DecomposeMemoryAccessTest = ast::transform::TransformTest;
-
-TEST_F(DecomposeMemoryAccessTest, ShouldRunEmptyModule) {
- auto* src = R"()";
-
- EXPECT_FALSE(ShouldRun<DecomposeMemoryAccess>(src));
-}
-
-TEST_F(DecomposeMemoryAccessTest, ShouldRunStorageBuffer) {
- auto* src = R"(
-struct Buffer {
- i : i32,
-};
-@group(0) @binding(0) var<storage, read_write> sb : Buffer;
-)";
-
- EXPECT_TRUE(ShouldRun<DecomposeMemoryAccess>(src));
-}
-
-TEST_F(DecomposeMemoryAccessTest, ShouldRunUniformBuffer) {
- auto* src = R"(
-struct Buffer {
- i : i32,
-};
-@group(0) @binding(0) var<uniform> ub : Buffer;
-)";
-
- EXPECT_TRUE(ShouldRun<DecomposeMemoryAccess>(src));
-}
-
-TEST_F(DecomposeMemoryAccessTest, SB_BasicLoad) {
- auto* src = R"(
-enable f16;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_vec3_f16 : array<vec3<f16>, 2>,
-};
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var scalar_f32 : f32 = sb.scalar_f32;
- var scalar_i32 : i32 = sb.scalar_i32;
- var scalar_u32 : u32 = sb.scalar_u32;
- var scalar_f16 : f16 = sb.scalar_f16;
- var vec2_f32 : vec2<f32> = sb.vec2_f32;
- var vec2_i32 : vec2<i32> = sb.vec2_i32;
- var vec2_u32 : vec2<u32> = sb.vec2_u32;
- var vec2_f16 : vec2<f16> = sb.vec2_f16;
- var vec3_f32 : vec3<f32> = sb.vec3_f32;
- var vec3_i32 : vec3<i32> = sb.vec3_i32;
- var vec3_u32 : vec3<u32> = sb.vec3_u32;
- var vec3_f16 : vec3<f16> = sb.vec3_f16;
- var vec4_f32 : vec4<f32> = sb.vec4_f32;
- var vec4_i32 : vec4<i32> = sb.vec4_i32;
- var vec4_u32 : vec4<u32> = sb.vec4_u32;
- var vec4_f16 : vec4<f16> = sb.vec4_f16;
- var mat2x2_f32 : mat2x2<f32> = sb.mat2x2_f32;
- var mat2x3_f32 : mat2x3<f32> = sb.mat2x3_f32;
- var mat2x4_f32 : mat2x4<f32> = sb.mat2x4_f32;
- var mat3x2_f32 : mat3x2<f32> = sb.mat3x2_f32;
- var mat3x3_f32 : mat3x3<f32> = sb.mat3x3_f32;
- var mat3x4_f32 : mat3x4<f32> = sb.mat3x4_f32;
- var mat4x2_f32 : mat4x2<f32> = sb.mat4x2_f32;
- var mat4x3_f32 : mat4x3<f32> = sb.mat4x3_f32;
- var mat4x4_f32 : mat4x4<f32> = sb.mat4x4_f32;
- var mat2x2_f16 : mat2x2<f16> = sb.mat2x2_f16;
- var mat2x3_f16 : mat2x3<f16> = sb.mat2x3_f16;
- var mat2x4_f16 : mat2x4<f16> = sb.mat2x4_f16;
- var mat3x2_f16 : mat3x2<f16> = sb.mat3x2_f16;
- var mat3x3_f16 : mat3x3<f16> = sb.mat3x3_f16;
- var mat3x4_f16 : mat3x4<f16> = sb.mat3x4_f16;
- var mat4x2_f16 : mat4x2<f16> = sb.mat4x2_f16;
- var mat4x3_f16 : mat4x3<f16> = sb.mat4x3_f16;
- var mat4x4_f16 : mat4x4<f16> = sb.mat4x4_f16;
- var arr2_vec3_f32 : array<vec3<f32>, 2> = sb.arr2_vec3_f32;
- var arr2_vec3_f16 : array<vec3<f16>, 2> = sb.arr2_vec3_f16;
-}
-)";
-
- auto* expect = R"(
-enable f16;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_vec3_f16 : array<vec3<f16>, 2>,
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load(offset : u32) -> f32
-
-@internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_1(offset : u32) -> i32
-
-@internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_2(offset : u32) -> u32
-
-@internal(intrinsic_load_storage_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_3(offset : u32) -> f16
-
-@internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_4(offset : u32) -> vec2<f32>
-
-@internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_5(offset : u32) -> vec2<i32>
-
-@internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_6(offset : u32) -> vec2<u32>
-
-@internal(intrinsic_load_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_7(offset : u32) -> vec2<f16>
-
-@internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_8(offset : u32) -> vec3<f32>
-
-@internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_9(offset : u32) -> vec3<i32>
-
-@internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_10(offset : u32) -> vec3<u32>
-
-@internal(intrinsic_load_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_11(offset : u32) -> vec3<f16>
-
-@internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_12(offset : u32) -> vec4<f32>
-
-@internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_13(offset : u32) -> vec4<i32>
-
-@internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_14(offset : u32) -> vec4<u32>
-
-@internal(intrinsic_load_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_15(offset : u32) -> vec4<f16>
-
-fn sb_load_16(offset : u32) -> mat2x2<f32> {
- return mat2x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)));
-}
-
-fn sb_load_17(offset : u32) -> mat2x3<f32> {
- return mat2x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)));
-}
-
-fn sb_load_18(offset : u32) -> mat2x4<f32> {
- return mat2x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)));
-}
-
-fn sb_load_19(offset : u32) -> mat3x2<f32> {
- return mat3x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)), sb_load_4((offset + 16u)));
-}
-
-fn sb_load_20(offset : u32) -> mat3x3<f32> {
- return mat3x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)), sb_load_8((offset + 32u)));
-}
-
-fn sb_load_21(offset : u32) -> mat3x4<f32> {
- return mat3x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)), sb_load_12((offset + 32u)));
-}
-
-fn sb_load_22(offset : u32) -> mat4x2<f32> {
- return mat4x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)), sb_load_4((offset + 16u)), sb_load_4((offset + 24u)));
-}
-
-fn sb_load_23(offset : u32) -> mat4x3<f32> {
- return mat4x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)), sb_load_8((offset + 32u)), sb_load_8((offset + 48u)));
-}
-
-fn sb_load_24(offset : u32) -> mat4x4<f32> {
- return mat4x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)), sb_load_12((offset + 32u)), sb_load_12((offset + 48u)));
-}
-
-fn sb_load_25(offset : u32) -> mat2x2<f16> {
- return mat2x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)));
-}
-
-fn sb_load_26(offset : u32) -> mat2x3<f16> {
- return mat2x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)));
-}
-
-fn sb_load_27(offset : u32) -> mat2x4<f16> {
- return mat2x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)));
-}
-
-fn sb_load_28(offset : u32) -> mat3x2<f16> {
- return mat3x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)), sb_load_7((offset + 8u)));
-}
-
-fn sb_load_29(offset : u32) -> mat3x3<f16> {
- return mat3x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)), sb_load_11((offset + 16u)));
-}
-
-fn sb_load_30(offset : u32) -> mat3x4<f16> {
- return mat3x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)), sb_load_15((offset + 16u)));
-}
-
-fn sb_load_31(offset : u32) -> mat4x2<f16> {
- return mat4x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)), sb_load_7((offset + 8u)), sb_load_7((offset + 12u)));
-}
-
-fn sb_load_32(offset : u32) -> mat4x3<f16> {
- return mat4x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)), sb_load_11((offset + 16u)), sb_load_11((offset + 24u)));
-}
-
-fn sb_load_33(offset : u32) -> mat4x4<f16> {
- return mat4x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)), sb_load_15((offset + 16u)), sb_load_15((offset + 24u)));
-}
-
-fn sb_load_34(offset : u32) -> array<vec3<f32>, 2u> {
- var arr : array<vec3<f32>, 2u>;
- for(var i = 0u; (i < 2u); i = (i + 1u)) {
- arr[i] = sb_load_8((offset + (i * 16u)));
- }
- return arr;
-}
-
-fn sb_load_35(offset : u32) -> array<vec3<f16>, 2u> {
- var arr_1 : array<vec3<f16>, 2u>;
- for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
- arr_1[i_1] = sb_load_11((offset + (i_1 * 8u)));
- }
- return arr_1;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var scalar_f32 : f32 = sb_load(0u);
- var scalar_i32 : i32 = sb_load_1(4u);
- var scalar_u32 : u32 = sb_load_2(8u);
- var scalar_f16 : f16 = sb_load_3(12u);
- var vec2_f32 : vec2<f32> = sb_load_4(16u);
- var vec2_i32 : vec2<i32> = sb_load_5(24u);
- var vec2_u32 : vec2<u32> = sb_load_6(32u);
- var vec2_f16 : vec2<f16> = sb_load_7(40u);
- var vec3_f32 : vec3<f32> = sb_load_8(48u);
- var vec3_i32 : vec3<i32> = sb_load_9(64u);
- var vec3_u32 : vec3<u32> = sb_load_10(80u);
- var vec3_f16 : vec3<f16> = sb_load_11(96u);
- var vec4_f32 : vec4<f32> = sb_load_12(112u);
- var vec4_i32 : vec4<i32> = sb_load_13(128u);
- var vec4_u32 : vec4<u32> = sb_load_14(144u);
- var vec4_f16 : vec4<f16> = sb_load_15(160u);
- var mat2x2_f32 : mat2x2<f32> = sb_load_16(168u);
- var mat2x3_f32 : mat2x3<f32> = sb_load_17(192u);
- var mat2x4_f32 : mat2x4<f32> = sb_load_18(224u);
- var mat3x2_f32 : mat3x2<f32> = sb_load_19(256u);
- var mat3x3_f32 : mat3x3<f32> = sb_load_20(288u);
- var mat3x4_f32 : mat3x4<f32> = sb_load_21(336u);
- var mat4x2_f32 : mat4x2<f32> = sb_load_22(384u);
- var mat4x3_f32 : mat4x3<f32> = sb_load_23(416u);
- var mat4x4_f32 : mat4x4<f32> = sb_load_24(480u);
- var mat2x2_f16 : mat2x2<f16> = sb_load_25(544u);
- var mat2x3_f16 : mat2x3<f16> = sb_load_26(552u);
- var mat2x4_f16 : mat2x4<f16> = sb_load_27(568u);
- var mat3x2_f16 : mat3x2<f16> = sb_load_28(584u);
- var mat3x3_f16 : mat3x3<f16> = sb_load_29(600u);
- var mat3x4_f16 : mat3x4<f16> = sb_load_30(624u);
- var mat4x2_f16 : mat4x2<f16> = sb_load_31(648u);
- var mat4x3_f16 : mat4x3<f16> = sb_load_32(664u);
- var mat4x4_f16 : mat4x4<f16> = sb_load_33(696u);
- var arr2_vec3_f32 : array<vec3<f32>, 2> = sb_load_34(736u);
- var arr2_vec3_f16 : array<vec3<f16>, 2> = sb_load_35(768u);
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, SB_BasicLoad_OutOfOrder) {
- auto* src = R"(
-enable f16;
-
-@compute @workgroup_size(1)
-fn main() {
- var scalar_f32 : f32 = sb.scalar_f32;
- var scalar_i32 : i32 = sb.scalar_i32;
- var scalar_u32 : u32 = sb.scalar_u32;
- var scalar_f16 : f16 = sb.scalar_f16;
- var vec2_f32 : vec2<f32> = sb.vec2_f32;
- var vec2_i32 : vec2<i32> = sb.vec2_i32;
- var vec2_u32 : vec2<u32> = sb.vec2_u32;
- var vec2_f16 : vec2<f16> = sb.vec2_f16;
- var vec3_f32 : vec3<f32> = sb.vec3_f32;
- var vec3_i32 : vec3<i32> = sb.vec3_i32;
- var vec3_u32 : vec3<u32> = sb.vec3_u32;
- var vec3_f16 : vec3<f16> = sb.vec3_f16;
- var vec4_f32 : vec4<f32> = sb.vec4_f32;
- var vec4_i32 : vec4<i32> = sb.vec4_i32;
- var vec4_u32 : vec4<u32> = sb.vec4_u32;
- var vec4_f16 : vec4<f16> = sb.vec4_f16;
- var mat2x2_f32 : mat2x2<f32> = sb.mat2x2_f32;
- var mat2x3_f32 : mat2x3<f32> = sb.mat2x3_f32;
- var mat2x4_f32 : mat2x4<f32> = sb.mat2x4_f32;
- var mat3x2_f32 : mat3x2<f32> = sb.mat3x2_f32;
- var mat3x3_f32 : mat3x3<f32> = sb.mat3x3_f32;
- var mat3x4_f32 : mat3x4<f32> = sb.mat3x4_f32;
- var mat4x2_f32 : mat4x2<f32> = sb.mat4x2_f32;
- var mat4x3_f32 : mat4x3<f32> = sb.mat4x3_f32;
- var mat4x4_f32 : mat4x4<f32> = sb.mat4x4_f32;
- var mat2x2_f16 : mat2x2<f16> = sb.mat2x2_f16;
- var mat2x3_f16 : mat2x3<f16> = sb.mat2x3_f16;
- var mat2x4_f16 : mat2x4<f16> = sb.mat2x4_f16;
- var mat3x2_f16 : mat3x2<f16> = sb.mat3x2_f16;
- var mat3x3_f16 : mat3x3<f16> = sb.mat3x3_f16;
- var mat3x4_f16 : mat3x4<f16> = sb.mat3x4_f16;
- var mat4x2_f16 : mat4x2<f16> = sb.mat4x2_f16;
- var mat4x3_f16 : mat4x3<f16> = sb.mat4x3_f16;
- var mat4x4_f16 : mat4x4<f16> = sb.mat4x4_f16;
- var arr2_vec3_f32 : array<vec3<f32>, 2> = sb.arr2_vec3_f32;
- var arr2_vec3_f16 : array<vec3<f16>, 2> = sb.arr2_vec3_f16;
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_vec3_f16 : array<vec3<f16>, 2>,
-};
-)";
-
- auto* expect = R"(
-enable f16;
-
-@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load(offset : u32) -> f32
-
-@internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_1(offset : u32) -> i32
-
-@internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_2(offset : u32) -> u32
-
-@internal(intrinsic_load_storage_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_3(offset : u32) -> f16
-
-@internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_4(offset : u32) -> vec2<f32>
-
-@internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_5(offset : u32) -> vec2<i32>
-
-@internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_6(offset : u32) -> vec2<u32>
-
-@internal(intrinsic_load_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_7(offset : u32) -> vec2<f16>
-
-@internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_8(offset : u32) -> vec3<f32>
-
-@internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_9(offset : u32) -> vec3<i32>
-
-@internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_10(offset : u32) -> vec3<u32>
-
-@internal(intrinsic_load_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_11(offset : u32) -> vec3<f16>
-
-@internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_12(offset : u32) -> vec4<f32>
-
-@internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_13(offset : u32) -> vec4<i32>
-
-@internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_14(offset : u32) -> vec4<u32>
-
-@internal(intrinsic_load_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_15(offset : u32) -> vec4<f16>
-
-fn sb_load_16(offset : u32) -> mat2x2<f32> {
- return mat2x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)));
-}
-
-fn sb_load_17(offset : u32) -> mat2x3<f32> {
- return mat2x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)));
-}
-
-fn sb_load_18(offset : u32) -> mat2x4<f32> {
- return mat2x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)));
-}
-
-fn sb_load_19(offset : u32) -> mat3x2<f32> {
- return mat3x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)), sb_load_4((offset + 16u)));
-}
-
-fn sb_load_20(offset : u32) -> mat3x3<f32> {
- return mat3x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)), sb_load_8((offset + 32u)));
-}
-
-fn sb_load_21(offset : u32) -> mat3x4<f32> {
- return mat3x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)), sb_load_12((offset + 32u)));
-}
-
-fn sb_load_22(offset : u32) -> mat4x2<f32> {
- return mat4x2<f32>(sb_load_4((offset + 0u)), sb_load_4((offset + 8u)), sb_load_4((offset + 16u)), sb_load_4((offset + 24u)));
-}
-
-fn sb_load_23(offset : u32) -> mat4x3<f32> {
- return mat4x3<f32>(sb_load_8((offset + 0u)), sb_load_8((offset + 16u)), sb_load_8((offset + 32u)), sb_load_8((offset + 48u)));
-}
-
-fn sb_load_24(offset : u32) -> mat4x4<f32> {
- return mat4x4<f32>(sb_load_12((offset + 0u)), sb_load_12((offset + 16u)), sb_load_12((offset + 32u)), sb_load_12((offset + 48u)));
-}
-
-fn sb_load_25(offset : u32) -> mat2x2<f16> {
- return mat2x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)));
-}
-
-fn sb_load_26(offset : u32) -> mat2x3<f16> {
- return mat2x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)));
-}
-
-fn sb_load_27(offset : u32) -> mat2x4<f16> {
- return mat2x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)));
-}
-
-fn sb_load_28(offset : u32) -> mat3x2<f16> {
- return mat3x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)), sb_load_7((offset + 8u)));
-}
-
-fn sb_load_29(offset : u32) -> mat3x3<f16> {
- return mat3x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)), sb_load_11((offset + 16u)));
-}
-
-fn sb_load_30(offset : u32) -> mat3x4<f16> {
- return mat3x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)), sb_load_15((offset + 16u)));
-}
-
-fn sb_load_31(offset : u32) -> mat4x2<f16> {
- return mat4x2<f16>(sb_load_7((offset + 0u)), sb_load_7((offset + 4u)), sb_load_7((offset + 8u)), sb_load_7((offset + 12u)));
-}
-
-fn sb_load_32(offset : u32) -> mat4x3<f16> {
- return mat4x3<f16>(sb_load_11((offset + 0u)), sb_load_11((offset + 8u)), sb_load_11((offset + 16u)), sb_load_11((offset + 24u)));
-}
-
-fn sb_load_33(offset : u32) -> mat4x4<f16> {
- return mat4x4<f16>(sb_load_15((offset + 0u)), sb_load_15((offset + 8u)), sb_load_15((offset + 16u)), sb_load_15((offset + 24u)));
-}
-
-fn sb_load_34(offset : u32) -> array<vec3<f32>, 2u> {
- var arr : array<vec3<f32>, 2u>;
- for(var i = 0u; (i < 2u); i = (i + 1u)) {
- arr[i] = sb_load_8((offset + (i * 16u)));
- }
- return arr;
-}
-
-fn sb_load_35(offset : u32) -> array<vec3<f16>, 2u> {
- var arr_1 : array<vec3<f16>, 2u>;
- for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
- arr_1[i_1] = sb_load_11((offset + (i_1 * 8u)));
- }
- return arr_1;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var scalar_f32 : f32 = sb_load(0u);
- var scalar_i32 : i32 = sb_load_1(4u);
- var scalar_u32 : u32 = sb_load_2(8u);
- var scalar_f16 : f16 = sb_load_3(12u);
- var vec2_f32 : vec2<f32> = sb_load_4(16u);
- var vec2_i32 : vec2<i32> = sb_load_5(24u);
- var vec2_u32 : vec2<u32> = sb_load_6(32u);
- var vec2_f16 : vec2<f16> = sb_load_7(40u);
- var vec3_f32 : vec3<f32> = sb_load_8(48u);
- var vec3_i32 : vec3<i32> = sb_load_9(64u);
- var vec3_u32 : vec3<u32> = sb_load_10(80u);
- var vec3_f16 : vec3<f16> = sb_load_11(96u);
- var vec4_f32 : vec4<f32> = sb_load_12(112u);
- var vec4_i32 : vec4<i32> = sb_load_13(128u);
- var vec4_u32 : vec4<u32> = sb_load_14(144u);
- var vec4_f16 : vec4<f16> = sb_load_15(160u);
- var mat2x2_f32 : mat2x2<f32> = sb_load_16(168u);
- var mat2x3_f32 : mat2x3<f32> = sb_load_17(192u);
- var mat2x4_f32 : mat2x4<f32> = sb_load_18(224u);
- var mat3x2_f32 : mat3x2<f32> = sb_load_19(256u);
- var mat3x3_f32 : mat3x3<f32> = sb_load_20(288u);
- var mat3x4_f32 : mat3x4<f32> = sb_load_21(336u);
- var mat4x2_f32 : mat4x2<f32> = sb_load_22(384u);
- var mat4x3_f32 : mat4x3<f32> = sb_load_23(416u);
- var mat4x4_f32 : mat4x4<f32> = sb_load_24(480u);
- var mat2x2_f16 : mat2x2<f16> = sb_load_25(544u);
- var mat2x3_f16 : mat2x3<f16> = sb_load_26(552u);
- var mat2x4_f16 : mat2x4<f16> = sb_load_27(568u);
- var mat3x2_f16 : mat3x2<f16> = sb_load_28(584u);
- var mat3x3_f16 : mat3x3<f16> = sb_load_29(600u);
- var mat3x4_f16 : mat3x4<f16> = sb_load_30(624u);
- var mat4x2_f16 : mat4x2<f16> = sb_load_31(648u);
- var mat4x3_f16 : mat4x3<f16> = sb_load_32(664u);
- var mat4x4_f16 : mat4x4<f16> = sb_load_33(696u);
- var arr2_vec3_f32 : array<vec3<f32>, 2> = sb_load_34(736u);
- var arr2_vec3_f16 : array<vec3<f16>, 2> = sb_load_35(768u);
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_vec3_f16 : array<vec3<f16>, 2>,
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, UB_BasicLoad) {
- auto* src = R"(
-enable f16;
-
-struct UB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-};
-
-@group(0) @binding(0) var<uniform> ub : UB;
-
-@compute @workgroup_size(1)
-fn main() {
- var scalar_f32 : f32 = ub.scalar_f32;
- var scalar_i32 : i32 = ub.scalar_i32;
- var scalar_u32 : u32 = ub.scalar_u32;
- var scalar_f16 : f16 = ub.scalar_f16;
- var vec2_f32 : vec2<f32> = ub.vec2_f32;
- var vec2_i32 : vec2<i32> = ub.vec2_i32;
- var vec2_u32 : vec2<u32> = ub.vec2_u32;
- var vec2_f16 : vec2<f16> = ub.vec2_f16;
- var vec3_f32 : vec3<f32> = ub.vec3_f32;
- var vec3_i32 : vec3<i32> = ub.vec3_i32;
- var vec3_u32 : vec3<u32> = ub.vec3_u32;
- var vec3_f16 : vec3<f16> = ub.vec3_f16;
- var vec4_f32 : vec4<f32> = ub.vec4_f32;
- var vec4_i32 : vec4<i32> = ub.vec4_i32;
- var vec4_u32 : vec4<u32> = ub.vec4_u32;
- var vec4_f16 : vec4<f16> = ub.vec4_f16;
- var mat2x2_f32 : mat2x2<f32> = ub.mat2x2_f32;
- var mat2x3_f32 : mat2x3<f32> = ub.mat2x3_f32;
- var mat2x4_f32 : mat2x4<f32> = ub.mat2x4_f32;
- var mat3x2_f32 : mat3x2<f32> = ub.mat3x2_f32;
- var mat3x3_f32 : mat3x3<f32> = ub.mat3x3_f32;
- var mat3x4_f32 : mat3x4<f32> = ub.mat3x4_f32;
- var mat4x2_f32 : mat4x2<f32> = ub.mat4x2_f32;
- var mat4x3_f32 : mat4x3<f32> = ub.mat4x3_f32;
- var mat4x4_f32 : mat4x4<f32> = ub.mat4x4_f32;
- var mat2x2_f16 : mat2x2<f16> = ub.mat2x2_f16;
- var mat2x3_f16 : mat2x3<f16> = ub.mat2x3_f16;
- var mat2x4_f16 : mat2x4<f16> = ub.mat2x4_f16;
- var mat3x2_f16 : mat3x2<f16> = ub.mat3x2_f16;
- var mat3x3_f16 : mat3x3<f16> = ub.mat3x3_f16;
- var mat3x4_f16 : mat3x4<f16> = ub.mat3x4_f16;
- var mat4x2_f16 : mat4x2<f16> = ub.mat4x2_f16;
- var mat4x3_f16 : mat4x3<f16> = ub.mat4x3_f16;
- var mat4x4_f16 : mat4x4<f16> = ub.mat4x4_f16;
- var arr2_vec3_f32 : array<vec3<f32>, 2> = ub.arr2_vec3_f32;
- var arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = ub.arr2_mat4x2_f16;
-}
-)";
-
- auto* expect = R"(
-enable f16;
-
-struct UB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-}
-
-@group(0) @binding(0) var<uniform> ub : UB;
-
-@internal(intrinsic_load_uniform_f32) @internal(disable_validation__function_has_no_body)
-fn ub_load(offset : u32) -> f32
-
-@internal(intrinsic_load_uniform_i32) @internal(disable_validation__function_has_no_body)
-fn ub_load_1(offset : u32) -> i32
-
-@internal(intrinsic_load_uniform_u32) @internal(disable_validation__function_has_no_body)
-fn ub_load_2(offset : u32) -> u32
-
-@internal(intrinsic_load_uniform_f16) @internal(disable_validation__function_has_no_body)
-fn ub_load_3(offset : u32) -> f16
-
-@internal(intrinsic_load_uniform_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn ub_load_4(offset : u32) -> vec2<f32>
-
-@internal(intrinsic_load_uniform_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn ub_load_5(offset : u32) -> vec2<i32>
-
-@internal(intrinsic_load_uniform_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn ub_load_6(offset : u32) -> vec2<u32>
-
-@internal(intrinsic_load_uniform_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn ub_load_7(offset : u32) -> vec2<f16>
-
-@internal(intrinsic_load_uniform_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn ub_load_8(offset : u32) -> vec3<f32>
-
-@internal(intrinsic_load_uniform_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn ub_load_9(offset : u32) -> vec3<i32>
-
-@internal(intrinsic_load_uniform_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn ub_load_10(offset : u32) -> vec3<u32>
-
-@internal(intrinsic_load_uniform_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn ub_load_11(offset : u32) -> vec3<f16>
-
-@internal(intrinsic_load_uniform_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn ub_load_12(offset : u32) -> vec4<f32>
-
-@internal(intrinsic_load_uniform_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn ub_load_13(offset : u32) -> vec4<i32>
-
-@internal(intrinsic_load_uniform_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn ub_load_14(offset : u32) -> vec4<u32>
-
-@internal(intrinsic_load_uniform_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn ub_load_15(offset : u32) -> vec4<f16>
-
-fn ub_load_16(offset : u32) -> mat2x2<f32> {
- return mat2x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)));
-}
-
-fn ub_load_17(offset : u32) -> mat2x3<f32> {
- return mat2x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)));
-}
-
-fn ub_load_18(offset : u32) -> mat2x4<f32> {
- return mat2x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)));
-}
-
-fn ub_load_19(offset : u32) -> mat3x2<f32> {
- return mat3x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)), ub_load_4((offset + 16u)));
-}
-
-fn ub_load_20(offset : u32) -> mat3x3<f32> {
- return mat3x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)), ub_load_8((offset + 32u)));
-}
-
-fn ub_load_21(offset : u32) -> mat3x4<f32> {
- return mat3x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)), ub_load_12((offset + 32u)));
-}
-
-fn ub_load_22(offset : u32) -> mat4x2<f32> {
- return mat4x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)), ub_load_4((offset + 16u)), ub_load_4((offset + 24u)));
-}
-
-fn ub_load_23(offset : u32) -> mat4x3<f32> {
- return mat4x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)), ub_load_8((offset + 32u)), ub_load_8((offset + 48u)));
-}
-
-fn ub_load_24(offset : u32) -> mat4x4<f32> {
- return mat4x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)), ub_load_12((offset + 32u)), ub_load_12((offset + 48u)));
-}
-
-fn ub_load_25(offset : u32) -> mat2x2<f16> {
- return mat2x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)));
-}
-
-fn ub_load_26(offset : u32) -> mat2x3<f16> {
- return mat2x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)));
-}
-
-fn ub_load_27(offset : u32) -> mat2x4<f16> {
- return mat2x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)));
-}
-
-fn ub_load_28(offset : u32) -> mat3x2<f16> {
- return mat3x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)), ub_load_7((offset + 8u)));
-}
-
-fn ub_load_29(offset : u32) -> mat3x3<f16> {
- return mat3x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)), ub_load_11((offset + 16u)));
-}
-
-fn ub_load_30(offset : u32) -> mat3x4<f16> {
- return mat3x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)), ub_load_15((offset + 16u)));
-}
-
-fn ub_load_31(offset : u32) -> mat4x2<f16> {
- return mat4x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)), ub_load_7((offset + 8u)), ub_load_7((offset + 12u)));
-}
-
-fn ub_load_32(offset : u32) -> mat4x3<f16> {
- return mat4x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)), ub_load_11((offset + 16u)), ub_load_11((offset + 24u)));
-}
-
-fn ub_load_33(offset : u32) -> mat4x4<f16> {
- return mat4x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)), ub_load_15((offset + 16u)), ub_load_15((offset + 24u)));
-}
-
-fn ub_load_34(offset : u32) -> array<vec3<f32>, 2u> {
- var arr : array<vec3<f32>, 2u>;
- for(var i = 0u; (i < 2u); i = (i + 1u)) {
- arr[i] = ub_load_8((offset + (i * 16u)));
- }
- return arr;
-}
-
-fn ub_load_35(offset : u32) -> array<mat4x2<f16>, 2u> {
- var arr_1 : array<mat4x2<f16>, 2u>;
- for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
- arr_1[i_1] = ub_load_31((offset + (i_1 * 16u)));
- }
- return arr_1;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var scalar_f32 : f32 = ub_load(0u);
- var scalar_i32 : i32 = ub_load_1(4u);
- var scalar_u32 : u32 = ub_load_2(8u);
- var scalar_f16 : f16 = ub_load_3(12u);
- var vec2_f32 : vec2<f32> = ub_load_4(16u);
- var vec2_i32 : vec2<i32> = ub_load_5(24u);
- var vec2_u32 : vec2<u32> = ub_load_6(32u);
- var vec2_f16 : vec2<f16> = ub_load_7(40u);
- var vec3_f32 : vec3<f32> = ub_load_8(48u);
- var vec3_i32 : vec3<i32> = ub_load_9(64u);
- var vec3_u32 : vec3<u32> = ub_load_10(80u);
- var vec3_f16 : vec3<f16> = ub_load_11(96u);
- var vec4_f32 : vec4<f32> = ub_load_12(112u);
- var vec4_i32 : vec4<i32> = ub_load_13(128u);
- var vec4_u32 : vec4<u32> = ub_load_14(144u);
- var vec4_f16 : vec4<f16> = ub_load_15(160u);
- var mat2x2_f32 : mat2x2<f32> = ub_load_16(168u);
- var mat2x3_f32 : mat2x3<f32> = ub_load_17(192u);
- var mat2x4_f32 : mat2x4<f32> = ub_load_18(224u);
- var mat3x2_f32 : mat3x2<f32> = ub_load_19(256u);
- var mat3x3_f32 : mat3x3<f32> = ub_load_20(288u);
- var mat3x4_f32 : mat3x4<f32> = ub_load_21(336u);
- var mat4x2_f32 : mat4x2<f32> = ub_load_22(384u);
- var mat4x3_f32 : mat4x3<f32> = ub_load_23(416u);
- var mat4x4_f32 : mat4x4<f32> = ub_load_24(480u);
- var mat2x2_f16 : mat2x2<f16> = ub_load_25(544u);
- var mat2x3_f16 : mat2x3<f16> = ub_load_26(552u);
- var mat2x4_f16 : mat2x4<f16> = ub_load_27(568u);
- var mat3x2_f16 : mat3x2<f16> = ub_load_28(584u);
- var mat3x3_f16 : mat3x3<f16> = ub_load_29(600u);
- var mat3x4_f16 : mat3x4<f16> = ub_load_30(624u);
- var mat4x2_f16 : mat4x2<f16> = ub_load_31(648u);
- var mat4x3_f16 : mat4x3<f16> = ub_load_32(664u);
- var mat4x4_f16 : mat4x4<f16> = ub_load_33(696u);
- var arr2_vec3_f32 : array<vec3<f32>, 2> = ub_load_34(736u);
- var arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = ub_load_35(768u);
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, UB_BasicLoad_OutOfOrder) {
- auto* src = R"(
-enable f16;
-
-@compute @workgroup_size(1)
-fn main() {
- var scalar_f32 : f32 = ub.scalar_f32;
- var scalar_i32 : i32 = ub.scalar_i32;
- var scalar_u32 : u32 = ub.scalar_u32;
- var scalar_f16 : f16 = ub.scalar_f16;
- var vec2_f32 : vec2<f32> = ub.vec2_f32;
- var vec2_i32 : vec2<i32> = ub.vec2_i32;
- var vec2_u32 : vec2<u32> = ub.vec2_u32;
- var vec2_f16 : vec2<f16> = ub.vec2_f16;
- var vec3_f32 : vec3<f32> = ub.vec3_f32;
- var vec3_i32 : vec3<i32> = ub.vec3_i32;
- var vec3_u32 : vec3<u32> = ub.vec3_u32;
- var vec3_f16 : vec3<f16> = ub.vec3_f16;
- var vec4_f32 : vec4<f32> = ub.vec4_f32;
- var vec4_i32 : vec4<i32> = ub.vec4_i32;
- var vec4_u32 : vec4<u32> = ub.vec4_u32;
- var vec4_f16 : vec4<f16> = ub.vec4_f16;
- var mat2x2_f32 : mat2x2<f32> = ub.mat2x2_f32;
- var mat2x3_f32 : mat2x3<f32> = ub.mat2x3_f32;
- var mat2x4_f32 : mat2x4<f32> = ub.mat2x4_f32;
- var mat3x2_f32 : mat3x2<f32> = ub.mat3x2_f32;
- var mat3x3_f32 : mat3x3<f32> = ub.mat3x3_f32;
- var mat3x4_f32 : mat3x4<f32> = ub.mat3x4_f32;
- var mat4x2_f32 : mat4x2<f32> = ub.mat4x2_f32;
- var mat4x3_f32 : mat4x3<f32> = ub.mat4x3_f32;
- var mat4x4_f32 : mat4x4<f32> = ub.mat4x4_f32;
- var mat2x2_f16 : mat2x2<f16> = ub.mat2x2_f16;
- var mat2x3_f16 : mat2x3<f16> = ub.mat2x3_f16;
- var mat2x4_f16 : mat2x4<f16> = ub.mat2x4_f16;
- var mat3x2_f16 : mat3x2<f16> = ub.mat3x2_f16;
- var mat3x3_f16 : mat3x3<f16> = ub.mat3x3_f16;
- var mat3x4_f16 : mat3x4<f16> = ub.mat3x4_f16;
- var mat4x2_f16 : mat4x2<f16> = ub.mat4x2_f16;
- var mat4x3_f16 : mat4x3<f16> = ub.mat4x3_f16;
- var mat4x4_f16 : mat4x4<f16> = ub.mat4x4_f16;
- var arr2_vec3_f32 : array<vec3<f32>, 2> = ub.arr2_vec3_f32;
- var arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = ub.arr2_mat4x2_f16;
-}
-
-@group(0) @binding(0) var<uniform> ub : UB;
-
-struct UB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-};
-)";
-
- auto* expect = R"(
-enable f16;
-
-@internal(intrinsic_load_uniform_f32) @internal(disable_validation__function_has_no_body)
-fn ub_load(offset : u32) -> f32
-
-@internal(intrinsic_load_uniform_i32) @internal(disable_validation__function_has_no_body)
-fn ub_load_1(offset : u32) -> i32
-
-@internal(intrinsic_load_uniform_u32) @internal(disable_validation__function_has_no_body)
-fn ub_load_2(offset : u32) -> u32
-
-@internal(intrinsic_load_uniform_f16) @internal(disable_validation__function_has_no_body)
-fn ub_load_3(offset : u32) -> f16
-
-@internal(intrinsic_load_uniform_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn ub_load_4(offset : u32) -> vec2<f32>
-
-@internal(intrinsic_load_uniform_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn ub_load_5(offset : u32) -> vec2<i32>
-
-@internal(intrinsic_load_uniform_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn ub_load_6(offset : u32) -> vec2<u32>
-
-@internal(intrinsic_load_uniform_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn ub_load_7(offset : u32) -> vec2<f16>
-
-@internal(intrinsic_load_uniform_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn ub_load_8(offset : u32) -> vec3<f32>
-
-@internal(intrinsic_load_uniform_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn ub_load_9(offset : u32) -> vec3<i32>
-
-@internal(intrinsic_load_uniform_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn ub_load_10(offset : u32) -> vec3<u32>
-
-@internal(intrinsic_load_uniform_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn ub_load_11(offset : u32) -> vec3<f16>
-
-@internal(intrinsic_load_uniform_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn ub_load_12(offset : u32) -> vec4<f32>
-
-@internal(intrinsic_load_uniform_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn ub_load_13(offset : u32) -> vec4<i32>
-
-@internal(intrinsic_load_uniform_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn ub_load_14(offset : u32) -> vec4<u32>
-
-@internal(intrinsic_load_uniform_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn ub_load_15(offset : u32) -> vec4<f16>
-
-fn ub_load_16(offset : u32) -> mat2x2<f32> {
- return mat2x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)));
-}
-
-fn ub_load_17(offset : u32) -> mat2x3<f32> {
- return mat2x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)));
-}
-
-fn ub_load_18(offset : u32) -> mat2x4<f32> {
- return mat2x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)));
-}
-
-fn ub_load_19(offset : u32) -> mat3x2<f32> {
- return mat3x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)), ub_load_4((offset + 16u)));
-}
-
-fn ub_load_20(offset : u32) -> mat3x3<f32> {
- return mat3x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)), ub_load_8((offset + 32u)));
-}
-
-fn ub_load_21(offset : u32) -> mat3x4<f32> {
- return mat3x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)), ub_load_12((offset + 32u)));
-}
-
-fn ub_load_22(offset : u32) -> mat4x2<f32> {
- return mat4x2<f32>(ub_load_4((offset + 0u)), ub_load_4((offset + 8u)), ub_load_4((offset + 16u)), ub_load_4((offset + 24u)));
-}
-
-fn ub_load_23(offset : u32) -> mat4x3<f32> {
- return mat4x3<f32>(ub_load_8((offset + 0u)), ub_load_8((offset + 16u)), ub_load_8((offset + 32u)), ub_load_8((offset + 48u)));
-}
-
-fn ub_load_24(offset : u32) -> mat4x4<f32> {
- return mat4x4<f32>(ub_load_12((offset + 0u)), ub_load_12((offset + 16u)), ub_load_12((offset + 32u)), ub_load_12((offset + 48u)));
-}
-
-fn ub_load_25(offset : u32) -> mat2x2<f16> {
- return mat2x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)));
-}
-
-fn ub_load_26(offset : u32) -> mat2x3<f16> {
- return mat2x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)));
-}
-
-fn ub_load_27(offset : u32) -> mat2x4<f16> {
- return mat2x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)));
-}
-
-fn ub_load_28(offset : u32) -> mat3x2<f16> {
- return mat3x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)), ub_load_7((offset + 8u)));
-}
-
-fn ub_load_29(offset : u32) -> mat3x3<f16> {
- return mat3x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)), ub_load_11((offset + 16u)));
-}
-
-fn ub_load_30(offset : u32) -> mat3x4<f16> {
- return mat3x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)), ub_load_15((offset + 16u)));
-}
-
-fn ub_load_31(offset : u32) -> mat4x2<f16> {
- return mat4x2<f16>(ub_load_7((offset + 0u)), ub_load_7((offset + 4u)), ub_load_7((offset + 8u)), ub_load_7((offset + 12u)));
-}
-
-fn ub_load_32(offset : u32) -> mat4x3<f16> {
- return mat4x3<f16>(ub_load_11((offset + 0u)), ub_load_11((offset + 8u)), ub_load_11((offset + 16u)), ub_load_11((offset + 24u)));
-}
-
-fn ub_load_33(offset : u32) -> mat4x4<f16> {
- return mat4x4<f16>(ub_load_15((offset + 0u)), ub_load_15((offset + 8u)), ub_load_15((offset + 16u)), ub_load_15((offset + 24u)));
-}
-
-fn ub_load_34(offset : u32) -> array<vec3<f32>, 2u> {
- var arr : array<vec3<f32>, 2u>;
- for(var i = 0u; (i < 2u); i = (i + 1u)) {
- arr[i] = ub_load_8((offset + (i * 16u)));
- }
- return arr;
-}
-
-fn ub_load_35(offset : u32) -> array<mat4x2<f16>, 2u> {
- var arr_1 : array<mat4x2<f16>, 2u>;
- for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
- arr_1[i_1] = ub_load_31((offset + (i_1 * 16u)));
- }
- return arr_1;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var scalar_f32 : f32 = ub_load(0u);
- var scalar_i32 : i32 = ub_load_1(4u);
- var scalar_u32 : u32 = ub_load_2(8u);
- var scalar_f16 : f16 = ub_load_3(12u);
- var vec2_f32 : vec2<f32> = ub_load_4(16u);
- var vec2_i32 : vec2<i32> = ub_load_5(24u);
- var vec2_u32 : vec2<u32> = ub_load_6(32u);
- var vec2_f16 : vec2<f16> = ub_load_7(40u);
- var vec3_f32 : vec3<f32> = ub_load_8(48u);
- var vec3_i32 : vec3<i32> = ub_load_9(64u);
- var vec3_u32 : vec3<u32> = ub_load_10(80u);
- var vec3_f16 : vec3<f16> = ub_load_11(96u);
- var vec4_f32 : vec4<f32> = ub_load_12(112u);
- var vec4_i32 : vec4<i32> = ub_load_13(128u);
- var vec4_u32 : vec4<u32> = ub_load_14(144u);
- var vec4_f16 : vec4<f16> = ub_load_15(160u);
- var mat2x2_f32 : mat2x2<f32> = ub_load_16(168u);
- var mat2x3_f32 : mat2x3<f32> = ub_load_17(192u);
- var mat2x4_f32 : mat2x4<f32> = ub_load_18(224u);
- var mat3x2_f32 : mat3x2<f32> = ub_load_19(256u);
- var mat3x3_f32 : mat3x3<f32> = ub_load_20(288u);
- var mat3x4_f32 : mat3x4<f32> = ub_load_21(336u);
- var mat4x2_f32 : mat4x2<f32> = ub_load_22(384u);
- var mat4x3_f32 : mat4x3<f32> = ub_load_23(416u);
- var mat4x4_f32 : mat4x4<f32> = ub_load_24(480u);
- var mat2x2_f16 : mat2x2<f16> = ub_load_25(544u);
- var mat2x3_f16 : mat2x3<f16> = ub_load_26(552u);
- var mat2x4_f16 : mat2x4<f16> = ub_load_27(568u);
- var mat3x2_f16 : mat3x2<f16> = ub_load_28(584u);
- var mat3x3_f16 : mat3x3<f16> = ub_load_29(600u);
- var mat3x4_f16 : mat3x4<f16> = ub_load_30(624u);
- var mat4x2_f16 : mat4x2<f16> = ub_load_31(648u);
- var mat4x3_f16 : mat4x3<f16> = ub_load_32(664u);
- var mat4x4_f16 : mat4x4<f16> = ub_load_33(696u);
- var arr2_vec3_f32 : array<vec3<f32>, 2> = ub_load_34(736u);
- var arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = ub_load_35(768u);
-}
-
-@group(0) @binding(0) var<uniform> ub : UB;
-
-struct UB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, SB_BasicStore) {
- auto* src = R"(
-enable f16;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-};
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- sb.scalar_f32 = f32();
- sb.scalar_i32 = i32();
- sb.scalar_u32 = u32();
- sb.scalar_f16 = f16();
- sb.vec2_f32 = vec2<f32>();
- sb.vec2_i32 = vec2<i32>();
- sb.vec2_u32 = vec2<u32>();
- sb.vec2_f16 = vec2<f16>();
- sb.vec3_f32 = vec3<f32>();
- sb.vec3_i32 = vec3<i32>();
- sb.vec3_u32 = vec3<u32>();
- sb.vec3_f16 = vec3<f16>();
- sb.vec4_f32 = vec4<f32>();
- sb.vec4_i32 = vec4<i32>();
- sb.vec4_u32 = vec4<u32>();
- sb.vec4_f16 = vec4<f16>();
- sb.mat2x2_f32 = mat2x2<f32>();
- sb.mat2x3_f32 = mat2x3<f32>();
- sb.mat2x4_f32 = mat2x4<f32>();
- sb.mat3x2_f32 = mat3x2<f32>();
- sb.mat3x3_f32 = mat3x3<f32>();
- sb.mat3x4_f32 = mat3x4<f32>();
- sb.mat4x2_f32 = mat4x2<f32>();
- sb.mat4x3_f32 = mat4x3<f32>();
- sb.mat4x4_f32 = mat4x4<f32>();
- sb.mat2x2_f16 = mat2x2<f16>();
- sb.mat2x3_f16 = mat2x3<f16>();
- sb.mat2x4_f16 = mat2x4<f16>();
- sb.mat3x2_f16 = mat3x2<f16>();
- sb.mat3x3_f16 = mat3x3<f16>();
- sb.mat3x4_f16 = mat3x4<f16>();
- sb.mat4x2_f16 = mat4x2<f16>();
- sb.mat4x3_f16 = mat4x3<f16>();
- sb.mat4x4_f16 = mat4x4<f16>();
- sb.arr2_vec3_f32 = array<vec3<f32>, 2>();
- sb.arr2_mat4x2_f16 = array<mat4x2<f16>, 2>();
-}
-)";
-
- auto* expect = R"(
-enable f16;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store(offset : u32, value : f32)
-
-@internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_1(offset : u32, value : i32)
-
-@internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_2(offset : u32, value : u32)
-
-@internal(intrinsic_store_storage_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_3(offset : u32, value : f16)
-
-@internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_4(offset : u32, value : vec2<f32>)
-
-@internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_5(offset : u32, value : vec2<i32>)
-
-@internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_6(offset : u32, value : vec2<u32>)
-
-@internal(intrinsic_store_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_7(offset : u32, value : vec2<f16>)
-
-@internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_8(offset : u32, value : vec3<f32>)
-
-@internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_9(offset : u32, value : vec3<i32>)
-
-@internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_10(offset : u32, value : vec3<u32>)
-
-@internal(intrinsic_store_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_11(offset : u32, value : vec3<f16>)
-
-@internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_12(offset : u32, value : vec4<f32>)
-
-@internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_13(offset : u32, value : vec4<i32>)
-
-@internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_14(offset : u32, value : vec4<u32>)
-
-@internal(intrinsic_store_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_15(offset : u32, value : vec4<f16>)
-
-fn sb_store_16(offset : u32, value : mat2x2<f32>) {
- sb_store_4((offset + 0u), value[0u]);
- sb_store_4((offset + 8u), value[1u]);
-}
-
-fn sb_store_17(offset : u32, value : mat2x3<f32>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 16u), value[1u]);
-}
-
-fn sb_store_18(offset : u32, value : mat2x4<f32>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 16u), value[1u]);
-}
-
-fn sb_store_19(offset : u32, value : mat3x2<f32>) {
- sb_store_4((offset + 0u), value[0u]);
- sb_store_4((offset + 8u), value[1u]);
- sb_store_4((offset + 16u), value[2u]);
-}
-
-fn sb_store_20(offset : u32, value : mat3x3<f32>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 16u), value[1u]);
- sb_store_8((offset + 32u), value[2u]);
-}
-
-fn sb_store_21(offset : u32, value : mat3x4<f32>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 16u), value[1u]);
- sb_store_12((offset + 32u), value[2u]);
-}
-
-fn sb_store_22(offset : u32, value : mat4x2<f32>) {
- sb_store_4((offset + 0u), value[0u]);
- sb_store_4((offset + 8u), value[1u]);
- sb_store_4((offset + 16u), value[2u]);
- sb_store_4((offset + 24u), value[3u]);
-}
-
-fn sb_store_23(offset : u32, value : mat4x3<f32>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 16u), value[1u]);
- sb_store_8((offset + 32u), value[2u]);
- sb_store_8((offset + 48u), value[3u]);
-}
-
-fn sb_store_24(offset : u32, value : mat4x4<f32>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 16u), value[1u]);
- sb_store_12((offset + 32u), value[2u]);
- sb_store_12((offset + 48u), value[3u]);
-}
-
-fn sb_store_25(offset : u32, value : mat2x2<f16>) {
- sb_store_7((offset + 0u), value[0u]);
- sb_store_7((offset + 4u), value[1u]);
-}
-
-fn sb_store_26(offset : u32, value : mat2x3<f16>) {
- sb_store_11((offset + 0u), value[0u]);
- sb_store_11((offset + 8u), value[1u]);
-}
-
-fn sb_store_27(offset : u32, value : mat2x4<f16>) {
- sb_store_15((offset + 0u), value[0u]);
- sb_store_15((offset + 8u), value[1u]);
-}
-
-fn sb_store_28(offset : u32, value : mat3x2<f16>) {
- sb_store_7((offset + 0u), value[0u]);
- sb_store_7((offset + 4u), value[1u]);
- sb_store_7((offset + 8u), value[2u]);
-}
-
-fn sb_store_29(offset : u32, value : mat3x3<f16>) {
- sb_store_11((offset + 0u), value[0u]);
- sb_store_11((offset + 8u), value[1u]);
- sb_store_11((offset + 16u), value[2u]);
-}
-
-fn sb_store_30(offset : u32, value : mat3x4<f16>) {
- sb_store_15((offset + 0u), value[0u]);
- sb_store_15((offset + 8u), value[1u]);
- sb_store_15((offset + 16u), value[2u]);
-}
-
-fn sb_store_31(offset : u32, value : mat4x2<f16>) {
- sb_store_7((offset + 0u), value[0u]);
- sb_store_7((offset + 4u), value[1u]);
- sb_store_7((offset + 8u), value[2u]);
- sb_store_7((offset + 12u), value[3u]);
-}
-
-fn sb_store_32(offset : u32, value : mat4x3<f16>) {
- sb_store_11((offset + 0u), value[0u]);
- sb_store_11((offset + 8u), value[1u]);
- sb_store_11((offset + 16u), value[2u]);
- sb_store_11((offset + 24u), value[3u]);
-}
-
-fn sb_store_33(offset : u32, value : mat4x4<f16>) {
- sb_store_15((offset + 0u), value[0u]);
- sb_store_15((offset + 8u), value[1u]);
- sb_store_15((offset + 16u), value[2u]);
- sb_store_15((offset + 24u), value[3u]);
-}
-
-fn sb_store_34(offset : u32, value : array<vec3<f32>, 2u>) {
- var array_1 = value;
- for(var i = 0u; (i < 2u); i = (i + 1u)) {
- sb_store_8((offset + (i * 16u)), array_1[i]);
- }
-}
-
-fn sb_store_35(offset : u32, value : array<mat4x2<f16>, 2u>) {
- var array_2 = value;
- for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
- sb_store_31((offset + (i_1 * 16u)), array_2[i_1]);
- }
-}
-
-@compute @workgroup_size(1)
-fn main() {
- sb_store(0u, f32());
- sb_store_1(4u, i32());
- sb_store_2(8u, u32());
- sb_store_3(12u, f16());
- sb_store_4(16u, vec2<f32>());
- sb_store_5(24u, vec2<i32>());
- sb_store_6(32u, vec2<u32>());
- sb_store_7(40u, vec2<f16>());
- sb_store_8(48u, vec3<f32>());
- sb_store_9(64u, vec3<i32>());
- sb_store_10(80u, vec3<u32>());
- sb_store_11(96u, vec3<f16>());
- sb_store_12(112u, vec4<f32>());
- sb_store_13(128u, vec4<i32>());
- sb_store_14(144u, vec4<u32>());
- sb_store_15(160u, vec4<f16>());
- sb_store_16(168u, mat2x2<f32>());
- sb_store_17(192u, mat2x3<f32>());
- sb_store_18(224u, mat2x4<f32>());
- sb_store_19(256u, mat3x2<f32>());
- sb_store_20(288u, mat3x3<f32>());
- sb_store_21(336u, mat3x4<f32>());
- sb_store_22(384u, mat4x2<f32>());
- sb_store_23(416u, mat4x3<f32>());
- sb_store_24(480u, mat4x4<f32>());
- sb_store_25(544u, mat2x2<f16>());
- sb_store_26(552u, mat2x3<f16>());
- sb_store_27(568u, mat2x4<f16>());
- sb_store_28(584u, mat3x2<f16>());
- sb_store_29(600u, mat3x3<f16>());
- sb_store_30(624u, mat3x4<f16>());
- sb_store_31(648u, mat4x2<f16>());
- sb_store_32(664u, mat4x3<f16>());
- sb_store_33(696u, mat4x4<f16>());
- sb_store_34(736u, array<vec3<f32>, 2>());
- sb_store_35(768u, array<mat4x2<f16>, 2>());
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, SB_BasicStore_OutOfOrder) {
- auto* src = R"(
-enable f16;
-
-@compute @workgroup_size(1)
-fn main() {
- sb.scalar_f32 = f32();
- sb.scalar_i32 = i32();
- sb.scalar_u32 = u32();
- sb.scalar_f16 = f16();
- sb.vec2_f32 = vec2<f32>();
- sb.vec2_i32 = vec2<i32>();
- sb.vec2_u32 = vec2<u32>();
- sb.vec2_f16 = vec2<f16>();
- sb.vec3_f32 = vec3<f32>();
- sb.vec3_i32 = vec3<i32>();
- sb.vec3_u32 = vec3<u32>();
- sb.vec3_f16 = vec3<f16>();
- sb.vec4_f32 = vec4<f32>();
- sb.vec4_i32 = vec4<i32>();
- sb.vec4_u32 = vec4<u32>();
- sb.vec4_f16 = vec4<f16>();
- sb.mat2x2_f32 = mat2x2<f32>();
- sb.mat2x3_f32 = mat2x3<f32>();
- sb.mat2x4_f32 = mat2x4<f32>();
- sb.mat3x2_f32 = mat3x2<f32>();
- sb.mat3x3_f32 = mat3x3<f32>();
- sb.mat3x4_f32 = mat3x4<f32>();
- sb.mat4x2_f32 = mat4x2<f32>();
- sb.mat4x3_f32 = mat4x3<f32>();
- sb.mat4x4_f32 = mat4x4<f32>();
- sb.mat2x2_f16 = mat2x2<f16>();
- sb.mat2x3_f16 = mat2x3<f16>();
- sb.mat2x4_f16 = mat2x4<f16>();
- sb.mat3x2_f16 = mat3x2<f16>();
- sb.mat3x3_f16 = mat3x3<f16>();
- sb.mat3x4_f16 = mat3x4<f16>();
- sb.mat4x2_f16 = mat4x2<f16>();
- sb.mat4x3_f16 = mat4x3<f16>();
- sb.mat4x4_f16 = mat4x4<f16>();
- sb.arr2_vec3_f32 = array<vec3<f32>, 2>();
- sb.arr2_mat4x2_f16 = array<mat4x2<f16>, 2>();
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-};
-)";
-
- auto* expect = R"(
-enable f16;
-
-@internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store(offset : u32, value : f32)
-
-@internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_1(offset : u32, value : i32)
-
-@internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_2(offset : u32, value : u32)
-
-@internal(intrinsic_store_storage_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_3(offset : u32, value : f16)
-
-@internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_4(offset : u32, value : vec2<f32>)
-
-@internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_5(offset : u32, value : vec2<i32>)
-
-@internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_6(offset : u32, value : vec2<u32>)
-
-@internal(intrinsic_store_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_7(offset : u32, value : vec2<f16>)
-
-@internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_8(offset : u32, value : vec3<f32>)
-
-@internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_9(offset : u32, value : vec3<i32>)
-
-@internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_10(offset : u32, value : vec3<u32>)
-
-@internal(intrinsic_store_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_11(offset : u32, value : vec3<f16>)
-
-@internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_12(offset : u32, value : vec4<f32>)
-
-@internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_13(offset : u32, value : vec4<i32>)
-
-@internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_14(offset : u32, value : vec4<u32>)
-
-@internal(intrinsic_store_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_15(offset : u32, value : vec4<f16>)
-
-fn sb_store_16(offset : u32, value : mat2x2<f32>) {
- sb_store_4((offset + 0u), value[0u]);
- sb_store_4((offset + 8u), value[1u]);
-}
-
-fn sb_store_17(offset : u32, value : mat2x3<f32>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 16u), value[1u]);
-}
-
-fn sb_store_18(offset : u32, value : mat2x4<f32>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 16u), value[1u]);
-}
-
-fn sb_store_19(offset : u32, value : mat3x2<f32>) {
- sb_store_4((offset + 0u), value[0u]);
- sb_store_4((offset + 8u), value[1u]);
- sb_store_4((offset + 16u), value[2u]);
-}
-
-fn sb_store_20(offset : u32, value : mat3x3<f32>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 16u), value[1u]);
- sb_store_8((offset + 32u), value[2u]);
-}
-
-fn sb_store_21(offset : u32, value : mat3x4<f32>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 16u), value[1u]);
- sb_store_12((offset + 32u), value[2u]);
-}
-
-fn sb_store_22(offset : u32, value : mat4x2<f32>) {
- sb_store_4((offset + 0u), value[0u]);
- sb_store_4((offset + 8u), value[1u]);
- sb_store_4((offset + 16u), value[2u]);
- sb_store_4((offset + 24u), value[3u]);
-}
-
-fn sb_store_23(offset : u32, value : mat4x3<f32>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 16u), value[1u]);
- sb_store_8((offset + 32u), value[2u]);
- sb_store_8((offset + 48u), value[3u]);
-}
-
-fn sb_store_24(offset : u32, value : mat4x4<f32>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 16u), value[1u]);
- sb_store_12((offset + 32u), value[2u]);
- sb_store_12((offset + 48u), value[3u]);
-}
-
-fn sb_store_25(offset : u32, value : mat2x2<f16>) {
- sb_store_7((offset + 0u), value[0u]);
- sb_store_7((offset + 4u), value[1u]);
-}
-
-fn sb_store_26(offset : u32, value : mat2x3<f16>) {
- sb_store_11((offset + 0u), value[0u]);
- sb_store_11((offset + 8u), value[1u]);
-}
-
-fn sb_store_27(offset : u32, value : mat2x4<f16>) {
- sb_store_15((offset + 0u), value[0u]);
- sb_store_15((offset + 8u), value[1u]);
-}
-
-fn sb_store_28(offset : u32, value : mat3x2<f16>) {
- sb_store_7((offset + 0u), value[0u]);
- sb_store_7((offset + 4u), value[1u]);
- sb_store_7((offset + 8u), value[2u]);
-}
-
-fn sb_store_29(offset : u32, value : mat3x3<f16>) {
- sb_store_11((offset + 0u), value[0u]);
- sb_store_11((offset + 8u), value[1u]);
- sb_store_11((offset + 16u), value[2u]);
-}
-
-fn sb_store_30(offset : u32, value : mat3x4<f16>) {
- sb_store_15((offset + 0u), value[0u]);
- sb_store_15((offset + 8u), value[1u]);
- sb_store_15((offset + 16u), value[2u]);
-}
-
-fn sb_store_31(offset : u32, value : mat4x2<f16>) {
- sb_store_7((offset + 0u), value[0u]);
- sb_store_7((offset + 4u), value[1u]);
- sb_store_7((offset + 8u), value[2u]);
- sb_store_7((offset + 12u), value[3u]);
-}
-
-fn sb_store_32(offset : u32, value : mat4x3<f16>) {
- sb_store_11((offset + 0u), value[0u]);
- sb_store_11((offset + 8u), value[1u]);
- sb_store_11((offset + 16u), value[2u]);
- sb_store_11((offset + 24u), value[3u]);
-}
-
-fn sb_store_33(offset : u32, value : mat4x4<f16>) {
- sb_store_15((offset + 0u), value[0u]);
- sb_store_15((offset + 8u), value[1u]);
- sb_store_15((offset + 16u), value[2u]);
- sb_store_15((offset + 24u), value[3u]);
-}
-
-fn sb_store_34(offset : u32, value : array<vec3<f32>, 2u>) {
- var array_1 = value;
- for(var i = 0u; (i < 2u); i = (i + 1u)) {
- sb_store_8((offset + (i * 16u)), array_1[i]);
- }
-}
-
-fn sb_store_35(offset : u32, value : array<mat4x2<f16>, 2u>) {
- var array_2 = value;
- for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
- sb_store_31((offset + (i_1 * 16u)), array_2[i_1]);
- }
-}
-
-@compute @workgroup_size(1)
-fn main() {
- sb_store(0u, f32());
- sb_store_1(4u, i32());
- sb_store_2(8u, u32());
- sb_store_3(12u, f16());
- sb_store_4(16u, vec2<f32>());
- sb_store_5(24u, vec2<i32>());
- sb_store_6(32u, vec2<u32>());
- sb_store_7(40u, vec2<f16>());
- sb_store_8(48u, vec3<f32>());
- sb_store_9(64u, vec3<i32>());
- sb_store_10(80u, vec3<u32>());
- sb_store_11(96u, vec3<f16>());
- sb_store_12(112u, vec4<f32>());
- sb_store_13(128u, vec4<i32>());
- sb_store_14(144u, vec4<u32>());
- sb_store_15(160u, vec4<f16>());
- sb_store_16(168u, mat2x2<f32>());
- sb_store_17(192u, mat2x3<f32>());
- sb_store_18(224u, mat2x4<f32>());
- sb_store_19(256u, mat3x2<f32>());
- sb_store_20(288u, mat3x3<f32>());
- sb_store_21(336u, mat3x4<f32>());
- sb_store_22(384u, mat4x2<f32>());
- sb_store_23(416u, mat4x3<f32>());
- sb_store_24(480u, mat4x4<f32>());
- sb_store_25(544u, mat2x2<f16>());
- sb_store_26(552u, mat2x3<f16>());
- sb_store_27(568u, mat2x4<f16>());
- sb_store_28(584u, mat3x2<f16>());
- sb_store_29(600u, mat3x3<f16>());
- sb_store_30(624u, mat3x4<f16>());
- sb_store_31(648u, mat4x2<f16>());
- sb_store_32(664u, mat4x3<f16>());
- sb_store_33(696u, mat4x4<f16>());
- sb_store_34(736u, array<vec3<f32>, 2>());
- sb_store_35(768u, array<mat4x2<f16>, 2>());
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, LoadStructure) {
- auto* src = R"(
-enable f16;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-};
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var x : SB = sb;
-}
-)";
-
- auto* expect = R"(
-enable f16;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_1(offset : u32) -> f32
-
-@internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_2(offset : u32) -> i32
-
-@internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_3(offset : u32) -> u32
-
-@internal(intrinsic_load_storage_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_4(offset : u32) -> f16
-
-@internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_5(offset : u32) -> vec2<f32>
-
-@internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_6(offset : u32) -> vec2<i32>
-
-@internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_7(offset : u32) -> vec2<u32>
-
-@internal(intrinsic_load_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_8(offset : u32) -> vec2<f16>
-
-@internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_9(offset : u32) -> vec3<f32>
-
-@internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_10(offset : u32) -> vec3<i32>
-
-@internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_11(offset : u32) -> vec3<u32>
-
-@internal(intrinsic_load_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_12(offset : u32) -> vec3<f16>
-
-@internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_13(offset : u32) -> vec4<f32>
-
-@internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_14(offset : u32) -> vec4<i32>
-
-@internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_15(offset : u32) -> vec4<u32>
-
-@internal(intrinsic_load_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_16(offset : u32) -> vec4<f16>
-
-fn sb_load_17(offset : u32) -> mat2x2<f32> {
- return mat2x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)));
-}
-
-fn sb_load_18(offset : u32) -> mat2x3<f32> {
- return mat2x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)));
-}
-
-fn sb_load_19(offset : u32) -> mat2x4<f32> {
- return mat2x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)));
-}
-
-fn sb_load_20(offset : u32) -> mat3x2<f32> {
- return mat3x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)), sb_load_5((offset + 16u)));
-}
-
-fn sb_load_21(offset : u32) -> mat3x3<f32> {
- return mat3x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)), sb_load_9((offset + 32u)));
-}
-
-fn sb_load_22(offset : u32) -> mat3x4<f32> {
- return mat3x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)), sb_load_13((offset + 32u)));
-}
-
-fn sb_load_23(offset : u32) -> mat4x2<f32> {
- return mat4x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)), sb_load_5((offset + 16u)), sb_load_5((offset + 24u)));
-}
-
-fn sb_load_24(offset : u32) -> mat4x3<f32> {
- return mat4x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)), sb_load_9((offset + 32u)), sb_load_9((offset + 48u)));
-}
-
-fn sb_load_25(offset : u32) -> mat4x4<f32> {
- return mat4x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)), sb_load_13((offset + 32u)), sb_load_13((offset + 48u)));
-}
-
-fn sb_load_26(offset : u32) -> mat2x2<f16> {
- return mat2x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)));
-}
-
-fn sb_load_27(offset : u32) -> mat2x3<f16> {
- return mat2x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)));
-}
-
-fn sb_load_28(offset : u32) -> mat2x4<f16> {
- return mat2x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)));
-}
-
-fn sb_load_29(offset : u32) -> mat3x2<f16> {
- return mat3x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)), sb_load_8((offset + 8u)));
-}
-
-fn sb_load_30(offset : u32) -> mat3x3<f16> {
- return mat3x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)), sb_load_12((offset + 16u)));
-}
-
-fn sb_load_31(offset : u32) -> mat3x4<f16> {
- return mat3x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)), sb_load_16((offset + 16u)));
-}
-
-fn sb_load_32(offset : u32) -> mat4x2<f16> {
- return mat4x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)), sb_load_8((offset + 8u)), sb_load_8((offset + 12u)));
-}
-
-fn sb_load_33(offset : u32) -> mat4x3<f16> {
- return mat4x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)), sb_load_12((offset + 16u)), sb_load_12((offset + 24u)));
-}
-
-fn sb_load_34(offset : u32) -> mat4x4<f16> {
- return mat4x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)), sb_load_16((offset + 16u)), sb_load_16((offset + 24u)));
-}
-
-fn sb_load_35(offset : u32) -> array<vec3<f32>, 2u> {
- var arr : array<vec3<f32>, 2u>;
- for(var i = 0u; (i < 2u); i = (i + 1u)) {
- arr[i] = sb_load_9((offset + (i * 16u)));
- }
- return arr;
-}
-
-fn sb_load_36(offset : u32) -> array<mat4x2<f16>, 2u> {
- var arr_1 : array<mat4x2<f16>, 2u>;
- for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
- arr_1[i_1] = sb_load_32((offset + (i_1 * 16u)));
- }
- return arr_1;
-}
-
-fn sb_load(offset : u32) -> SB {
- return SB(sb_load_1((offset + 0u)), sb_load_2((offset + 4u)), sb_load_3((offset + 8u)), sb_load_4((offset + 12u)), sb_load_5((offset + 16u)), sb_load_6((offset + 24u)), sb_load_7((offset + 32u)), sb_load_8((offset + 40u)), sb_load_9((offset + 48u)), sb_load_10((offset + 64u)), sb_load_11((offset + 80u)), sb_load_12((offset + 96u)), sb_load_13((offset + 112u)), sb_load_14((offset + 128u)), sb_load_15((offset + 144u)), sb_load_16((offset + 160u)), sb_load_17((offset + 168u)), sb_load_18((offset + 192u)), sb_load_19((offset + 224u)), sb_load_20((offset + 256u)), sb_load_21((offset + 288u)), sb_load_22((offset + 336u)), sb_load_23((offset + 384u)), sb_load_24((offset + 416u)), sb_load_25((offset + 480u)), sb_load_26((offset + 544u)), sb_load_27((offset + 552u)), sb_load_28((offset + 568u)), sb_load_29((offset + 584u)), sb_load_30((offset + 600u)), sb_load_31((offset + 624u)), sb_load_32((offset + 648u)), sb_load_33((offset + 664u)), sb_load_34((offset + 696u)), sb_load_35((offset + 736u)), sb_load_36((offset + 768u)));
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var x : SB = sb_load(0u);
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, LoadStructure_OutOfOrder) {
- auto* src = R"(
-enable f16;
-
-@compute @workgroup_size(1)
-fn main() {
- var x : SB = sb;
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-};
-)";
-
- auto* expect = R"(
-enable f16;
-
-@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_1(offset : u32) -> f32
-
-@internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_2(offset : u32) -> i32
-
-@internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_3(offset : u32) -> u32
-
-@internal(intrinsic_load_storage_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_4(offset : u32) -> f16
-
-@internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_5(offset : u32) -> vec2<f32>
-
-@internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_6(offset : u32) -> vec2<i32>
-
-@internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_7(offset : u32) -> vec2<u32>
-
-@internal(intrinsic_load_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_8(offset : u32) -> vec2<f16>
-
-@internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_9(offset : u32) -> vec3<f32>
-
-@internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_10(offset : u32) -> vec3<i32>
-
-@internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_11(offset : u32) -> vec3<u32>
-
-@internal(intrinsic_load_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_12(offset : u32) -> vec3<f16>
-
-@internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load_13(offset : u32) -> vec4<f32>
-
-@internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn sb_load_14(offset : u32) -> vec4<i32>
-
-@internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn sb_load_15(offset : u32) -> vec4<u32>
-
-@internal(intrinsic_load_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn sb_load_16(offset : u32) -> vec4<f16>
-
-fn sb_load_17(offset : u32) -> mat2x2<f32> {
- return mat2x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)));
-}
-
-fn sb_load_18(offset : u32) -> mat2x3<f32> {
- return mat2x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)));
-}
-
-fn sb_load_19(offset : u32) -> mat2x4<f32> {
- return mat2x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)));
-}
-
-fn sb_load_20(offset : u32) -> mat3x2<f32> {
- return mat3x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)), sb_load_5((offset + 16u)));
-}
-
-fn sb_load_21(offset : u32) -> mat3x3<f32> {
- return mat3x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)), sb_load_9((offset + 32u)));
-}
-
-fn sb_load_22(offset : u32) -> mat3x4<f32> {
- return mat3x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)), sb_load_13((offset + 32u)));
-}
-
-fn sb_load_23(offset : u32) -> mat4x2<f32> {
- return mat4x2<f32>(sb_load_5((offset + 0u)), sb_load_5((offset + 8u)), sb_load_5((offset + 16u)), sb_load_5((offset + 24u)));
-}
-
-fn sb_load_24(offset : u32) -> mat4x3<f32> {
- return mat4x3<f32>(sb_load_9((offset + 0u)), sb_load_9((offset + 16u)), sb_load_9((offset + 32u)), sb_load_9((offset + 48u)));
-}
-
-fn sb_load_25(offset : u32) -> mat4x4<f32> {
- return mat4x4<f32>(sb_load_13((offset + 0u)), sb_load_13((offset + 16u)), sb_load_13((offset + 32u)), sb_load_13((offset + 48u)));
-}
-
-fn sb_load_26(offset : u32) -> mat2x2<f16> {
- return mat2x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)));
-}
-
-fn sb_load_27(offset : u32) -> mat2x3<f16> {
- return mat2x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)));
-}
-
-fn sb_load_28(offset : u32) -> mat2x4<f16> {
- return mat2x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)));
-}
-
-fn sb_load_29(offset : u32) -> mat3x2<f16> {
- return mat3x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)), sb_load_8((offset + 8u)));
-}
-
-fn sb_load_30(offset : u32) -> mat3x3<f16> {
- return mat3x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)), sb_load_12((offset + 16u)));
-}
-
-fn sb_load_31(offset : u32) -> mat3x4<f16> {
- return mat3x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)), sb_load_16((offset + 16u)));
-}
-
-fn sb_load_32(offset : u32) -> mat4x2<f16> {
- return mat4x2<f16>(sb_load_8((offset + 0u)), sb_load_8((offset + 4u)), sb_load_8((offset + 8u)), sb_load_8((offset + 12u)));
-}
-
-fn sb_load_33(offset : u32) -> mat4x3<f16> {
- return mat4x3<f16>(sb_load_12((offset + 0u)), sb_load_12((offset + 8u)), sb_load_12((offset + 16u)), sb_load_12((offset + 24u)));
-}
-
-fn sb_load_34(offset : u32) -> mat4x4<f16> {
- return mat4x4<f16>(sb_load_16((offset + 0u)), sb_load_16((offset + 8u)), sb_load_16((offset + 16u)), sb_load_16((offset + 24u)));
-}
-
-fn sb_load_35(offset : u32) -> array<vec3<f32>, 2u> {
- var arr : array<vec3<f32>, 2u>;
- for(var i = 0u; (i < 2u); i = (i + 1u)) {
- arr[i] = sb_load_9((offset + (i * 16u)));
- }
- return arr;
-}
-
-fn sb_load_36(offset : u32) -> array<mat4x2<f16>, 2u> {
- var arr_1 : array<mat4x2<f16>, 2u>;
- for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
- arr_1[i_1] = sb_load_32((offset + (i_1 * 16u)));
- }
- return arr_1;
-}
-
-fn sb_load(offset : u32) -> SB {
- return SB(sb_load_1((offset + 0u)), sb_load_2((offset + 4u)), sb_load_3((offset + 8u)), sb_load_4((offset + 12u)), sb_load_5((offset + 16u)), sb_load_6((offset + 24u)), sb_load_7((offset + 32u)), sb_load_8((offset + 40u)), sb_load_9((offset + 48u)), sb_load_10((offset + 64u)), sb_load_11((offset + 80u)), sb_load_12((offset + 96u)), sb_load_13((offset + 112u)), sb_load_14((offset + 128u)), sb_load_15((offset + 144u)), sb_load_16((offset + 160u)), sb_load_17((offset + 168u)), sb_load_18((offset + 192u)), sb_load_19((offset + 224u)), sb_load_20((offset + 256u)), sb_load_21((offset + 288u)), sb_load_22((offset + 336u)), sb_load_23((offset + 384u)), sb_load_24((offset + 416u)), sb_load_25((offset + 480u)), sb_load_26((offset + 544u)), sb_load_27((offset + 552u)), sb_load_28((offset + 568u)), sb_load_29((offset + 584u)), sb_load_30((offset + 600u)), sb_load_31((offset + 624u)), sb_load_32((offset + 648u)), sb_load_33((offset + 664u)), sb_load_34((offset + 696u)), sb_load_35((offset + 736u)), sb_load_36((offset + 768u)));
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var x : SB = sb_load(0u);
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, StoreStructure) {
- auto* src = R"(
-enable f16;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-};
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- sb = SB();
-}
-)";
-
- auto* expect = R"(
-enable f16;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_1(offset : u32, value : f32)
-
-@internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_2(offset : u32, value : i32)
-
-@internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_3(offset : u32, value : u32)
-
-@internal(intrinsic_store_storage_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_4(offset : u32, value : f16)
-
-@internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_5(offset : u32, value : vec2<f32>)
-
-@internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_6(offset : u32, value : vec2<i32>)
-
-@internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_7(offset : u32, value : vec2<u32>)
-
-@internal(intrinsic_store_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_8(offset : u32, value : vec2<f16>)
-
-@internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_9(offset : u32, value : vec3<f32>)
-
-@internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_10(offset : u32, value : vec3<i32>)
-
-@internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_11(offset : u32, value : vec3<u32>)
-
-@internal(intrinsic_store_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_12(offset : u32, value : vec3<f16>)
-
-@internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_13(offset : u32, value : vec4<f32>)
-
-@internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_14(offset : u32, value : vec4<i32>)
-
-@internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_15(offset : u32, value : vec4<u32>)
-
-@internal(intrinsic_store_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_16(offset : u32, value : vec4<f16>)
-
-fn sb_store_17(offset : u32, value : mat2x2<f32>) {
- sb_store_5((offset + 0u), value[0u]);
- sb_store_5((offset + 8u), value[1u]);
-}
-
-fn sb_store_18(offset : u32, value : mat2x3<f32>) {
- sb_store_9((offset + 0u), value[0u]);
- sb_store_9((offset + 16u), value[1u]);
-}
-
-fn sb_store_19(offset : u32, value : mat2x4<f32>) {
- sb_store_13((offset + 0u), value[0u]);
- sb_store_13((offset + 16u), value[1u]);
-}
-
-fn sb_store_20(offset : u32, value : mat3x2<f32>) {
- sb_store_5((offset + 0u), value[0u]);
- sb_store_5((offset + 8u), value[1u]);
- sb_store_5((offset + 16u), value[2u]);
-}
-
-fn sb_store_21(offset : u32, value : mat3x3<f32>) {
- sb_store_9((offset + 0u), value[0u]);
- sb_store_9((offset + 16u), value[1u]);
- sb_store_9((offset + 32u), value[2u]);
-}
-
-fn sb_store_22(offset : u32, value : mat3x4<f32>) {
- sb_store_13((offset + 0u), value[0u]);
- sb_store_13((offset + 16u), value[1u]);
- sb_store_13((offset + 32u), value[2u]);
-}
-
-fn sb_store_23(offset : u32, value : mat4x2<f32>) {
- sb_store_5((offset + 0u), value[0u]);
- sb_store_5((offset + 8u), value[1u]);
- sb_store_5((offset + 16u), value[2u]);
- sb_store_5((offset + 24u), value[3u]);
-}
-
-fn sb_store_24(offset : u32, value : mat4x3<f32>) {
- sb_store_9((offset + 0u), value[0u]);
- sb_store_9((offset + 16u), value[1u]);
- sb_store_9((offset + 32u), value[2u]);
- sb_store_9((offset + 48u), value[3u]);
-}
-
-fn sb_store_25(offset : u32, value : mat4x4<f32>) {
- sb_store_13((offset + 0u), value[0u]);
- sb_store_13((offset + 16u), value[1u]);
- sb_store_13((offset + 32u), value[2u]);
- sb_store_13((offset + 48u), value[3u]);
-}
-
-fn sb_store_26(offset : u32, value : mat2x2<f16>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 4u), value[1u]);
-}
-
-fn sb_store_27(offset : u32, value : mat2x3<f16>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 8u), value[1u]);
-}
-
-fn sb_store_28(offset : u32, value : mat2x4<f16>) {
- sb_store_16((offset + 0u), value[0u]);
- sb_store_16((offset + 8u), value[1u]);
-}
-
-fn sb_store_29(offset : u32, value : mat3x2<f16>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 4u), value[1u]);
- sb_store_8((offset + 8u), value[2u]);
-}
-
-fn sb_store_30(offset : u32, value : mat3x3<f16>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 8u), value[1u]);
- sb_store_12((offset + 16u), value[2u]);
-}
-
-fn sb_store_31(offset : u32, value : mat3x4<f16>) {
- sb_store_16((offset + 0u), value[0u]);
- sb_store_16((offset + 8u), value[1u]);
- sb_store_16((offset + 16u), value[2u]);
-}
-
-fn sb_store_32(offset : u32, value : mat4x2<f16>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 4u), value[1u]);
- sb_store_8((offset + 8u), value[2u]);
- sb_store_8((offset + 12u), value[3u]);
-}
-
-fn sb_store_33(offset : u32, value : mat4x3<f16>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 8u), value[1u]);
- sb_store_12((offset + 16u), value[2u]);
- sb_store_12((offset + 24u), value[3u]);
-}
-
-fn sb_store_34(offset : u32, value : mat4x4<f16>) {
- sb_store_16((offset + 0u), value[0u]);
- sb_store_16((offset + 8u), value[1u]);
- sb_store_16((offset + 16u), value[2u]);
- sb_store_16((offset + 24u), value[3u]);
-}
-
-fn sb_store_35(offset : u32, value : array<vec3<f32>, 2u>) {
- var array_1 = value;
- for(var i = 0u; (i < 2u); i = (i + 1u)) {
- sb_store_9((offset + (i * 16u)), array_1[i]);
- }
-}
-
-fn sb_store_36(offset : u32, value : array<mat4x2<f16>, 2u>) {
- var array_2 = value;
- for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
- sb_store_32((offset + (i_1 * 16u)), array_2[i_1]);
- }
-}
-
-fn sb_store(offset : u32, value : SB) {
- sb_store_1((offset + 0u), value.scalar_f32);
- sb_store_2((offset + 4u), value.scalar_i32);
- sb_store_3((offset + 8u), value.scalar_u32);
- sb_store_4((offset + 12u), value.scalar_f16);
- sb_store_5((offset + 16u), value.vec2_f32);
- sb_store_6((offset + 24u), value.vec2_i32);
- sb_store_7((offset + 32u), value.vec2_u32);
- sb_store_8((offset + 40u), value.vec2_f16);
- sb_store_9((offset + 48u), value.vec3_f32);
- sb_store_10((offset + 64u), value.vec3_i32);
- sb_store_11((offset + 80u), value.vec3_u32);
- sb_store_12((offset + 96u), value.vec3_f16);
- sb_store_13((offset + 112u), value.vec4_f32);
- sb_store_14((offset + 128u), value.vec4_i32);
- sb_store_15((offset + 144u), value.vec4_u32);
- sb_store_16((offset + 160u), value.vec4_f16);
- sb_store_17((offset + 168u), value.mat2x2_f32);
- sb_store_18((offset + 192u), value.mat2x3_f32);
- sb_store_19((offset + 224u), value.mat2x4_f32);
- sb_store_20((offset + 256u), value.mat3x2_f32);
- sb_store_21((offset + 288u), value.mat3x3_f32);
- sb_store_22((offset + 336u), value.mat3x4_f32);
- sb_store_23((offset + 384u), value.mat4x2_f32);
- sb_store_24((offset + 416u), value.mat4x3_f32);
- sb_store_25((offset + 480u), value.mat4x4_f32);
- sb_store_26((offset + 544u), value.mat2x2_f16);
- sb_store_27((offset + 552u), value.mat2x3_f16);
- sb_store_28((offset + 568u), value.mat2x4_f16);
- sb_store_29((offset + 584u), value.mat3x2_f16);
- sb_store_30((offset + 600u), value.mat3x3_f16);
- sb_store_31((offset + 624u), value.mat3x4_f16);
- sb_store_32((offset + 648u), value.mat4x2_f16);
- sb_store_33((offset + 664u), value.mat4x3_f16);
- sb_store_34((offset + 696u), value.mat4x4_f16);
- sb_store_35((offset + 736u), value.arr2_vec3_f32);
- sb_store_36((offset + 768u), value.arr2_mat4x2_f16);
-}
-
-@compute @workgroup_size(1)
-fn main() {
- sb_store(0u, SB());
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, StoreStructure_OutOfOrder) {
- auto* src = R"(
-enable f16;
-
-@compute @workgroup_size(1)
-fn main() {
- sb = SB();
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-};
-)";
-
- auto* expect = R"(
-enable f16;
-
-@internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_1(offset : u32, value : f32)
-
-@internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_2(offset : u32, value : i32)
-
-@internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_3(offset : u32, value : u32)
-
-@internal(intrinsic_store_storage_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_4(offset : u32, value : f16)
-
-@internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_5(offset : u32, value : vec2<f32>)
-
-@internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_6(offset : u32, value : vec2<i32>)
-
-@internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_7(offset : u32, value : vec2<u32>)
-
-@internal(intrinsic_store_storage_vec2_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_8(offset : u32, value : vec2<f16>)
-
-@internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_9(offset : u32, value : vec3<f32>)
-
-@internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_10(offset : u32, value : vec3<i32>)
-
-@internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_11(offset : u32, value : vec3<u32>)
-
-@internal(intrinsic_store_storage_vec3_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_12(offset : u32, value : vec3<f16>)
-
-@internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
-fn sb_store_13(offset : u32, value : vec4<f32>)
-
-@internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
-fn sb_store_14(offset : u32, value : vec4<i32>)
-
-@internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
-fn sb_store_15(offset : u32, value : vec4<u32>)
-
-@internal(intrinsic_store_storage_vec4_f16) @internal(disable_validation__function_has_no_body)
-fn sb_store_16(offset : u32, value : vec4<f16>)
-
-fn sb_store_17(offset : u32, value : mat2x2<f32>) {
- sb_store_5((offset + 0u), value[0u]);
- sb_store_5((offset + 8u), value[1u]);
-}
-
-fn sb_store_18(offset : u32, value : mat2x3<f32>) {
- sb_store_9((offset + 0u), value[0u]);
- sb_store_9((offset + 16u), value[1u]);
-}
-
-fn sb_store_19(offset : u32, value : mat2x4<f32>) {
- sb_store_13((offset + 0u), value[0u]);
- sb_store_13((offset + 16u), value[1u]);
-}
-
-fn sb_store_20(offset : u32, value : mat3x2<f32>) {
- sb_store_5((offset + 0u), value[0u]);
- sb_store_5((offset + 8u), value[1u]);
- sb_store_5((offset + 16u), value[2u]);
-}
-
-fn sb_store_21(offset : u32, value : mat3x3<f32>) {
- sb_store_9((offset + 0u), value[0u]);
- sb_store_9((offset + 16u), value[1u]);
- sb_store_9((offset + 32u), value[2u]);
-}
-
-fn sb_store_22(offset : u32, value : mat3x4<f32>) {
- sb_store_13((offset + 0u), value[0u]);
- sb_store_13((offset + 16u), value[1u]);
- sb_store_13((offset + 32u), value[2u]);
-}
-
-fn sb_store_23(offset : u32, value : mat4x2<f32>) {
- sb_store_5((offset + 0u), value[0u]);
- sb_store_5((offset + 8u), value[1u]);
- sb_store_5((offset + 16u), value[2u]);
- sb_store_5((offset + 24u), value[3u]);
-}
-
-fn sb_store_24(offset : u32, value : mat4x3<f32>) {
- sb_store_9((offset + 0u), value[0u]);
- sb_store_9((offset + 16u), value[1u]);
- sb_store_9((offset + 32u), value[2u]);
- sb_store_9((offset + 48u), value[3u]);
-}
-
-fn sb_store_25(offset : u32, value : mat4x4<f32>) {
- sb_store_13((offset + 0u), value[0u]);
- sb_store_13((offset + 16u), value[1u]);
- sb_store_13((offset + 32u), value[2u]);
- sb_store_13((offset + 48u), value[3u]);
-}
-
-fn sb_store_26(offset : u32, value : mat2x2<f16>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 4u), value[1u]);
-}
-
-fn sb_store_27(offset : u32, value : mat2x3<f16>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 8u), value[1u]);
-}
-
-fn sb_store_28(offset : u32, value : mat2x4<f16>) {
- sb_store_16((offset + 0u), value[0u]);
- sb_store_16((offset + 8u), value[1u]);
-}
-
-fn sb_store_29(offset : u32, value : mat3x2<f16>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 4u), value[1u]);
- sb_store_8((offset + 8u), value[2u]);
-}
-
-fn sb_store_30(offset : u32, value : mat3x3<f16>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 8u), value[1u]);
- sb_store_12((offset + 16u), value[2u]);
-}
-
-fn sb_store_31(offset : u32, value : mat3x4<f16>) {
- sb_store_16((offset + 0u), value[0u]);
- sb_store_16((offset + 8u), value[1u]);
- sb_store_16((offset + 16u), value[2u]);
-}
-
-fn sb_store_32(offset : u32, value : mat4x2<f16>) {
- sb_store_8((offset + 0u), value[0u]);
- sb_store_8((offset + 4u), value[1u]);
- sb_store_8((offset + 8u), value[2u]);
- sb_store_8((offset + 12u), value[3u]);
-}
-
-fn sb_store_33(offset : u32, value : mat4x3<f16>) {
- sb_store_12((offset + 0u), value[0u]);
- sb_store_12((offset + 8u), value[1u]);
- sb_store_12((offset + 16u), value[2u]);
- sb_store_12((offset + 24u), value[3u]);
-}
-
-fn sb_store_34(offset : u32, value : mat4x4<f16>) {
- sb_store_16((offset + 0u), value[0u]);
- sb_store_16((offset + 8u), value[1u]);
- sb_store_16((offset + 16u), value[2u]);
- sb_store_16((offset + 24u), value[3u]);
-}
-
-fn sb_store_35(offset : u32, value : array<vec3<f32>, 2u>) {
- var array_1 = value;
- for(var i = 0u; (i < 2u); i = (i + 1u)) {
- sb_store_9((offset + (i * 16u)), array_1[i]);
- }
-}
-
-fn sb_store_36(offset : u32, value : array<mat4x2<f16>, 2u>) {
- var array_2 = value;
- for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
- sb_store_32((offset + (i_1 * 16u)), array_2[i_1]);
- }
-}
-
-fn sb_store(offset : u32, value : SB) {
- sb_store_1((offset + 0u), value.scalar_f32);
- sb_store_2((offset + 4u), value.scalar_i32);
- sb_store_3((offset + 8u), value.scalar_u32);
- sb_store_4((offset + 12u), value.scalar_f16);
- sb_store_5((offset + 16u), value.vec2_f32);
- sb_store_6((offset + 24u), value.vec2_i32);
- sb_store_7((offset + 32u), value.vec2_u32);
- sb_store_8((offset + 40u), value.vec2_f16);
- sb_store_9((offset + 48u), value.vec3_f32);
- sb_store_10((offset + 64u), value.vec3_i32);
- sb_store_11((offset + 80u), value.vec3_u32);
- sb_store_12((offset + 96u), value.vec3_f16);
- sb_store_13((offset + 112u), value.vec4_f32);
- sb_store_14((offset + 128u), value.vec4_i32);
- sb_store_15((offset + 144u), value.vec4_u32);
- sb_store_16((offset + 160u), value.vec4_f16);
- sb_store_17((offset + 168u), value.mat2x2_f32);
- sb_store_18((offset + 192u), value.mat2x3_f32);
- sb_store_19((offset + 224u), value.mat2x4_f32);
- sb_store_20((offset + 256u), value.mat3x2_f32);
- sb_store_21((offset + 288u), value.mat3x3_f32);
- sb_store_22((offset + 336u), value.mat3x4_f32);
- sb_store_23((offset + 384u), value.mat4x2_f32);
- sb_store_24((offset + 416u), value.mat4x3_f32);
- sb_store_25((offset + 480u), value.mat4x4_f32);
- sb_store_26((offset + 544u), value.mat2x2_f16);
- sb_store_27((offset + 552u), value.mat2x3_f16);
- sb_store_28((offset + 568u), value.mat2x4_f16);
- sb_store_29((offset + 584u), value.mat3x2_f16);
- sb_store_30((offset + 600u), value.mat3x3_f16);
- sb_store_31((offset + 624u), value.mat3x4_f16);
- sb_store_32((offset + 648u), value.mat4x2_f16);
- sb_store_33((offset + 664u), value.mat4x3_f16);
- sb_store_34((offset + 696u), value.mat4x4_f16);
- sb_store_35((offset + 736u), value.arr2_vec3_f32);
- sb_store_36((offset + 768u), value.arr2_mat4x2_f16);
-}
-
-@compute @workgroup_size(1)
-fn main() {
- sb_store(0u, SB());
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- scalar_f32 : f32,
- scalar_i32 : i32,
- scalar_u32 : u32,
- scalar_f16 : f16,
- vec2_f32 : vec2<f32>,
- vec2_i32 : vec2<i32>,
- vec2_u32 : vec2<u32>,
- vec2_f16 : vec2<f16>,
- vec3_f32 : vec3<f32>,
- vec3_i32 : vec3<i32>,
- vec3_u32 : vec3<u32>,
- vec3_f16 : vec3<f16>,
- vec4_f32 : vec4<f32>,
- vec4_i32 : vec4<i32>,
- vec4_u32 : vec4<u32>,
- vec4_f16 : vec4<f16>,
- mat2x2_f32 : mat2x2<f32>,
- mat2x3_f32 : mat2x3<f32>,
- mat2x4_f32 : mat2x4<f32>,
- mat3x2_f32 : mat3x2<f32>,
- mat3x3_f32 : mat3x3<f32>,
- mat3x4_f32 : mat3x4<f32>,
- mat4x2_f32 : mat4x2<f32>,
- mat4x3_f32 : mat4x3<f32>,
- mat4x4_f32 : mat4x4<f32>,
- mat2x2_f16 : mat2x2<f16>,
- mat2x3_f16 : mat2x3<f16>,
- mat2x4_f16 : mat2x4<f16>,
- mat3x2_f16 : mat3x2<f16>,
- mat3x3_f16 : mat3x3<f16>,
- mat3x4_f16 : mat3x4<f16>,
- mat4x2_f16 : mat4x2<f16>,
- mat4x3_f16 : mat4x3<f16>,
- mat4x4_f16 : mat4x4<f16>,
- arr2_vec3_f32 : array<vec3<f32>, 2>,
- arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, ComplexStaticAccessChain) {
- auto* src = R"(
-// sizeof(S1) == 32
-// alignof(S1) == 16
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-};
-
-// sizeof(S2) == 116
-// alignof(S2) == 16
-struct S2 {
- a : i32,
- b : array<S1, 3>,
- c : i32,
-};
-
-struct SB {
- @size(128)
- a : i32,
- b : array<S2>,
-};
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var x : f32 = sb.b[4].b[1].b.z;
-}
-)";
-
- // sb.b[4].b[1].b.z
- // ^ ^ ^ ^ ^ ^
- // | | | | | |
- // 128 | |688 | 712
- // | | |
- // 640 656 704
-
- auto* expect = R"(
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-}
-
-struct S2 {
- a : i32,
- b : array<S1, 3>,
- c : i32,
-}
-
-struct SB {
- @size(128)
- a : i32,
- b : array<S2>,
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load(offset : u32) -> f32
-
-@compute @workgroup_size(1)
-fn main() {
- var x : f32 = sb_load(712u);
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, ComplexStaticAccessChain_ViaPointerDot) {
- auto* src = R"(
-// sizeof(S1) == 32
-// alignof(S1) == 16
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-};
-
-// sizeof(S2) == 116
-// alignof(S2) == 16
-struct S2 {
- a : i32,
- b : array<S1, 3>,
- c : i32,
-};
-
-struct SB {
- @size(128)
- a : i32,
- b : array<S2>,
-};
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- let p = &sb;
- var x : f32 = (*p).b[4].b[1].b.z;
-}
-)";
-
- // sb.b[4].b[1].b.z
- // ^ ^ ^ ^ ^ ^
- // | | | | | |
- // 128 | |688 | 712
- // | | |
- // 640 656 704
-
- auto* expect = R"(
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-}
-
-struct S2 {
- a : i32,
- b : array<S1, 3>,
- c : i32,
-}
-
-struct SB {
- @size(128)
- a : i32,
- b : array<S2>,
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load(offset : u32) -> f32
-
-@compute @workgroup_size(1)
-fn main() {
- var x : f32 = sb_load(712u);
-}
-)";
-
- auto got = Run<ast::transform::SimplifyPointers, DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, ComplexStaticAccessChain_OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main() {
- var x : f32 = sb.b[4].b[1].b.z;
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- @size(128)
- a : i32,
- b : array<S2>,
-};
-
-struct S2 {
- a : i32,
- b : array<S1, 3>,
- c : i32,
-};
-
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-};
-)";
-
- // sb.b[4].b[1].b.z
- // ^ ^ ^ ^ ^ ^
- // | | | | | |
- // 128 | |688 | 712
- // | | |
- // 640 656 704
-
- auto* expect = R"(
-@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load(offset : u32) -> f32
-
-@compute @workgroup_size(1)
-fn main() {
- var x : f32 = sb_load(712u);
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- @size(128)
- a : i32,
- b : array<S2>,
-}
-
-struct S2 {
- a : i32,
- b : array<S1, 3>,
- c : i32,
-}
-
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, ComplexDynamicAccessChain) {
- auto* src = R"(
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-};
-
-struct S2 {
- a : i32,
- b : array<S1, 3>,
- c : i32,
-};
-
-struct SB {
- @size(128)
- a : i32,
- b : array<S2>,
-};
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var i : i32 = 4;
- var j : u32 = 1u;
- var k : i32 = 2;
- var x : f32 = sb.b[i].b[j].b[k];
-}
-)";
-
- auto* expect = R"(
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-}
-
-struct S2 {
- a : i32,
- b : array<S1, 3>,
- c : i32,
-}
-
-struct SB {
- @size(128)
- a : i32,
- b : array<S2>,
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load(offset : u32) -> f32
-
-@compute @workgroup_size(1)
-fn main() {
- var i : i32 = 4;
- var j : u32 = 1u;
- var k : i32 = 2;
- var x : f32 = sb_load((((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, ComplexDynamicAccessChain_OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main() {
- var i : i32 = 4;
- var j : u32 = 1u;
- var k : i32 = 2;
- var x : f32 = sb.b[i].b[j].b[k];
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- @size(128)
- a : i32,
- b : array<S2>
-};
-
-struct S2 {
- a : i32,
- b : array<S1, 3>,
- c : i32,
-};
-
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-};
-)";
-
- auto* expect = R"(
-@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load(offset : u32) -> f32
-
-@compute @workgroup_size(1)
-fn main() {
- var i : i32 = 4;
- var j : u32 = 1u;
- var k : i32 = 2;
- var x : f32 = sb_load((((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- @size(128)
- a : i32,
- b : array<S2>,
-}
-
-struct S2 {
- a : i32,
- b : array<S1, 3>,
- c : i32,
-}
-
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, ComplexDynamicAccessChainWithAliases) {
- auto* src = R"(
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-};
-
-alias A1 = S1;
-
-alias A1_Array = array<S1, 3>;
-
-struct S2 {
- a : i32,
- b : A1_Array,
- c : i32,
-};
-
-alias A2 = S2;
-
-alias A2_Array = array<S2>;
-
-struct SB {
- @size(128)
- a : i32,
- b : A2_Array,
-};
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- var i : i32 = 4;
- var j : u32 = 1u;
- var k : i32 = 2;
- var x : f32 = sb.b[i].b[j].b[k];
-}
-)";
-
- auto* expect = R"(
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-}
-
-alias A1 = S1;
-
-alias A1_Array = array<S1, 3>;
-
-struct S2 {
- a : i32,
- b : A1_Array,
- c : i32,
-}
-
-alias A2 = S2;
-
-alias A2_Array = array<S2>;
-
-struct SB {
- @size(128)
- a : i32,
- b : A2_Array,
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load(offset : u32) -> f32
-
-@compute @workgroup_size(1)
-fn main() {
- var i : i32 = 4;
- var j : u32 = 1u;
- var k : i32 = 2;
- var x : f32 = sb_load((((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, ComplexDynamicAccessChainWithAliases_OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main() {
- var i : i32 = 4;
- var j : u32 = 1u;
- var k : i32 = 2;
- var x : f32 = sb.b[i].b[j].b[k];
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- @size(128)
- a : i32,
- b : A2_Array,
-};
-
-alias A2_Array = array<S2>;
-
-alias A2 = S2;
-
-struct S2 {
- a : i32,
- b : A1_Array,
- c : i32,
-};
-
-alias A1 = S1;
-
-alias A1_Array = array<S1, 3>;
-
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-};
-)";
-
- auto* expect = R"(
-@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
-fn sb_load(offset : u32) -> f32
-
-@compute @workgroup_size(1)
-fn main() {
- var i : i32 = 4;
- var j : u32 = 1u;
- var k : i32 = 2;
- var x : f32 = sb_load((((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- @size(128)
- a : i32,
- b : A2_Array,
-}
-
-alias A2_Array = array<S2>;
-
-alias A2 = S2;
-
-struct S2 {
- a : i32,
- b : A1_Array,
- c : i32,
-}
-
-alias A1 = S1;
-
-alias A1_Array = array<S1, 3>;
-
-struct S1 {
- a : i32,
- b : vec3<f32>,
- c : i32,
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, StorageBufferAtomics) {
- auto* src = R"(
-struct SB {
- padding : vec4<f32>,
- a : atomic<i32>,
- b : atomic<u32>,
-};
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@compute @workgroup_size(1)
-fn main() {
- atomicStore(&sb.a, 123);
- atomicLoad(&sb.a);
- atomicAdd(&sb.a, 123);
- atomicSub(&sb.a, 123);
- atomicMax(&sb.a, 123);
- atomicMin(&sb.a, 123);
- atomicAnd(&sb.a, 123);
- atomicOr(&sb.a, 123);
- atomicXor(&sb.a, 123);
- atomicExchange(&sb.a, 123);
- atomicCompareExchangeWeak(&sb.a, 123, 345);
-
- atomicStore(&sb.b, 123u);
- atomicLoad(&sb.b);
- atomicAdd(&sb.b, 123u);
- atomicSub(&sb.b, 123u);
- atomicMax(&sb.b, 123u);
- atomicMin(&sb.b, 123u);
- atomicAnd(&sb.b, 123u);
- atomicOr(&sb.b, 123u);
- atomicXor(&sb.b, 123u);
- atomicExchange(&sb.b, 123u);
- atomicCompareExchangeWeak(&sb.b, 123u, 345u);
-}
-)";
-
- auto* expect = R"(
-struct SB {
- padding : vec4<f32>,
- a : atomic<i32>,
- b : atomic<u32>,
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-@internal(intrinsic_atomic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicStore(offset : u32, param_1 : i32)
-
-@internal(intrinsic_atomic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicLoad(offset : u32) -> i32
-
-@internal(intrinsic_atomic_add_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicAdd(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_sub_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicSub(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_max_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicMax(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_min_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicMin(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_and_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicAnd(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_or_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicOr(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_xor_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicXor(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_exchange_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicExchange(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_compare_exchange_weak_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicCompareExchangeWeak(offset : u32, param_1 : i32, param_2 : i32) -> __atomic_compare_exchange_result_i32
-
-@internal(intrinsic_atomic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicStore_1(offset : u32, param_1 : u32)
-
-@internal(intrinsic_atomic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicLoad_1(offset : u32) -> u32
-
-@internal(intrinsic_atomic_add_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicAdd_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_sub_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicSub_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_max_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicMax_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_min_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicMin_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_and_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicAnd_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_or_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicOr_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_xor_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicXor_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_exchange_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicExchange_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_compare_exchange_weak_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicCompareExchangeWeak_1(offset : u32, param_1 : u32, param_2 : u32) -> __atomic_compare_exchange_result_u32
-
-@compute @workgroup_size(1)
-fn main() {
- sbatomicStore(16u, 123);
- sbatomicLoad(16u);
- sbatomicAdd(16u, 123);
- sbatomicSub(16u, 123);
- sbatomicMax(16u, 123);
- sbatomicMin(16u, 123);
- sbatomicAnd(16u, 123);
- sbatomicOr(16u, 123);
- sbatomicXor(16u, 123);
- sbatomicExchange(16u, 123);
- sbatomicCompareExchangeWeak(16u, 123, 345);
- sbatomicStore_1(20u, 123u);
- sbatomicLoad_1(20u);
- sbatomicAdd_1(20u, 123u);
- sbatomicSub_1(20u, 123u);
- sbatomicMax_1(20u, 123u);
- sbatomicMin_1(20u, 123u);
- sbatomicAnd_1(20u, 123u);
- sbatomicOr_1(20u, 123u);
- sbatomicXor_1(20u, 123u);
- sbatomicExchange_1(20u, 123u);
- sbatomicCompareExchangeWeak_1(20u, 123u, 345u);
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, StorageBufferAtomics_OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main() {
- atomicStore(&sb.a, 123);
- atomicLoad(&sb.a);
- atomicAdd(&sb.a, 123);
- atomicSub(&sb.a, 123);
- atomicMax(&sb.a, 123);
- atomicMin(&sb.a, 123);
- atomicAnd(&sb.a, 123);
- atomicOr(&sb.a, 123);
- atomicXor(&sb.a, 123);
- atomicExchange(&sb.a, 123);
- atomicCompareExchangeWeak(&sb.a, 123, 345);
-
- atomicStore(&sb.b, 123u);
- atomicLoad(&sb.b);
- atomicAdd(&sb.b, 123u);
- atomicSub(&sb.b, 123u);
- atomicMax(&sb.b, 123u);
- atomicMin(&sb.b, 123u);
- atomicAnd(&sb.b, 123u);
- atomicOr(&sb.b, 123u);
- atomicXor(&sb.b, 123u);
- atomicExchange(&sb.b, 123u);
- atomicCompareExchangeWeak(&sb.b, 123u, 345u);
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- padding : vec4<f32>,
- a : atomic<i32>,
- b : atomic<u32>,
-};
-)";
-
- auto* expect = R"(
-@internal(intrinsic_atomic_store_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicStore(offset : u32, param_1 : i32)
-
-@internal(intrinsic_atomic_load_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicLoad(offset : u32) -> i32
-
-@internal(intrinsic_atomic_add_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicAdd(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_sub_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicSub(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_max_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicMax(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_min_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicMin(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_and_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicAnd(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_or_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicOr(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_xor_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicXor(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_exchange_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicExchange(offset : u32, param_1 : i32) -> i32
-
-@internal(intrinsic_atomic_compare_exchange_weak_storage_i32) @internal(disable_validation__function_has_no_body)
-fn sbatomicCompareExchangeWeak(offset : u32, param_1 : i32, param_2 : i32) -> __atomic_compare_exchange_result_i32
-
-@internal(intrinsic_atomic_store_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicStore_1(offset : u32, param_1 : u32)
-
-@internal(intrinsic_atomic_load_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicLoad_1(offset : u32) -> u32
-
-@internal(intrinsic_atomic_add_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicAdd_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_sub_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicSub_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_max_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicMax_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_min_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicMin_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_and_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicAnd_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_or_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicOr_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_xor_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicXor_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_exchange_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicExchange_1(offset : u32, param_1 : u32) -> u32
-
-@internal(intrinsic_atomic_compare_exchange_weak_storage_u32) @internal(disable_validation__function_has_no_body)
-fn sbatomicCompareExchangeWeak_1(offset : u32, param_1 : u32, param_2 : u32) -> __atomic_compare_exchange_result_u32
-
-@compute @workgroup_size(1)
-fn main() {
- sbatomicStore(16u, 123);
- sbatomicLoad(16u);
- sbatomicAdd(16u, 123);
- sbatomicSub(16u, 123);
- sbatomicMax(16u, 123);
- sbatomicMin(16u, 123);
- sbatomicAnd(16u, 123);
- sbatomicOr(16u, 123);
- sbatomicXor(16u, 123);
- sbatomicExchange(16u, 123);
- sbatomicCompareExchangeWeak(16u, 123, 345);
- sbatomicStore_1(20u, 123u);
- sbatomicLoad_1(20u);
- sbatomicAdd_1(20u, 123u);
- sbatomicSub_1(20u, 123u);
- sbatomicMax_1(20u, 123u);
- sbatomicMin_1(20u, 123u);
- sbatomicAnd_1(20u, 123u);
- sbatomicOr_1(20u, 123u);
- sbatomicXor_1(20u, 123u);
- sbatomicExchange_1(20u, 123u);
- sbatomicCompareExchangeWeak_1(20u, 123u, 345u);
-}
-
-@group(0) @binding(0) var<storage, read_write> sb : SB;
-
-struct SB {
- padding : vec4<f32>,
- a : atomic<i32>,
- b : atomic<u32>,
-}
-)";
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, WorkgroupBufferAtomics) {
- auto* src = R"(
-struct S {
- padding : vec4<f32>,
- a : atomic<i32>,
- b : atomic<u32>,
-}
-
-var<workgroup> w : S;
-
-@compute @workgroup_size(1)
-fn main() {
- atomicStore(&(w.a), 123);
- atomicLoad(&(w.a));
- atomicAdd(&(w.a), 123);
- atomicSub(&(w.a), 123);
- atomicMax(&(w.a), 123);
- atomicMin(&(w.a), 123);
- atomicAnd(&(w.a), 123);
- atomicOr(&(w.a), 123);
- atomicXor(&(w.a), 123);
- atomicExchange(&(w.a), 123);
- atomicCompareExchangeWeak(&(w.a), 123, 345);
- atomicStore(&(w.b), 123u);
- atomicLoad(&(w.b));
- atomicAdd(&(w.b), 123u);
- atomicSub(&(w.b), 123u);
- atomicMax(&(w.b), 123u);
- atomicMin(&(w.b), 123u);
- atomicAnd(&(w.b), 123u);
- atomicOr(&(w.b), 123u);
- atomicXor(&(w.b), 123u);
- atomicExchange(&(w.b), 123u);
- atomicCompareExchangeWeak(&(w.b), 123u, 345u);
-}
-)";
-
- auto* expect = src;
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(DecomposeMemoryAccessTest, WorkgroupBufferAtomics_OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main() {
- atomicStore(&(w.a), 123);
- atomicLoad(&(w.a));
- atomicAdd(&(w.a), 123);
- atomicSub(&(w.a), 123);
- atomicMax(&(w.a), 123);
- atomicMin(&(w.a), 123);
- atomicAnd(&(w.a), 123);
- atomicOr(&(w.a), 123);
- atomicXor(&(w.a), 123);
- atomicExchange(&(w.a), 123);
- atomicCompareExchangeWeak(&(w.a), 123, 345);
- atomicStore(&(w.b), 123u);
- atomicLoad(&(w.b));
- atomicAdd(&(w.b), 123u);
- atomicSub(&(w.b), 123u);
- atomicMax(&(w.b), 123u);
- atomicMin(&(w.b), 123u);
- atomicAnd(&(w.b), 123u);
- atomicOr(&(w.b), 123u);
- atomicXor(&(w.b), 123u);
- atomicExchange(&(w.b), 123u);
- atomicCompareExchangeWeak(&(w.b), 123u, 345u);
-}
-
-var<workgroup> w : S;
-
-struct S {
- padding : vec4<f32>,
- a : atomic<i32>,
- b : atomic<u32>,
-}
-)";
-
- auto* expect = src;
-
- auto got = Run<DecomposeMemoryAccess>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment.cc b/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment.cc
deleted file mode 100644
index dd03321..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment.cc
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright 2021 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/hlsl/writer/ast_raise/localize_struct_array_assignment.h"
-
-#include <unordered_map>
-#include <utility>
-
-#include "src/tint/lang/core/type/reference.h"
-#include "src/tint/lang/wgsl/ast/assignment_statement.h"
-#include "src/tint/lang/wgsl/ast/transform/simplify_pointers.h"
-#include "src/tint/lang/wgsl/ast/traverse_expressions.h"
-#include "src/tint/lang/wgsl/program/clone_context.h"
-#include "src/tint/lang/wgsl/program/program_builder.h"
-#include "src/tint/lang/wgsl/resolver/resolve.h"
-#include "src/tint/lang/wgsl/sem/member_accessor_expression.h"
-#include "src/tint/lang/wgsl/sem/statement.h"
-#include "src/tint/lang/wgsl/sem/value_expression.h"
-#include "src/tint/lang/wgsl/sem/variable.h"
-#include "src/tint/utils/macros/scoped_assignment.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::LocalizeStructArrayAssignment);
-
-namespace tint::hlsl::writer {
-
-/// PIMPL state for the transform
-struct LocalizeStructArrayAssignment::State {
- /// Constructor
- /// @param program the source program
- explicit State(const Program& program) : src(program) {}
-
- /// Runs the transform
- /// @returns the new program or SkipTransform if the transform is not required
- ApplyResult Run() {
- struct Shared {
- bool process_nested_nodes = false;
- Vector<const ast::Statement*, 4> insert_before_stmts;
- Vector<const ast::Statement*, 4> insert_after_stmts;
- } s;
-
- bool made_changes = false;
-
- for (auto* node : src.ASTNodes().Objects()) {
- if (auto* assign_stmt = node->As<ast::AssignmentStatement>()) {
- // Process if it's an assignment statement to a dynamically indexed array
- // within a struct on a function or private storage variable. This
- // specific use-case is what FXC fails to compile with:
- // error X3500: array reference cannot be used as an l-value; not natively
- // addressable
- if (!ContainsStructArrayIndex(assign_stmt->lhs)) {
- continue;
- }
- auto og = GetOriginatingTypeAndAddressSpace(assign_stmt);
- if (!(og.first->Is<core::type::Struct>() &&
- (og.second == core::AddressSpace::kFunction ||
- og.second == core::AddressSpace::kPrivate))) {
- continue;
- }
-
- ctx.Replace(assign_stmt, [&, assign_stmt] {
- // Reset shared state for this assignment statement
- s = Shared{};
-
- const ast::Expression* new_lhs = nullptr;
- {
- TINT_SCOPED_ASSIGNMENT(s.process_nested_nodes, true);
- new_lhs = ctx.Clone(assign_stmt->lhs);
- }
-
- auto* new_assign_stmt = b.Assign(new_lhs, ctx.Clone(assign_stmt->rhs));
-
- // Combine insert_before_stmts + new_assign_stmt + insert_after_stmts into
- // a block and return it
- auto stmts = std::move(s.insert_before_stmts);
- stmts.Reserve(1 + s.insert_after_stmts.Length());
- stmts.Push(new_assign_stmt);
- for (auto* stmt : s.insert_after_stmts) {
- stmts.Push(stmt);
- }
-
- return b.Block(std::move(stmts));
- });
-
- made_changes = true;
- }
- }
-
- if (!made_changes) {
- return SkipTransform;
- }
-
- ctx.ReplaceAll(
- [&](const ast::IndexAccessorExpression* index_access) -> const ast::Expression* {
- if (!s.process_nested_nodes) {
- return nullptr;
- }
-
- // Indexing a member access expr?
- auto* mem_access = index_access->object->As<ast::MemberAccessorExpression>();
- if (!mem_access) {
- return nullptr;
- }
-
- // Process any nested IndexAccessorExpressions
- mem_access = ctx.Clone(mem_access);
-
- // Store the address of the member access into a let as we need to read
- // the value twice e.g. let tint_symbol = &(s.a1);
- auto mem_access_ptr = b.Sym();
- s.insert_before_stmts.Push(b.Decl(b.Let(mem_access_ptr, b.AddressOf(mem_access))));
-
- // Disable further transforms when cloning
- TINT_SCOPED_ASSIGNMENT(s.process_nested_nodes, false);
-
- // Copy entire array out of struct into local temp var
- // e.g. var tint_symbol_1 = *(tint_symbol);
- auto tmp_var = b.Sym();
- s.insert_before_stmts.Push(b.Decl(b.Var(tmp_var, b.Deref(mem_access_ptr))));
-
- // Replace input index_access with a clone of itself, but with its
- // .object replaced by the new temp var. This is returned from this
- // function to modify the original assignment statement. e.g.
- // tint_symbol_1[uniforms.i]
- auto* new_index_access = b.IndexAccessor(tmp_var, ctx.Clone(index_access->index));
-
- // Assign temp var back to array
- // e.g. *(tint_symbol) = tint_symbol_1;
- auto* assign_rhs_to_temp = b.Assign(b.Deref(mem_access_ptr), tmp_var);
- {
- Vector<const ast::Statement*, 8> stmts{assign_rhs_to_temp};
- for (auto* stmt : s.insert_after_stmts) {
- stmts.Push(stmt);
- }
- s.insert_after_stmts = std::move(stmts);
- }
-
- return new_index_access;
- });
-
- ctx.Clone();
- return resolver::Resolve(b);
- }
-
- private:
- /// The source program
- const Program& src;
- /// The target program builder
- ProgramBuilder b;
- /// The clone context
- program::CloneContext ctx = {&b, &src, /* auto_clone_symbols */ true};
-
- /// Returns true if `expr` contains an index accessor expression to a
- /// structure member of array type.
- bool ContainsStructArrayIndex(const ast::Expression* expr) {
- bool result = false;
- TraverseExpressions(expr, [&](const ast::IndexAccessorExpression* ia) {
- // Indexing using a runtime value?
- auto* idx_sem = src.Sem().GetVal(ia->index);
- if (!idx_sem->ConstantValue()) {
- // Indexing a member access expr?
- if (auto* ma = ia->object->As<ast::MemberAccessorExpression>()) {
- const auto* ma_ty = src.TypeOf(ma);
- if (DAWN_UNLIKELY(ma_ty->Is<core::type::Pointer>())) {
- TINT_ICE()
- << "lhs of index accessor expression should not be a pointer. These "
- "should have been removed by the SimplifyPointers transform";
- }
- // That accesses an array?
- if (ma_ty->UnwrapRef()->Is<core::type::Array>()) {
- result = true;
- return ast::TraverseAction::Stop;
- }
- }
- }
- return ast::TraverseAction::Descend;
- });
-
- return result;
- }
-
- // Returns the type and address space of the originating variable of the lhs
- // of the assignment statement.
- // See https://www.w3.org/TR/WGSL/#originating-variable-section
- std::pair<const core::type::Type*, core::AddressSpace> GetOriginatingTypeAndAddressSpace(
- const ast::AssignmentStatement* assign_stmt) {
- auto* root_ident = src.Sem().GetVal(assign_stmt->lhs)->RootIdentifier();
- if (DAWN_UNLIKELY(!root_ident)) {
- TINT_ICE() << "Unable to determine originating variable for lhs of assignment "
- "statement";
- }
-
- return Switch(
- root_ident->Type(), //
- [&](const core::type::Reference* ref) {
- return std::make_pair(ref->StoreType(), ref->AddressSpace());
- },
- [&](const core::type::Pointer* ptr) {
- return std::make_pair(ptr->StoreType(), ptr->AddressSpace());
- }, //
- TINT_ICE_ON_NO_MATCH);
- }
-};
-
-LocalizeStructArrayAssignment::LocalizeStructArrayAssignment() = default;
-
-LocalizeStructArrayAssignment::~LocalizeStructArrayAssignment() = default;
-
-ast::transform::Transform::ApplyResult LocalizeStructArrayAssignment::Apply(
- const Program& src,
- const ast::transform::DataMap&,
- ast::transform::DataMap&) const {
- return State{src}.Run();
-}
-
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment.h b/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment.h
deleted file mode 100644
index 550d625..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2021 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_LANG_HLSL_WRITER_AST_RAISE_LOCALIZE_STRUCT_ARRAY_ASSIGNMENT_H_
-#define SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_LOCALIZE_STRUCT_ARRAY_ASSIGNMENT_H_
-
-#include "src/tint/lang/wgsl/ast/transform/transform.h"
-
-namespace tint::hlsl::writer {
-
-/// This transforms replaces assignment to dynamically-indexed fixed-size arrays
-/// in structs on shader-local variables with code that copies the arrays to a
-/// temporary local variable, assigns to the local variable, and copies the
-/// array back. This is to work around FXC's compilation failure for these cases
-/// (see crbug.com/tint/1206).
-///
-/// @note Depends on the following transforms to have been run first:
-/// * SimplifyPointers
-class LocalizeStructArrayAssignment final
- : public Castable<LocalizeStructArrayAssignment, ast::transform::Transform> {
- public:
- /// Constructor
- LocalizeStructArrayAssignment();
-
- /// Destructor
- ~LocalizeStructArrayAssignment() override;
-
- /// @copydoc ast::transform::Transform::Apply
- ApplyResult Apply(const Program& program,
- const ast::transform::DataMap& inputs,
- ast::transform::DataMap& outputs) const override;
-
- private:
- struct State;
-};
-
-} // namespace tint::hlsl::writer
-
-#endif // SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_LOCALIZE_STRUCT_ARRAY_ASSIGNMENT_H_
diff --git a/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment_test.cc b/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment_test.cc
deleted file mode 100644
index c6a6f6b..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment_test.cc
+++ /dev/null
@@ -1,1009 +0,0 @@
-// Copyright 2021 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/hlsl/writer/ast_raise/localize_struct_array_assignment.h"
-#include "src/tint/lang/wgsl/ast/transform/simplify_pointers.h"
-#include "src/tint/lang/wgsl/ast/transform/unshadow.h"
-
-#include "src/tint/lang/wgsl/ast/transform/helper_test.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using LocalizeStructArrayAssignmentTest = ast::transform::TransformTest;
-using Unshadow = ast::transform::Unshadow;
-using SimplifyPointers = ast::transform::SimplifyPointers;
-
-TEST_F(LocalizeStructArrayAssignmentTest, EmptyModule) {
- auto* src = R"()";
- EXPECT_FALSE(ShouldRun<LocalizeStructArrayAssignment>(src));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, StructArray) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-};
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- s1.a1[uniforms.i] = v;
-}
-)";
-
- auto* expect = R"(
-struct Uniforms {
- i : u32,
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- {
- let tint_symbol = &(s1.a1);
- var tint_symbol_1 = *(tint_symbol);
- tint_symbol_1[uniforms.i] = v;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, StructArray_OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- s1.a1[uniforms.i] = v;
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct Uniforms {
- i : u32,
-};
-)";
-
- auto* expect = R"(
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- {
- let tint_symbol = &(s1.a1);
- var tint_symbol_1 = *(tint_symbol);
- tint_symbol_1[uniforms.i] = v;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct Uniforms {
- i : u32,
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, StructStructArray) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct S1 {
- a : array<InnerS, 8>,
-};
-
-struct OuterS {
- s2 : S1,
-};
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- s1.s2.a[uniforms.i] = v;
-}
-)";
-
- auto* expect = R"(
-struct Uniforms {
- i : u32,
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct S1 {
- a : array<InnerS, 8>,
-}
-
-struct OuterS {
- s2 : S1,
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- {
- let tint_symbol = &(s1.s2.a);
- var tint_symbol_1 = *(tint_symbol);
- tint_symbol_1[uniforms.i] = v;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, StructStructArray_OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- s1.s2.a[uniforms.i] = v;
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-struct OuterS {
- s2 : S1,
-};
-
-struct S1 {
- a : array<InnerS, 8>,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct Uniforms {
- i : u32,
-};
-)";
-
- auto* expect = R"(
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- {
- let tint_symbol = &(s1.s2.a);
- var tint_symbol_1 = *(tint_symbol);
- tint_symbol_1[uniforms.i] = v;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-struct OuterS {
- s2 : S1,
-}
-
-struct S1 {
- a : array<InnerS, 8>,
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct Uniforms {
- i : u32,
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, StructArrayArray) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
- j : u32,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct OuterS {
- a1 : array<array<InnerS, 8>, 8>,
-};
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- s1.a1[uniforms.i][uniforms.j] = v;
-}
-)";
-
- auto* expect = R"(
-struct Uniforms {
- i : u32,
- j : u32,
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct OuterS {
- a1 : array<array<InnerS, 8>, 8>,
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- {
- let tint_symbol = &(s1.a1);
- var tint_symbol_1 = *(tint_symbol);
- tint_symbol_1[uniforms.i][uniforms.j] = v;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, StructArrayStruct) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct S1 {
- s2 : InnerS,
-};
-
-struct OuterS {
- a1 : array<S1, 8>,
-};
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- s1.a1[uniforms.i].s2 = v;
-}
-)";
-
- auto* expect = R"(
-struct Uniforms {
- i : u32,
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct S1 {
- s2 : InnerS,
-}
-
-struct OuterS {
- a1 : array<S1, 8>,
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- {
- let tint_symbol = &(s1.a1);
- var tint_symbol_1 = *(tint_symbol);
- tint_symbol_1[uniforms.i].s2 = v;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, StructArrayStructArray) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
- j : u32,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct S1 {
- a2 : array<InnerS, 8>,
-};
-
-struct OuterS {
- a1 : array<S1, 8>,
-};
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s : OuterS;
- s.a1[uniforms.i].a2[uniforms.j] = v;
-}
-)";
-
- auto* expect = R"(
-struct Uniforms {
- i : u32,
- j : u32,
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct S1 {
- a2 : array<InnerS, 8>,
-}
-
-struct OuterS {
- a1 : array<S1, 8>,
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s : OuterS;
- {
- let tint_symbol = &(s.a1);
- var tint_symbol_1 = *(tint_symbol);
- let tint_symbol_2 = &(tint_symbol_1[uniforms.i].a2);
- var tint_symbol_3 = *(tint_symbol_2);
- tint_symbol_3[uniforms.j] = v;
- *(tint_symbol_2) = tint_symbol_3;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, IndexingWithSideEffectFunc) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
- j : u32,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct S1 {
- a2 : array<InnerS, 8>,
-};
-
-struct OuterS {
- a1 : array<S1, 8>,
-};
-
-var<private> nextIndex : u32;
-fn getNextIndex() -> u32 {
- nextIndex = nextIndex + 1u;
- return nextIndex;
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s : OuterS;
- s.a1[getNextIndex()].a2[uniforms.j] = v;
-}
-)";
-
- auto* expect = R"(
-struct Uniforms {
- i : u32,
- j : u32,
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct S1 {
- a2 : array<InnerS, 8>,
-}
-
-struct OuterS {
- a1 : array<S1, 8>,
-}
-
-var<private> nextIndex : u32;
-
-fn getNextIndex() -> u32 {
- nextIndex = (nextIndex + 1u);
- return nextIndex;
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s : OuterS;
- {
- let tint_symbol = &(s.a1);
- var tint_symbol_1 = *(tint_symbol);
- let tint_symbol_2 = &(tint_symbol_1[getNextIndex()].a2);
- var tint_symbol_3 = *(tint_symbol_2);
- tint_symbol_3[uniforms.j] = v;
- *(tint_symbol_2) = tint_symbol_3;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, IndexingWithSideEffectFunc_OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s : OuterS;
- s.a1[getNextIndex()].a2[uniforms.j] = v;
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-struct Uniforms {
- i : u32,
- j : u32,
-};
-
-var<private> nextIndex : u32;
-fn getNextIndex() -> u32 {
- nextIndex = nextIndex + 1u;
- return nextIndex;
-}
-
-struct OuterS {
- a1 : array<S1, 8>,
-};
-
-struct S1 {
- a2 : array<InnerS, 8>,
-};
-
-struct InnerS {
- v : i32,
-};
-)";
-
- auto* expect = R"(
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s : OuterS;
- {
- let tint_symbol = &(s.a1);
- var tint_symbol_1 = *(tint_symbol);
- let tint_symbol_2 = &(tint_symbol_1[getNextIndex()].a2);
- var tint_symbol_3 = *(tint_symbol_2);
- tint_symbol_3[uniforms.j] = v;
- *(tint_symbol_2) = tint_symbol_3;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-struct Uniforms {
- i : u32,
- j : u32,
-}
-
-var<private> nextIndex : u32;
-
-fn getNextIndex() -> u32 {
- nextIndex = (nextIndex + 1u);
- return nextIndex;
-}
-
-struct OuterS {
- a1 : array<S1, 8>,
-}
-
-struct S1 {
- a2 : array<InnerS, 8>,
-}
-
-struct InnerS {
- v : i32,
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, ViaPointerArg) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
-};
-struct InnerS {
- v : i32,
-};
-struct OuterS {
- a1 : array<InnerS, 8>,
-};
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-fn f(p : ptr<function, OuterS>) {
- var v : InnerS;
- (*p).a1[uniforms.i] = v;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var s1 : OuterS;
- f(&s1);
-}
-)";
-
- auto* expect = R"(
-struct Uniforms {
- i : u32,
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-fn f(p : ptr<function, OuterS>) {
- var v : InnerS;
- {
- let tint_symbol = &((*(p)).a1);
- var tint_symbol_1 = *(tint_symbol);
- tint_symbol_1[uniforms.i] = v;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var s1 : OuterS;
- f(&(s1));
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, ViaPointerArg_PointerDot) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
-};
-struct InnerS {
- v : i32,
-};
-struct OuterS {
- a1 : array<InnerS, 8>,
-};
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-fn f(p : ptr<function, OuterS>) {
- var v : InnerS;
- p.a1[uniforms.i] = v;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var s1 : OuterS;
- f(&s1);
-}
-)";
-
- auto* expect = R"(
-struct Uniforms {
- i : u32,
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-fn f(p : ptr<function, OuterS>) {
- var v : InnerS;
- {
- let tint_symbol = &((*(p)).a1);
- var tint_symbol_1 = *(tint_symbol);
- tint_symbol_1[uniforms.i] = v;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var s1 : OuterS;
- f(&(s1));
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, ViaPointerArg_OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main() {
- var s1 : OuterS;
- f(&s1);
-}
-
-fn f(p : ptr<function, OuterS>) {
- var v : InnerS;
- (*p).a1[uniforms.i] = v;
-}
-
-struct InnerS {
- v : i32,
-};
-struct OuterS {
- a1 : array<InnerS, 8>,
-};
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-struct Uniforms {
- i : u32,
-};
-)";
-
- auto* expect = R"(
-@compute @workgroup_size(1)
-fn main() {
- var s1 : OuterS;
- f(&(s1));
-}
-
-fn f(p : ptr<function, OuterS>) {
- var v : InnerS;
- {
- let tint_symbol = &((*(p)).a1);
- var tint_symbol_1 = *(tint_symbol);
- tint_symbol_1[uniforms.i] = v;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-struct Uniforms {
- i : u32,
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, ViaPointerVar) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-};
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-fn f(p : ptr<function, InnerS>, v : InnerS) {
- *(p) = v;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- let p = &(s1.a1[uniforms.i]);
- *(p) = v;
-}
-)";
-
- auto* expect = R"(
-struct Uniforms {
- i : u32,
-}
-
-struct InnerS {
- v : i32,
-}
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-fn f(p : ptr<function, InnerS>, v : InnerS) {
- *(p) = v;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : OuterS;
- let p_save = uniforms.i;
- {
- let tint_symbol = &(s1.a1);
- var tint_symbol_1 = *(tint_symbol);
- tint_symbol_1[p_save] = v;
- *(tint_symbol) = tint_symbol_1;
- }
-}
-)";
-
- auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, VectorAssignment) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
-}
-
-struct OuterS {
- a1 : array<u32, 8>,
-}
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-fn f(i : u32) -> u32 {
- return (i + 1u);
-}
-
-@compute @workgroup_size(1)
-fn main() {
- var s1 : OuterS;
- var v : vec3<f32>;
- v[s1.a1[uniforms.i]] = 1.0;
- v[f(s1.a1[uniforms.i])] = 1.0;
-}
-)";
-
- // Transform does nothing here as we're not actually assigning to the array in
- // the struct.
- EXPECT_FALSE(ShouldRun<LocalizeStructArrayAssignment>(src));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, ArrayStructArray) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-};
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : array<OuterS, 2>;
- s1[uniforms.i].a1[uniforms.i] = v;
-}
-)";
-
- // Transform does nothing as the struct-of-array is in an array, which FXC has no problem with.
- EXPECT_FALSE(ShouldRun<LocalizeStructArrayAssignment>(src));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, ArrayStructArray_ViaPointerDerefIndex) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-};
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : array<OuterS, 2>;
- let p = &s1;
- (*p)[uniforms.i].a1[uniforms.i] = v;
-}
-)";
-
- // Transform does nothing as the struct-of-array is in an array, which FXC has no problem with.
- EXPECT_FALSE(ShouldRun<LocalizeStructArrayAssignment>(src));
-}
-
-TEST_F(LocalizeStructArrayAssignmentTest, ArrayStructArray_ViaPointerIndex) {
- auto* src = R"(
-struct Uniforms {
- i : u32,
-};
-
-struct InnerS {
- v : i32,
-};
-
-struct OuterS {
- a1 : array<InnerS, 8>,
-};
-
-@group(1) @binding(4) var<uniform> uniforms : Uniforms;
-
-@compute @workgroup_size(1)
-fn main() {
- var v : InnerS;
- var s1 : array<OuterS, 2>;
- let p = &s1;
- p[uniforms.i].a1[uniforms.i] = v;
-}
-)";
-
- // Transform does nothing as the struct-of-array is in an array, which FXC has no problem with.
- EXPECT_FALSE(ShouldRun<LocalizeStructArrayAssignment>(src));
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc b/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc
deleted file mode 100644
index 161dad2..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2021 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/hlsl/writer/ast_raise/num_workgroups_from_uniform.h"
-
-#include <memory>
-#include <string>
-#include <unordered_set>
-#include <utility>
-
-#include "src/tint/lang/core/builtin_value.h"
-#include "src/tint/lang/core/fluent_types.h"
-#include "src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.h"
-#include "src/tint/lang/wgsl/program/clone_context.h"
-#include "src/tint/lang/wgsl/program/program_builder.h"
-#include "src/tint/lang/wgsl/resolver/resolve.h"
-#include "src/tint/lang/wgsl/sem/function.h"
-#include "src/tint/utils/math/hash.h"
-
-using namespace tint::core::fluent_types; // NOLINT
-
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::NumWorkgroupsFromUniform);
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::NumWorkgroupsFromUniform::Config);
-
-namespace tint::hlsl::writer {
-namespace {
-
-bool ShouldRun(const Program& program) {
- for (auto* node : program.ASTNodes().Objects()) {
- if (auto* attr = node->As<ast::BuiltinAttribute>()) {
- if (attr->builtin == core::BuiltinValue::kNumWorkgroups) {
- return true;
- }
- }
- }
- return false;
-}
-
-/// Accessor describes the identifiers used in a member accessor that is being
-/// used to retrieve the num_workgroups builtin from a parameter.
-struct Accessor {
- Symbol param;
- Symbol member;
-
- /// Equality operator
- bool operator==(const Accessor& other) const {
- return param == other.param && member == other.member;
- }
- /// Hash function
- struct Hasher {
- size_t operator()(const Accessor& a) const { return Hash(a.param, a.member); }
- };
-};
-
-} // namespace
-
-NumWorkgroupsFromUniform::NumWorkgroupsFromUniform() = default;
-NumWorkgroupsFromUniform::~NumWorkgroupsFromUniform() = default;
-
-ast::transform::Transform::ApplyResult NumWorkgroupsFromUniform::Apply(
- const Program& src,
- const ast::transform::DataMap& inputs,
- ast::transform::DataMap&) const {
- ProgramBuilder b;
- program::CloneContext ctx{&b, &src, /* auto_clone_symbols */ true};
-
- auto* cfg = inputs.Get<Config>();
- if (cfg == nullptr) {
- b.Diagnostics().AddError(Source{}) << "missing transform data for " << TypeInfo().name;
- return resolver::Resolve(b);
- }
-
- if (!ShouldRun(src)) {
- return SkipTransform;
- }
-
- const char* kNumWorkgroupsMemberName = "num_workgroups";
-
- // Find all entry point parameters that declare the num_workgroups builtin.
- std::unordered_set<Accessor, Accessor::Hasher> to_replace;
- for (auto* func : src.AST().Functions()) {
- // num_workgroups is only valid for compute stages.
- if (func->PipelineStage() != ast::PipelineStage::kCompute) {
- continue;
- }
-
- for (auto* param : src.Sem().Get(func)->Parameters()) {
- // Because the CanonicalizeEntryPointIO transform has been run, builtins
- // will only appear as struct members.
- auto* str = param->Type()->As<sem::Struct>();
- if (!str) {
- continue;
- }
-
- for (auto* member : str->Members()) {
- if (member->Attributes().builtin != core::BuiltinValue::kNumWorkgroups) {
- continue;
- }
-
- // Capture the symbols that would be used to access this member, which
- // we will replace later. We currently have no way to get from the
- // parameter directly to the member accessor expressions that use it.
- to_replace.insert({param->Declaration()->name->symbol, member->Name()});
-
- // Remove the struct member.
- // The CanonicalizeEntryPointIO transform will have generated this
- // struct uniquely for this particular entry point, so we know that
- // there will be no other uses of this struct in the module and that we
- // can safely modify it here.
- ctx.Remove(str->Declaration()->members, member->Declaration());
-
- // If this is the only member, remove the struct and parameter too.
- if (str->Members().Length() == 1) {
- ctx.Remove(func->params, param->Declaration());
- ctx.Remove(src.AST().GlobalDeclarations(), str->Declaration());
- }
- }
- }
- }
-
- // Get (or create, on first call) the uniform buffer that will receive the
- // number of workgroups.
- const ast::Variable* num_workgroups_ubo = nullptr;
- auto get_ubo = [&] {
- if (!num_workgroups_ubo) {
- auto* num_workgroups_struct =
- b.Structure(b.Sym(), tint::Vector{
- b.Member(kNumWorkgroupsMemberName, b.ty.vec3(b.ty.u32())),
- });
-
- uint32_t group, binding;
- if (cfg->ubo_binding.has_value()) {
- // If cfg->ubo_binding holds a value, use the specified binding point.
- group = cfg->ubo_binding->group;
- binding = cfg->ubo_binding->binding;
- } else {
- // If cfg->ubo_binding holds no value, use the binding 0 of the largest used group
- // plus 1, or group 0 if no resource bound.
- group = 0;
-
- for (auto* global : src.AST().GlobalVariables()) {
- auto* global_sem = src.Sem().Get<sem::GlobalVariable>(global);
- if (auto bp = global_sem->Attributes().binding_point) {
- if (bp->group >= group) {
- group = bp->group + 1;
- }
- }
- }
-
- binding = 0;
- }
-
- num_workgroups_ubo =
- b.GlobalVar(b.Sym(), b.ty.Of(num_workgroups_struct), core::AddressSpace::kUniform,
- b.Group(AInt(group)), b.Binding(AInt(binding)));
- }
- return num_workgroups_ubo;
- };
-
- // Now replace all the places where the builtins are accessed with the value
- // loaded from the uniform buffer.
- for (auto* node : src.ASTNodes().Objects()) {
- auto* accessor = node->As<ast::MemberAccessorExpression>();
- if (!accessor) {
- continue;
- }
- auto* ident = accessor->object->As<ast::IdentifierExpression>();
- if (!ident) {
- continue;
- }
-
- if (to_replace.count({ident->identifier->symbol, accessor->member->symbol}) != 0u) {
- ctx.Replace(accessor,
- b.MemberAccessor(get_ubo()->name->symbol, kNumWorkgroupsMemberName));
- }
- }
-
- ctx.Clone();
- return resolver::Resolve(b);
-}
-
-NumWorkgroupsFromUniform::Config::Config(std::optional<BindingPoint> ubo_bp)
- : ubo_binding(ubo_bp) {}
-NumWorkgroupsFromUniform::Config::Config(const Config&) = default;
-NumWorkgroupsFromUniform::Config::~Config() = default;
-
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.h b/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.h
deleted file mode 100644
index eb5983a..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2021 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_LANG_HLSL_WRITER_AST_RAISE_NUM_WORKGROUPS_FROM_UNIFORM_H_
-#define SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_NUM_WORKGROUPS_FROM_UNIFORM_H_
-
-#include <optional>
-
-#include "src/tint/api/common/binding_point.h"
-#include "src/tint/lang/wgsl/ast/transform/transform.h"
-
-namespace tint::hlsl::writer {
-
-/// NumWorkgroupsFromUniform is a transform that implements the `num_workgroups`
-/// builtin by loading it from a uniform buffer.
-///
-/// The generated uniform buffer will have the form:
-/// ```
-/// struct num_workgroups_struct {
-/// num_workgroups : vec3<u32>;
-/// };
-///
-/// @group(0) @binding(0)
-/// var<uniform> num_workgroups_ubo : num_workgroups_struct;
-/// ```
-/// The binding group and number used for this uniform buffer is provided via
-/// the `Config` transform input.
-///
-/// @note Depends on the following transforms to have been run first:
-/// * CanonicalizeEntryPointIO
-class NumWorkgroupsFromUniform final
- : public Castable<NumWorkgroupsFromUniform, ast::transform::Transform> {
- public:
- /// Constructor
- NumWorkgroupsFromUniform();
- /// Destructor
- ~NumWorkgroupsFromUniform() override;
-
- /// Configuration options for the NumWorkgroupsFromUniform transform.
- struct Config final : public Castable<Config, ast::transform::Data> {
- /// Constructor
- /// @param ubo_bp the binding point to use for the generated uniform buffer. If ubo_bp
- /// contains no value, a free binding point will be used to ensure the generated program is
- /// valid. Specifically, binding 0 of the largest used group plus 1 is used if at least one
- /// resource is bound, otherwise group 0 binding 0 is used.
- explicit Config(std::optional<BindingPoint> ubo_bp);
-
- /// Copy constructor
- Config(const Config&);
-
- /// Destructor
- ~Config() override;
-
- /// The binding point to use for the generated uniform buffer. If ubo_bp contains no value,
- /// a free binding point will be used. Specifically, binding 0 of the largest used group
- /// plus 1 is used if at least one resource is bound, otherwise group 0 binding 0 is used.
- std::optional<BindingPoint> ubo_binding;
- };
-
- /// @copydoc ast::transform::Transform::Apply
- ApplyResult Apply(const Program& program,
- const ast::transform::DataMap& inputs,
- ast::transform::DataMap& outputs) const override;
-};
-
-} // namespace tint::hlsl::writer
-
-#endif // SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_NUM_WORKGROUPS_FROM_UNIFORM_H_
diff --git a/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform_test.cc b/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform_test.cc
deleted file mode 100644
index ca580c0..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform_test.cc
+++ /dev/null
@@ -1,814 +0,0 @@
-// Copyright 2021 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/hlsl/writer/ast_raise/num_workgroups_from_uniform.h"
-
-#include <utility>
-
-#include "src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.h"
-#include "src/tint/lang/wgsl/ast/transform/helper_test.h"
-#include "src/tint/lang/wgsl/ast/transform/unshadow.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using NumWorkgroupsFromUniformTest = ast::transform::TransformTest;
-using CanonicalizeEntryPointIO = ast::transform::CanonicalizeEntryPointIO;
-using Unshadow = ast::transform::Unshadow;
-
-TEST_F(NumWorkgroupsFromUniformTest, ShouldRunEmptyModule) {
- auto* src = R"()";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- EXPECT_FALSE(ShouldRun<NumWorkgroupsFromUniform>(src, data));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, ShouldRunHasNumWorkgroups) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main(@builtin(num_workgroups) num_wgs : vec3<u32>) {
-}
-)";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- EXPECT_TRUE(ShouldRun<NumWorkgroupsFromUniform>(src, data));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, Error_MissingTransformData) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main(@builtin(num_workgroups) num_wgs : vec3<u32>) {
-}
-)";
-
- auto* expect = "error: missing transform data for tint::hlsl::writer::NumWorkgroupsFromUniform";
-
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, Basic) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main(@builtin(num_workgroups) num_wgs : vec3<u32>) {
- let groups_x = num_wgs.x;
- let groups_y = num_wgs.y;
- let groups_z = num_wgs.z;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol_2 {
- num_workgroups : vec3<u32>,
-}
-
-@group(0) @binding(30) var<uniform> tint_symbol_3 : tint_symbol_2;
-
-fn main_inner(num_wgs : vec3<u32>) {
- let groups_x = num_wgs.x;
- let groups_y = num_wgs.y;
- let groups_z = num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- main_inner(tint_symbol_3.num_workgroups);
-}
-)";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, Basic_VarCopy) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main(@builtin(num_workgroups) num_wgs : vec3<u32>) {
- var a = num_wgs;
- let groups_x = a.x;
- let groups_y = a.y;
- let groups_z = a.z;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol_2 {
- num_workgroups : vec3<u32>,
-}
-
-@group(0) @binding(30) var<uniform> tint_symbol_3 : tint_symbol_2;
-
-fn main_inner(num_wgs : vec3<u32>) {
- var a = num_wgs;
- let groups_x = a.x;
- let groups_y = a.y;
- let groups_z = a.z;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- main_inner(tint_symbol_3.num_workgroups);
-}
-)";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, Basic_VarCopy_ViaPointerDerefDot) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main(@builtin(num_workgroups) num_wgs : vec3<u32>) {
- var a = num_wgs;
- let p = &a;
- let groups_x = (*p).x;
- let groups_y = (*p).y;
- let groups_z = (*p).z;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol_2 {
- num_workgroups : vec3<u32>,
-}
-
-@group(0) @binding(30) var<uniform> tint_symbol_3 : tint_symbol_2;
-
-fn main_inner(num_wgs : vec3<u32>) {
- var a = num_wgs;
- let p = &(a);
- let groups_x = (*(p)).x;
- let groups_y = (*(p)).y;
- let groups_z = (*(p)).z;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- main_inner(tint_symbol_3.num_workgroups);
-}
-)";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, Basic_VarCopy_ViaPointerDot) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main(@builtin(num_workgroups) num_wgs : vec3<u32>) {
- var a = num_wgs;
- let p = &a;
- let groups_x = p.x;
- let groups_y = p.y;
- let groups_z = p.z;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol_2 {
- num_workgroups : vec3<u32>,
-}
-
-@group(0) @binding(30) var<uniform> tint_symbol_3 : tint_symbol_2;
-
-fn main_inner(num_wgs : vec3<u32>) {
- var a = num_wgs;
- let p = &(a);
- let groups_x = p.x;
- let groups_y = p.y;
- let groups_z = p.z;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- main_inner(tint_symbol_3.num_workgroups);
-}
-)";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, StructOnlyMember) {
- auto* src = R"(
-struct Builtins {
- @builtin(num_workgroups) num_wgs : vec3<u32>,
-};
-
-@compute @workgroup_size(1)
-fn main(in : Builtins) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol_2 {
- num_workgroups : vec3<u32>,
-}
-
-@group(0) @binding(30) var<uniform> tint_symbol_3 : tint_symbol_2;
-
-struct Builtins {
- num_wgs : vec3<u32>,
-}
-
-fn main_inner(in : Builtins) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- main_inner(Builtins(tint_symbol_3.num_workgroups));
-}
-)";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, StructOnlyMember_OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main(in : Builtins) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-struct Builtins {
- @builtin(num_workgroups) num_wgs : vec3<u32>,
-};
-)";
-
- auto* expect = R"(
-struct tint_symbol_2 {
- num_workgroups : vec3<u32>,
-}
-
-@group(0) @binding(30) var<uniform> tint_symbol_3 : tint_symbol_2;
-
-fn main_inner(in : Builtins) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main() {
- main_inner(Builtins(tint_symbol_3.num_workgroups));
-}
-
-struct Builtins {
- num_wgs : vec3<u32>,
-}
-)";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, StructMultipleMembers) {
- auto* src = R"(
-struct Builtins {
- @builtin(global_invocation_id) gid : vec3<u32>,
- @builtin(num_workgroups) num_wgs : vec3<u32>,
- @builtin(workgroup_id) wgid : vec3<u32>,
-};
-
-@compute @workgroup_size(1)
-fn main(in : Builtins) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol_2 {
- num_workgroups : vec3<u32>,
-}
-
-@group(0) @binding(30) var<uniform> tint_symbol_3 : tint_symbol_2;
-
-struct Builtins {
- gid : vec3<u32>,
- num_wgs : vec3<u32>,
- wgid : vec3<u32>,
-}
-
-struct tint_symbol_1 {
- @builtin(global_invocation_id)
- gid : vec3<u32>,
- @builtin(workgroup_id)
- wgid : vec3<u32>,
-}
-
-fn main_inner(in : Builtins) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main(tint_symbol : tint_symbol_1) {
- main_inner(Builtins(tint_symbol.gid, tint_symbol_3.num_workgroups, tint_symbol.wgid));
-}
-)";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, StructMultipleMembers_OutOfOrder) {
- auto* src = R"(
-@compute @workgroup_size(1)
-fn main(in : Builtins) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-struct Builtins {
- @builtin(global_invocation_id) gid : vec3<u32>,
- @builtin(num_workgroups) num_wgs : vec3<u32>,
- @builtin(workgroup_id) wgid : vec3<u32>,
-};
-
-)";
-
- auto* expect = R"(
-struct tint_symbol_2 {
- num_workgroups : vec3<u32>,
-}
-
-@group(0) @binding(30) var<uniform> tint_symbol_3 : tint_symbol_2;
-
-struct tint_symbol_1 {
- @builtin(global_invocation_id)
- gid : vec3<u32>,
- @builtin(workgroup_id)
- wgid : vec3<u32>,
-}
-
-fn main_inner(in : Builtins) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main(tint_symbol : tint_symbol_1) {
- main_inner(Builtins(tint_symbol.gid, tint_symbol_3.num_workgroups, tint_symbol.wgid));
-}
-
-struct Builtins {
- gid : vec3<u32>,
- num_wgs : vec3<u32>,
- wgid : vec3<u32>,
-}
-)";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, MultipleEntryPoints) {
- auto* src = R"(
-struct Builtins1 {
- @builtin(num_workgroups) num_wgs : vec3<u32>,
-};
-
-struct Builtins2 {
- @builtin(global_invocation_id) gid : vec3<u32>,
- @builtin(num_workgroups) num_wgs : vec3<u32>,
- @builtin(workgroup_id) wgid : vec3<u32>,
-};
-
-@compute @workgroup_size(1)
-fn main1(in : Builtins1) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main2(in : Builtins2) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main3(@builtin(num_workgroups) num_wgs : vec3<u32>) {
- let groups_x = num_wgs.x;
- let groups_y = num_wgs.y;
- let groups_z = num_wgs.z;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol_6 {
- num_workgroups : vec3<u32>,
-}
-
-@group(0) @binding(30) var<uniform> tint_symbol_7 : tint_symbol_6;
-
-struct Builtins1 {
- num_wgs : vec3<u32>,
-}
-
-struct Builtins2 {
- gid : vec3<u32>,
- num_wgs : vec3<u32>,
- wgid : vec3<u32>,
-}
-
-fn main1_inner(in : Builtins1) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main1() {
- main1_inner(Builtins1(tint_symbol_7.num_workgroups));
-}
-
-struct tint_symbol_3 {
- @builtin(global_invocation_id)
- gid : vec3<u32>,
- @builtin(workgroup_id)
- wgid : vec3<u32>,
-}
-
-fn main2_inner(in : Builtins2) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main2(tint_symbol_2 : tint_symbol_3) {
- main2_inner(Builtins2(tint_symbol_2.gid, tint_symbol_7.num_workgroups, tint_symbol_2.wgid));
-}
-
-fn main3_inner(num_wgs : vec3<u32>) {
- let groups_x = num_wgs.x;
- let groups_y = num_wgs.y;
- let groups_z = num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main3() {
- main3_inner(tint_symbol_7.num_workgroups);
-}
-)";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(NumWorkgroupsFromUniformTest, NoUsages) {
- auto* src = R"(
-struct Builtins {
- @builtin(global_invocation_id) gid : vec3<u32>,
- @builtin(workgroup_id) wgid : vec3<u32>,
-};
-
-@compute @workgroup_size(1)
-fn main(in : Builtins) {
-}
-)";
-
- auto* expect = R"(
-struct Builtins {
- gid : vec3<u32>,
- wgid : vec3<u32>,
-}
-
-struct tint_symbol_1 {
- @builtin(global_invocation_id)
- gid : vec3<u32>,
- @builtin(workgroup_id)
- wgid : vec3<u32>,
-}
-
-fn main_inner(in : Builtins) {
-}
-
-@compute @workgroup_size(1)
-fn main(tint_symbol : tint_symbol_1) {
- main_inner(Builtins(tint_symbol.gid, tint_symbol.wgid));
-}
-)";
-
- ast::transform::DataMap data;
- data.Add<NumWorkgroupsFromUniform::Config>(BindingPoint{0, 30u});
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-// Test that group 0 binding 0 is used if no bound resource in the program and binding point is not
-// specified in NumWorkgroupsFromUniform::Config.
-TEST_F(NumWorkgroupsFromUniformTest, UnspecifiedBindingPoint_NoResourceBound) {
- auto* src = R"(
-struct Builtins1 {
- @builtin(num_workgroups) num_wgs : vec3<u32>,
-};
-
-struct Builtins2 {
- @builtin(global_invocation_id) gid : vec3<u32>,
- @builtin(num_workgroups) num_wgs : vec3<u32>,
- @builtin(workgroup_id) wgid : vec3<u32>,
-};
-
-@compute @workgroup_size(1)
-fn main1(in : Builtins1) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main2(in : Builtins2) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main3(@builtin(num_workgroups) num_wgs : vec3<u32>) {
- let groups_x = num_wgs.x;
- let groups_y = num_wgs.y;
- let groups_z = num_wgs.z;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol_6 {
- num_workgroups : vec3<u32>,
-}
-
-@group(0) @binding(0) var<uniform> tint_symbol_7 : tint_symbol_6;
-
-struct Builtins1 {
- num_wgs : vec3<u32>,
-}
-
-struct Builtins2 {
- gid : vec3<u32>,
- num_wgs : vec3<u32>,
- wgid : vec3<u32>,
-}
-
-fn main1_inner(in : Builtins1) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main1() {
- main1_inner(Builtins1(tint_symbol_7.num_workgroups));
-}
-
-struct tint_symbol_3 {
- @builtin(global_invocation_id)
- gid : vec3<u32>,
- @builtin(workgroup_id)
- wgid : vec3<u32>,
-}
-
-fn main2_inner(in : Builtins2) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main2(tint_symbol_2 : tint_symbol_3) {
- main2_inner(Builtins2(tint_symbol_2.gid, tint_symbol_7.num_workgroups, tint_symbol_2.wgid));
-}
-
-fn main3_inner(num_wgs : vec3<u32>) {
- let groups_x = num_wgs.x;
- let groups_y = num_wgs.y;
- let groups_z = num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main3() {
- main3_inner(tint_symbol_7.num_workgroups);
-}
-)";
-
- ast::transform::DataMap data;
- // Make binding point unspecified.
- data.Add<NumWorkgroupsFromUniform::Config>(std::nullopt);
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-// Test that binding 0 of the largest used group plus 1 is used if at least one resource is bound in
-// the program and binding point is not specified in NumWorkgroupsFromUniform::Config.
-TEST_F(NumWorkgroupsFromUniformTest, UnspecifiedBindingPoint_MultipleResourceBound) {
- auto* src = R"(
-struct Builtins1 {
- @builtin(num_workgroups) num_wgs : vec3<u32>,
-};
-
-struct Builtins2 {
- @builtin(global_invocation_id) gid : vec3<u32>,
- @builtin(num_workgroups) num_wgs : vec3<u32>,
- @builtin(workgroup_id) wgid : vec3<u32>,
-};
-
-struct S0 {
- @size(4)
- m0 : u32,
- m1 : array<u32>,
-};
-
-struct S1 {
- @size(4)
- m0 : u32,
- m1 : array<u32, 6>,
-};
-
-@group(0) @binding(0) var g2 : texture_2d<f32>;
-@group(1) @binding(0) var g3 : texture_depth_2d;
-@group(1) @binding(1) var g4 : texture_storage_2d<rg32float, write>;
-@group(3) @binding(0) var g5 : texture_depth_cube_array;
-@group(4) @binding(0) var g6 : texture_external;
-
-@group(0) @binding(1) var<storage, read_write> g8 : S0;
-@group(1) @binding(3) var<storage, read> g9 : S0;
-@group(3) @binding(2) var<storage, read_write> g10 : S0;
-
-@compute @workgroup_size(1)
-fn main1(in : Builtins1) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
- g8.m0 = 1u;
-}
-
-@compute @workgroup_size(1)
-fn main2(in : Builtins2) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main3(@builtin(num_workgroups) num_wgs : vec3<u32>) {
- let groups_x = num_wgs.x;
- let groups_y = num_wgs.y;
- let groups_z = num_wgs.z;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol_6 {
- num_workgroups : vec3<u32>,
-}
-
-@group(5) @binding(0) var<uniform> tint_symbol_7 : tint_symbol_6;
-
-struct Builtins1 {
- num_wgs : vec3<u32>,
-}
-
-struct Builtins2 {
- gid : vec3<u32>,
- num_wgs : vec3<u32>,
- wgid : vec3<u32>,
-}
-
-struct S0 {
- @size(4)
- m0 : u32,
- m1 : array<u32>,
-}
-
-struct S1 {
- @size(4)
- m0 : u32,
- m1 : array<u32, 6>,
-}
-
-@group(0) @binding(0) var g2 : texture_2d<f32>;
-
-@group(1) @binding(0) var g3 : texture_depth_2d;
-
-@group(1) @binding(1) var g4 : texture_storage_2d<rg32float, write>;
-
-@group(3) @binding(0) var g5 : texture_depth_cube_array;
-
-@group(4) @binding(0) var g6 : texture_external;
-
-@group(0) @binding(1) var<storage, read_write> g8 : S0;
-
-@group(1) @binding(3) var<storage, read> g9 : S0;
-
-@group(3) @binding(2) var<storage, read_write> g10 : S0;
-
-fn main1_inner(in : Builtins1) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
- g8.m0 = 1u;
-}
-
-@compute @workgroup_size(1)
-fn main1() {
- main1_inner(Builtins1(tint_symbol_7.num_workgroups));
-}
-
-struct tint_symbol_3 {
- @builtin(global_invocation_id)
- gid : vec3<u32>,
- @builtin(workgroup_id)
- wgid : vec3<u32>,
-}
-
-fn main2_inner(in : Builtins2) {
- let groups_x = in.num_wgs.x;
- let groups_y = in.num_wgs.y;
- let groups_z = in.num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main2(tint_symbol_2 : tint_symbol_3) {
- main2_inner(Builtins2(tint_symbol_2.gid, tint_symbol_7.num_workgroups, tint_symbol_2.wgid));
-}
-
-fn main3_inner(num_wgs : vec3<u32>) {
- let groups_x = num_wgs.x;
- let groups_y = num_wgs.y;
- let groups_z = num_wgs.z;
-}
-
-@compute @workgroup_size(1)
-fn main3() {
- main3_inner(tint_symbol_7.num_workgroups);
-}
-)";
-
- ast::transform::DataMap data;
- // Make binding point unspecified.
- data.Add<NumWorkgroupsFromUniform::Config>(std::nullopt);
- auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc b/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc
deleted file mode 100644
index 4f9f515..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc
+++ /dev/null
@@ -1,525 +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.
-
-#include "src/tint/lang/hlsl/writer/ast_raise/pixel_local.h"
-
-#include <string>
-#include <utility>
-
-#include "src/tint/lang/core/fluent_types.h"
-#include "src/tint/lang/wgsl/program/clone_context.h"
-#include "src/tint/lang/wgsl/resolver/resolve.h"
-#include "src/tint/lang/wgsl/sem/function.h"
-#include "src/tint/lang/wgsl/sem/module.h"
-#include "src/tint/lang/wgsl/sem/statement.h"
-#include "src/tint/lang/wgsl/sem/struct.h"
-#include "src/tint/utils/containers/transform.h"
-#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/rtti/switch.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::PixelLocal);
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::PixelLocal::RasterizerOrderedView);
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::PixelLocal::Config);
-
-using namespace tint::core::fluent_types; // NOLINT
-
-namespace tint::hlsl::writer {
-
-/// PIMPL state for the transform
-struct PixelLocal::State {
- /// The source program
- const Program& src;
- /// The semantic information of the source program
- const sem::Info& sem;
- /// The target program builder
- ProgramBuilder b;
- /// The clone context
- program::CloneContext ctx = {&b, &src, /* auto_clone_symbols */ true};
- /// The transform config
- const Config& cfg;
-
- /// Constructor
- /// @param program the source program
- /// @param config the transform config
- State(const Program& program, const Config& config)
- : src(program), sem(program.Sem()), cfg(config) {}
-
- /// Runs the transform
- /// @returns the new program or SkipTransform if the transform is not required
- ApplyResult Run() {
- // If the pixel local extension isn't enabled, then there must be no use of pixel_local
- // variables, and so there's nothing for this transform to do.
- if (!sem.Module()->Extensions().Contains(
- wgsl::Extension::kChromiumExperimentalPixelLocal)) {
- return SkipTransform;
- }
-
- bool made_changes = false;
-
- // Change all module scope `var<pixel_local>` variables to `var<private>`.
- // We need to do this even if the variable is not referenced by the entry point as later
- // stages do not understand the pixel_local address space.
- for (auto* global : src.AST().GlobalVariables()) {
- if (auto* var = global->As<ast::Var>()) {
- if (sem.Get(var)->AddressSpace() == core::AddressSpace::kPixelLocal) {
- // Change the 'var<pixel_local>' to 'var<private>'
- ctx.Replace(var->declared_address_space, b.Expr(core::AddressSpace::kPrivate));
- made_changes = true;
- }
- }
- }
-
- // Find the single entry point
- const sem::Function* entry_point = nullptr;
- for (auto* fn : src.AST().Functions()) {
- if (fn->IsEntryPoint()) {
- if (entry_point != nullptr) {
- TINT_ICE() << "PixelLocal transform requires that the SingleEntryPoint "
- "transform has already been run";
- }
- entry_point = sem.Get(fn);
-
- // Look for a `var<pixel_local>` used by the entry point...
- const tint::sem::GlobalVariable* pixel_local_variable = nullptr;
- for (auto* global : entry_point->TransitivelyReferencedGlobals()) {
- if (global->AddressSpace() == core::AddressSpace::kPixelLocal) {
- pixel_local_variable = global;
- made_changes = true;
- break;
- }
- }
- if (pixel_local_variable == nullptr) {
- continue;
- }
-
- // Obtain struct of the pixel local.
- auto* pixel_local_str =
- pixel_local_variable->Type()->UnwrapRef()->As<sem::Struct>();
- if (auto res =
- TransformEntryPoint(entry_point, pixel_local_variable, pixel_local_str);
- res != Success) {
- b.Diagnostics().Add(res.Failure().reason);
- made_changes = true;
- }
-
- break; // Only a single `var<pixel_local>` can be used by an entry point.
- }
- }
-
- if (!made_changes) {
- return SkipTransform;
- }
-
- ctx.Clone();
- return resolver::Resolve(b);
- }
-
- /// Transforms the entry point @p entry_point to handle the direct or transitive usage of the
- /// `var<pixel_local>` @p pixel_local_var.
- /// @param entry_point the entry point
- /// @param pixel_local_var the `var<pixel_local>`
- /// @param pixel_local_str the struct type of the var
- diag::Result<SuccessType> TransformEntryPoint(const sem::Function* entry_point,
- const sem::GlobalVariable* pixel_local_var,
- const sem::Struct* pixel_local_str) {
- // Wrap the old entry point "fn" into a new entry point where functions to load and store
- // ROV data are called.
- auto* original_entry_point_fn = entry_point->Declaration();
- auto entry_point_name = original_entry_point_fn->name->symbol.Name();
-
- // Remove the @fragment attribute from the entry point
- ctx.Remove(original_entry_point_fn->attributes,
- ast::GetAttribute<ast::StageAttribute>(original_entry_point_fn->attributes));
- // Rename the entry point.
- auto inner_function_name = b.Symbols().New(entry_point_name + "_inner");
- ctx.Replace(original_entry_point_fn->name, b.Ident(inner_function_name));
-
- // Create a new function that wraps the entry point.
- // This function has all the existing entry point parameters and an additional
- // parameter for the input pixel local structure.
- auto new_entry_point_params = ctx.Clone(original_entry_point_fn->params);
-
- // Remove any entry-point attributes from the inner function.
- // This must come after `ctx.Clone(fn->params)` as we want these attributes on the outer
- // function.
- for (auto* param : original_entry_point_fn->params) {
- for (auto* attr : param->attributes) {
- if (attr->IsAnyOf<ast::BuiltinAttribute, ast::LocationAttribute,
- ast::InterpolateAttribute, ast::InvariantAttribute>()) {
- ctx.Remove(param->attributes, attr);
- }
- }
- }
-
- // Declare the ROVs for the members of the pixel local variable and the functions to
- // load data from and store data into the ROVs.
- auto load_rov_function_name = b.Symbols().New("load_from_pixel_local_storage");
- auto store_rov_function_name = b.Symbols().New("store_into_pixel_local_storage");
- if (auto res = DeclareROVsAndLoadStoreFunctions(
- load_rov_function_name, store_rov_function_name,
- pixel_local_var->Declaration()->name->symbol.Name(), pixel_local_str);
- res != Success) {
- return res.Failure();
- }
-
- // Declare new entry point
- Vector<const ast::Statement*, 5> new_entry_point_function_body;
-
- // 1. let `hlsl_sv_position` be `@builtin(position)`
- // Declare `@builtin(position)` in the input parameter of the new entry point if it is not
- // declared in the original entry point.
- auto sv_position_symbol = b.Symbols().New("hlsl_sv_position");
- new_entry_point_function_body.Push(DeclareVariableWithBuiltinPosition(
- new_entry_point_params, sv_position_symbol, entry_point));
-
- // 2. Call `load_from_pixel_local_storage(hlsl_sv_position)`
- new_entry_point_function_body.Push(
- b.CallStmt(b.Call(load_rov_function_name, sv_position_symbol)));
-
- // Declare the inner function
- // Build the arguments to call the inner function
- auto inner_function_call_args = tint::Transform(
- original_entry_point_fn->params, [&](auto* p) { return b.Expr(ctx.Clone(p->name)); });
-
- ast::Type new_entry_point_return_type;
- if (original_entry_point_fn->return_type) {
- // Create a structure to hold the combined flattened result of the entry point with
- // `@location` attribute
- auto new_entry_point_return_struct_name = b.Symbols().New(entry_point_name + "_res");
- Vector<const ast::StructMember*, 8> members;
- // arguments to the final `return` statement in the new entry point
- Vector<const ast::Expression*, 8> new_entry_point_return_value_constructor_args;
-
- auto add_member = [&](const core::type::Type* ty,
- VectorRef<const ast::Attribute*> attrs) {
- members.Push(b.Member("output_" + std::to_string(members.Length()),
- CreateASTTypeFor(ctx, ty), std::move(attrs)));
- };
-
- Symbol inner_function_call_result = b.Symbols().New("result");
- if (auto* str = entry_point->ReturnType()->As<sem::Struct>()) {
- // The entry point returned a structure.
- for (auto* member : str->Members()) {
- auto& member_attrs = member->Declaration()->attributes;
- add_member(member->Type(), ctx.Clone(member_attrs));
- new_entry_point_return_value_constructor_args.Push(
- b.MemberAccessor(inner_function_call_result, ctx.Clone(member->Name())));
- if (auto* location = ast::GetAttribute<ast::LocationAttribute>(member_attrs)) {
- // Remove the @location attribute from the member of the inner function's
- // output structure.
- // Note: This will break other entry points that share the same output
- // structure, however this transform assumes that the SingleEntryPoint
- // transform will have already been run.
- ctx.Remove(member_attrs, location);
- }
- }
- } else {
- // The entry point returned a non-structure
- add_member(entry_point->ReturnType(),
- ctx.Clone(original_entry_point_fn->return_type_attributes));
- new_entry_point_return_value_constructor_args.Push(
- b.Expr(inner_function_call_result));
-
- // Remove the @location from the inner function's return type attributes
- ctx.Remove(original_entry_point_fn->return_type_attributes,
- ast::GetAttribute<ast::LocationAttribute>(
- original_entry_point_fn->return_type_attributes));
- }
-
- // 3. Call inner function and get the return value
- new_entry_point_function_body.Push(
- b.Decl(b.Let(inner_function_call_result,
- b.Call(inner_function_name, std::move(inner_function_call_args)))));
-
- // Declare the output structure
- b.Structure(new_entry_point_return_struct_name, std::move(members));
-
- // 4. Call `store_into_pixel_local_storage(hlsl_sv_position)`
- new_entry_point_function_body.Push(
- b.CallStmt(b.Call(store_rov_function_name, sv_position_symbol)));
-
- // 5. Return the output structure
- new_entry_point_function_body.Push(
- b.Return(b.Call(new_entry_point_return_struct_name,
- std::move(new_entry_point_return_value_constructor_args))));
-
- new_entry_point_return_type = b.ty(new_entry_point_return_struct_name);
- } else {
- // 3. Call inner function without return value
- new_entry_point_function_body.Push(
- b.CallStmt(b.Call(inner_function_name, std::move(inner_function_call_args))));
-
- // 4. Call `store_into_pixel_local_storage(hlsl_sv_position)`
- new_entry_point_function_body.Push(
- b.CallStmt(b.Call(store_rov_function_name, sv_position_symbol)));
-
- new_entry_point_return_type = b.ty.void_();
- }
-
- // Declare the new entry point that calls the inner function
- b.Func(entry_point_name, std::move(new_entry_point_params), new_entry_point_return_type,
- new_entry_point_function_body, Vector{b.Stage(ast::PipelineStage::kFragment)});
- return Success;
- }
-
- /// Add the declarations of all the ROVs as a special type of read-write storage texture that
- /// represent the pixel local variable, the functions to load data from them and store data into
- /// them.
- /// @param load_rov_function_name the name of the funtion that loads the data from the ROVs
- /// @param store_rov_function_name the name of the function that stores the data into the ROVs
- /// @param pixel_local_variable_name the name of the pixel local variable
- /// @param pixel_local_str the struct type of the pixel local variable
- diag::Result<SuccessType> DeclareROVsAndLoadStoreFunctions(
- const Symbol& load_rov_function_name,
- const Symbol& store_rov_function_name,
- const std::string& pixel_local_variable_name,
- const sem::Struct* pixel_local_str) {
- std::string_view load_store_input_name = "my_input";
- Vector load_parameters{b.Param(load_store_input_name, b.ty.vec4<f32>())};
- Vector store_parameters{b.Param(load_store_input_name, b.ty.vec4<f32>())};
-
- // 1 declaration of `rov_texcoord` and at most 4 texture[Load|Store] calls (now the maximum
- // size of PLS is 16)
- Vector<const ast::Statement*, 5> load_body;
- Vector<const ast::Statement*, 5> store_body;
-
- // let rov_texcoord = vec2u(my_input.xy);
- auto rov_texcoord = b.Symbols().New("rov_texcoord");
- load_body.Push(b.Decl(
- b.Let(rov_texcoord, b.Call("vec2u", b.MemberAccessor(load_store_input_name, "xy")))));
- store_body.Push(b.Decl(
- b.Let(rov_texcoord, b.Call("vec2u", b.MemberAccessor(load_store_input_name, "xy")))));
-
- for (auto* member : pixel_local_str->Members()) {
- // Declare the read-write storage texture with RasterizerOrderedView attribute.
- auto member_format = Switch(
- member->Type(), //
- [&](const core::type::U32*) { return core::TexelFormat::kR32Uint; },
- [&](const core::type::I32*) { return core::TexelFormat::kR32Sint; },
- [&](const core::type::F32*) { return core::TexelFormat::kR32Float; },
- TINT_ICE_ON_NO_MATCH);
- auto rov_format = ROVTexelFormat(member->Index());
- if (DAWN_UNLIKELY(rov_format != Success)) {
- return rov_format.Failure();
- }
- auto rov_type = b.ty.storage_texture(core::type::TextureDimension::k2d,
- rov_format.Get(), core::Access::kReadWrite);
- auto rov_symbol_name = b.Symbols().New("pixel_local_" + member->Name().Name());
- b.GlobalVar(rov_symbol_name, rov_type,
- tint::Vector{b.Binding(AInt(ROVRegisterIndex(member->Index()))),
- b.Group(AInt(cfg.rov_group_index)), RasterizerOrderedView()});
-
- // The function body of loading from PLS
- // PLS_Private_Variable.member = textureLoad(pixel_local_member, rov_texcoord).x;
- // Or
- // PLS_Private_Variable.member =
- // bitcast(textureLoad(pixel_local_member, rov_texcoord).x);
- auto pixel_local_var_member_access_in_load_call =
- b.MemberAccessor(pixel_local_variable_name, ctx.Clone(member->Name()));
- auto load_call = b.Call(wgsl::BuiltinFn::kTextureLoad, rov_symbol_name, rov_texcoord);
- auto to_scalar_call = b.MemberAccessor(load_call, "x");
- if (rov_format == member_format) {
- load_body.Push(
- b.Assign(pixel_local_var_member_access_in_load_call, to_scalar_call));
- } else {
- auto member_ast_type = Switch(
- member->Type(), //
- [&](const core::type::U32*) { return b.ty.u32(); },
- [&](const core::type::I32*) { return b.ty.i32(); },
- [&](const core::type::F32*) { return b.ty.f32(); }, //
- TINT_ICE_ON_NO_MATCH);
-
- auto bitcast_to_member_type_call = b.Bitcast(member_ast_type, to_scalar_call);
- load_body.Push(b.Assign(pixel_local_var_member_access_in_load_call,
- bitcast_to_member_type_call));
- }
-
- // The function body of storing data into PLS
- // textureStore(pixel_local_member, rov_texcoord, vec4u(PLS_Private_Variable.member));
- // Or
- // textureStore(
- // pixel_local_member, rov_texcoord, vec4u(bitcast(PLS_Private_Variable.member)));
- std::string rov_pixel_type;
- switch (rov_format.Get()) {
- case core::TexelFormat::kR32Uint:
- rov_pixel_type = "vec4u";
- break;
- case core::TexelFormat::kR32Sint:
- rov_pixel_type = "vec4i";
- break;
- case core::TexelFormat::kR32Float:
- rov_pixel_type = "vec4f";
- break;
- default:
- TINT_UNREACHABLE();
- }
- auto pixel_local_var_member_access_in_store_call =
- b.MemberAccessor(pixel_local_variable_name, ctx.Clone(member->Name()));
- const ast::CallExpression* to_vec4_call = nullptr;
- if (rov_format == member_format) {
- to_vec4_call = b.Call(rov_pixel_type, pixel_local_var_member_access_in_store_call);
- } else {
- ast::Type rov_pixel_ast_type;
- switch (rov_format.Get()) {
- case core::TexelFormat::kR32Uint:
- rov_pixel_ast_type = b.ty.u32();
- break;
- case core::TexelFormat::kR32Sint:
- rov_pixel_ast_type = b.ty.i32();
- break;
- case core::TexelFormat::kR32Float:
- rov_pixel_ast_type = b.ty.f32();
- break;
- default:
- TINT_UNREACHABLE();
- }
- auto bitcast_to_rov_format_call =
- b.Bitcast(rov_pixel_ast_type, pixel_local_var_member_access_in_store_call);
- to_vec4_call = b.Call(rov_pixel_type, bitcast_to_rov_format_call);
- }
- auto store_call =
- b.Call(wgsl::BuiltinFn::kTextureStore, rov_symbol_name, rov_texcoord, to_vec4_call);
- store_body.Push(b.CallStmt(store_call));
- }
-
- b.Func(load_rov_function_name, std::move(load_parameters), b.ty.void_(), load_body);
- b.Func(store_rov_function_name, std::move(store_parameters), b.ty.void_(), store_body);
- return Success;
- }
-
- /// Find and get `@builtin(position)` which is needed for loading and storing data with ROVs
- /// @returns the statement object that initializes `new_entry_point_params` with
- /// `@builtin(position)`.
- /// @param new_entry_point_params the input parameters of the new entry point.
- /// `@builtin(position)` may be added if it is not in `new_entry_point_params`.
- /// @param variable_with_position_symbol the name of the variable that will be initialized with
- /// `@builtin(position)`.
- /// @param entry_point the semantic information of the entry point
- const ast::VariableDeclStatement* DeclareVariableWithBuiltinPosition(
- tint::Vector<const ast::Parameter*, 8>& new_entry_point_params,
- const tint::Symbol& variable_with_position_symbol,
- const sem::Function* entry_point) {
- for (size_t i = 0; i < entry_point->Parameters().Length(); ++i) {
- auto* parameter = entry_point->Parameters()[i];
- // 1. `@builtin(position)` is declared as a member of a structure
- if (auto* struct_type = parameter->Type()->As<sem::Struct>()) {
- for (auto* member : struct_type->Members()) {
- if (member->Attributes().builtin == core::BuiltinValue::kPosition) {
- return b.Decl(b.Let(
- variable_with_position_symbol,
- b.MemberAccessor(new_entry_point_params[i], member->Name().Name())));
- }
- }
- }
- // 2. `@builtin(position)` is declared as an individual input parameter
- if (auto* attribute = ast::GetAttribute<ast::BuiltinAttribute>(
- parameter->Declaration()->attributes)) {
- if (attribute->builtin == core::BuiltinValue::kPosition) {
- return b.Decl(
- b.Let(variable_with_position_symbol, b.Expr(new_entry_point_params[i])));
- }
- }
- }
-
- // 3. `@builtin(position)` is not declared in the input parameters and we should add one
- auto* new_position = b.Param(b.Symbols().New("my_pos"), b.ty.vec4<f32>(),
- Vector{b.Builtin(core::BuiltinValue::kPosition)});
- new_entry_point_params.Push(new_position);
- return b.Decl(b.Let(variable_with_position_symbol, b.Expr(new_position)));
- }
-
- /// @returns a new RasterizerOrderedView attribute
- PixelLocal::RasterizerOrderedView* RasterizerOrderedView() {
- return b.ASTNodes().Create<PixelLocal::RasterizerOrderedView>(b.ID(), b.AllocateNodeID());
- }
-
- /// @returns the register index for the pixel local field with the given index
- /// @param field_index the pixel local field index
- uint32_t ROVRegisterIndex(uint32_t field_index) {
- auto idx = cfg.pls_member_to_rov_reg.Get(field_index);
- if (DAWN_UNLIKELY(!idx)) {
- b.Diagnostics().AddError(Source{})
- << "PixelLocal::Config::attachments missing entry for field " << field_index;
- return 0;
- }
- return *idx;
- }
-
- /// @returns the texel format for the pixel local field with the given index
- /// @param field_index the pixel local field index
- diag::Result<core::TexelFormat> ROVTexelFormat(uint32_t field_index) {
- auto format = cfg.pls_member_to_rov_format.Get(field_index);
- if (DAWN_UNLIKELY(!format)) {
- diag::Diagnostic err;
- err.severity = diag::Severity::Error;
- err.message << "PixelLocal::Config::attachments missing entry for field "
- << field_index;
- return diag::Failure{std::move(err)};
- }
- return *format;
- }
-};
-
-PixelLocal::PixelLocal() = default;
-
-PixelLocal::~PixelLocal() = default;
-
-ast::transform::Transform::ApplyResult PixelLocal::Apply(const Program& src,
- const ast::transform::DataMap& inputs,
- ast::transform::DataMap&) const {
- auto* cfg = inputs.Get<Config>();
- if (!cfg) {
- ProgramBuilder b;
- b.Diagnostics().AddError(Source{}) << "missing transform data for " << TypeInfo().name;
- return resolver::Resolve(b);
- }
-
- return State(src, *cfg).Run();
-}
-
-PixelLocal::Config::Config() = default;
-
-PixelLocal::Config::Config(const Config&) = default;
-
-PixelLocal::Config::~Config() = default;
-
-PixelLocal::RasterizerOrderedView::RasterizerOrderedView(GenerationID pid, ast::NodeID nid)
- : Base(pid, nid, Empty) {}
-
-PixelLocal::RasterizerOrderedView::~RasterizerOrderedView() = default;
-
-std::string PixelLocal::RasterizerOrderedView::InternalName() const {
- return "rov";
-}
-
-const PixelLocal::RasterizerOrderedView* PixelLocal::RasterizerOrderedView::Clone(
- ast::CloneContext& ctx) const {
- return ctx.dst->ASTNodes().Create<RasterizerOrderedView>(ctx.dst->ID(),
- ctx.dst->AllocateNodeID());
-}
-
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_raise/pixel_local.h b/src/tint/lang/hlsl/writer/ast_raise/pixel_local.h
deleted file mode 100644
index 874b039..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/pixel_local.h
+++ /dev/null
@@ -1,116 +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_LANG_HLSL_WRITER_AST_RAISE_PIXEL_LOCAL_H_
-#define SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_PIXEL_LOCAL_H_
-
-#include <string>
-
-#include "src/tint/lang/core/texel_format.h"
-#include "src/tint/lang/wgsl/ast/internal_attribute.h"
-#include "src/tint/lang/wgsl/ast/transform/transform.h"
-
-namespace tint::hlsl::writer {
-
-/// PixelLocal transforms module-scope `var<pixel_local>`s and fragment entry point functions that
-/// use them:
-/// * `var<pixel_local>` will be transformed to `var<private>`, a bunch of read-write storage
-/// textures with a special `RasterizerOrderedView` attribute, a function to read the data from
-/// thes read-write storage textures into the `var<private>` (ROV Reader), and a function to write
-/// the data from the `var<private>` into the read-write storage textures (ROV Writer).
-/// * The entry point function will be wrapped with another function ('outer') that calls the
-/// 'inner' function.
-/// * The outer function will always have `@builtin(position)` in its input parameters.
-/// * The outer function will call the ROV reader before the original entry point function, and call
-/// the ROV writer after the original entry point function.
-/// @note PixelLocal requires that the SingleEntryPoint transform has already been run
-/// TODO(tint:2083): Optimize this in the future by inserting the load as late as possible and the
-/// store as early as possible.
-class PixelLocal final : public Castable<PixelLocal, ast::transform::Transform> {
- public:
- /// Transform configuration options
- struct Config final : public Castable<Config, ast::transform::Data> {
- /// Constructor
- Config();
-
- /// Copy Constructor
- Config(const Config&);
-
- /// Destructor
- ~Config() override;
-
- /// Index of pixel_local structure member index to ROV register
- Hashmap<uint32_t, uint32_t, 8> pls_member_to_rov_reg;
-
- /// Index of pixel_local structure member index to ROV format
- Hashmap<uint32_t, core::TexelFormat, 8> pls_member_to_rov_format;
-
- /// Group index of all ROVs
- uint32_t rov_group_index = 0;
- };
-
- /// RasterizerOrderedView is an InternalAttribute that's used to decorate a read-write storage
- /// texture object.
- class RasterizerOrderedView final
- : public Castable<RasterizerOrderedView, ast::InternalAttribute> {
- public:
- /// Constructor
- /// @param pid the identifier of the program that owns this node
- /// @param nid the unique node identifier
- RasterizerOrderedView(GenerationID pid, ast::NodeID nid);
-
- /// Destructor
- ~RasterizerOrderedView() override;
-
- /// @return a short description of the internal attribute which will be
- /// displayed as `@internal(<name>)`
- std::string InternalName() const override;
-
- /// Performs a deep clone of this object using the program::CloneContext `ctx`.
- /// @param ctx the clone context
- /// @return the newly cloned object
- const RasterizerOrderedView* Clone(ast::CloneContext& ctx) const override;
- };
-
- /// Constructor
- PixelLocal();
-
- /// Destructor
- ~PixelLocal() override;
-
- /// @copydoc ast::transform::Transform::Apply
- ApplyResult Apply(const Program& program,
- const ast::transform::DataMap& inputs,
- ast::transform::DataMap& outputs) const override;
-
- private:
- struct State;
-};
-
-} // namespace tint::hlsl::writer
-
-#endif // SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_PIXEL_LOCAL_H_
diff --git a/src/tint/lang/hlsl/writer/ast_raise/pixel_local_test.cc b/src/tint/lang/hlsl/writer/ast_raise/pixel_local_test.cc
deleted file mode 100644
index f34138a..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/pixel_local_test.cc
+++ /dev/null
@@ -1,1312 +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.
-
-#include <utility>
-
-#include "src/tint/lang/hlsl/writer/ast_raise/pixel_local.h"
-
-#include "src/tint/lang/wgsl/ast/transform/helper_test.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-struct ROVBinding {
- uint32_t field_index;
- uint32_t register_index;
- core::TexelFormat rov_format;
-};
-
-ast::transform::DataMap Bindings(std::initializer_list<ROVBinding> bindings,
- uint32_t groupIndex = 0) {
- PixelLocal::Config cfg;
- cfg.rov_group_index = groupIndex;
- for (auto& binding : bindings) {
- cfg.pls_member_to_rov_reg.Add(binding.field_index, binding.register_index);
- cfg.pls_member_to_rov_format.Add(binding.field_index, binding.rov_format);
- }
- ast::transform::DataMap data;
- data.Add<PixelLocal::Config>(std::move(cfg));
- return data;
-}
-
-using HLSLPixelLocalTest = ast::transform::TransformTest;
-
-TEST_F(HLSLPixelLocalTest, EmptyModule) {
- auto* src = "";
-
- EXPECT_FALSE(ShouldRun<PixelLocal>(src, Bindings({})));
-}
-
-TEST_F(HLSLPixelLocalTest, MissingBindings) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-@fragment
-fn F() -> @location(0) vec4f {
- P.a += 42;
- return vec4f(1, 0, 0, 1);
-}
-)";
-
- auto* expect = R"(error: PixelLocal::Config::attachments missing entry for field 0)";
- ast::transform::DataMap data;
- data.Add<PixelLocal::Config>();
- auto got = Run<PixelLocal>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, UseInEntryPoint_NoPosition) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-@fragment
-fn F() -> @location(0) vec4f {
- P.a += 42;
- return vec4f(1, 0, 0, 1);
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-struct F_res {
- @location(0)
- output_0 : vec4<f32>,
-}
-
-@fragment
-fn F(@builtin(position) my_pos : vec4<f32>) -> F_res {
- let hlsl_sv_position = my_pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- let result = F_inner();
- store_into_pixel_local_storage(hlsl_sv_position);
- return F_res(result);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-fn F_inner() -> vec4f {
- P.a += 42;
- return vec4f(1, 0, 0, 1);
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, UseInEntryPoint_SeparatePosition) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-@fragment
-fn F(@builtin(position) pos : vec4f) -> @location(0) vec4f {
- P.a += 42;
- return pos;
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-struct F_res {
- @location(0)
- output_0 : vec4<f32>,
-}
-
-@fragment
-fn F(@builtin(position) pos : vec4f) -> F_res {
- let hlsl_sv_position = pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- let result = F_inner(pos);
- store_into_pixel_local_storage(hlsl_sv_position);
- return F_res(result);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-fn F_inner(pos : vec4f) -> vec4f {
- P.a += 42;
- return pos;
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, UseInEntryPoint_PositionInStruct) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-struct FragmentInput {
- @location(0) input : vec4f,
- @builtin(position) pos : vec4f,
-}
-
-@fragment
-fn F(fragmentInput : FragmentInput) -> @location(0) vec4f {
- P.a += 42;
- return fragmentInput.input + fragmentInput.pos;
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-struct F_res {
- @location(0)
- output_0 : vec4<f32>,
-}
-
-@fragment
-fn F(fragmentInput : FragmentInput) -> F_res {
- let hlsl_sv_position = fragmentInput.pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- let result = F_inner(fragmentInput);
- store_into_pixel_local_storage(hlsl_sv_position);
- return F_res(result);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-struct FragmentInput {
- @location(0)
- input : vec4f,
- @builtin(position)
- pos : vec4f,
-}
-
-fn F_inner(fragmentInput : FragmentInput) -> vec4f {
- P.a += 42;
- return (fragmentInput.input + fragmentInput.pos);
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, UseInEntryPoint_NonZeroROVGroupIndex) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-struct FragmentInput {
- @location(0) input : vec4f,
- @builtin(position) pos : vec4f,
-}
-
-@fragment
-fn F(fragmentInput : FragmentInput) -> @location(0) vec4f {
- P.a += 42;
- return fragmentInput.input + fragmentInput.pos;
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(3) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-struct F_res {
- @location(0)
- output_0 : vec4<f32>,
-}
-
-@fragment
-fn F(fragmentInput : FragmentInput) -> F_res {
- let hlsl_sv_position = fragmentInput.pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- let result = F_inner(fragmentInput);
- store_into_pixel_local_storage(hlsl_sv_position);
- return F_res(result);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-struct FragmentInput {
- @location(0)
- input : vec4f,
- @builtin(position)
- pos : vec4f,
-}
-
-fn F_inner(fragmentInput : FragmentInput) -> vec4f {
- P.a += 42;
- return (fragmentInput.input + fragmentInput.pos);
-}
-)";
-
- constexpr uint32_t kROVGroupIndex = 3u;
- auto got =
- Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}, kROVGroupIndex));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, UseInEntryPoint_Multiple_PixelLocal_Members) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
- b : i32,
- c : f32,
- d : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-struct FragmentInput {
- @location(0) input : vec4f,
- @builtin(position) pos : vec4f,
-}
-
-@fragment
-fn F(fragmentInput : FragmentInput) -> @location(0) vec4f {
- P.a += 42;
- P.b -= 21;
- P.c += 12.5f;
- P.d -= 5;
- return fragmentInput.input + fragmentInput.pos;
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-@binding(2) @group(0) @internal(rov) var pixel_local_b : texture_storage_2d<r32sint, read_write>;
-
-@binding(3) @group(0) @internal(rov) var pixel_local_c : texture_storage_2d<r32float, read_write>;
-
-@binding(4) @group(0) @internal(rov) var pixel_local_d : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
- P.b = textureLoad(pixel_local_b, rov_texcoord).x;
- P.c = textureLoad(pixel_local_c, rov_texcoord).x;
- P.d = textureLoad(pixel_local_d, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
- textureStore(pixel_local_b, rov_texcoord, vec4i(P.b));
- textureStore(pixel_local_c, rov_texcoord, vec4f(P.c));
- textureStore(pixel_local_d, rov_texcoord, vec4u(P.d));
-}
-
-struct F_res {
- @location(0)
- output_0 : vec4<f32>,
-}
-
-@fragment
-fn F(fragmentInput : FragmentInput) -> F_res {
- let hlsl_sv_position = fragmentInput.pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- let result = F_inner(fragmentInput);
- store_into_pixel_local_storage(hlsl_sv_position);
- return F_res(result);
-}
-
-struct PixelLocal {
- a : u32,
- b : i32,
- c : f32,
- d : u32,
-}
-
-var<private> P : PixelLocal;
-
-struct FragmentInput {
- @location(0)
- input : vec4f,
- @builtin(position)
- pos : vec4f,
-}
-
-fn F_inner(fragmentInput : FragmentInput) -> vec4f {
- P.a += 42;
- P.b -= 21;
- P.c += 12.5f;
- P.d -= 5;
- return (fragmentInput.input + fragmentInput.pos);
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint},
- {1, 2, core::TexelFormat::kR32Sint},
- {2, 3, core::TexelFormat::kR32Float},
- {3, 4, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, UseInEntryPoint_Multiple_PixelLocal_Members_And_Fragment_Output) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
- b : i32,
- c : f32,
- d : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-struct FragmentInput {
- @location(0) input : vec4f,
- @builtin(position) pos : vec4f,
-}
-
-struct FragmentOutput {
- @location(0) color0 : vec4f,
- @location(1) color1 : vec4f,
-}
-
-@fragment
-fn F(fragmentInput : FragmentInput) -> FragmentOutput {
- P.a += 42;
- P.b -= 21;
- P.c += 12.5f;
- P.d -= 5;
- return FragmentOutput(fragmentInput.input, fragmentInput.pos);
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-@binding(2) @group(0) @internal(rov) var pixel_local_b : texture_storage_2d<r32sint, read_write>;
-
-@binding(3) @group(0) @internal(rov) var pixel_local_c : texture_storage_2d<r32float, read_write>;
-
-@binding(4) @group(0) @internal(rov) var pixel_local_d : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
- P.b = textureLoad(pixel_local_b, rov_texcoord).x;
- P.c = textureLoad(pixel_local_c, rov_texcoord).x;
- P.d = textureLoad(pixel_local_d, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
- textureStore(pixel_local_b, rov_texcoord, vec4i(P.b));
- textureStore(pixel_local_c, rov_texcoord, vec4f(P.c));
- textureStore(pixel_local_d, rov_texcoord, vec4u(P.d));
-}
-
-struct F_res {
- @location(0)
- output_0 : vec4<f32>,
- @location(1)
- output_1 : vec4<f32>,
-}
-
-@fragment
-fn F(fragmentInput : FragmentInput) -> F_res {
- let hlsl_sv_position = fragmentInput.pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- let result = F_inner(fragmentInput);
- store_into_pixel_local_storage(hlsl_sv_position);
- return F_res(result.color0, result.color1);
-}
-
-struct PixelLocal {
- a : u32,
- b : i32,
- c : f32,
- d : u32,
-}
-
-var<private> P : PixelLocal;
-
-struct FragmentInput {
- @location(0)
- input : vec4f,
- @builtin(position)
- pos : vec4f,
-}
-
-struct FragmentOutput {
- color0 : vec4f,
- color1 : vec4f,
-}
-
-fn F_inner(fragmentInput : FragmentInput) -> FragmentOutput {
- P.a += 42;
- P.b -= 21;
- P.c += 12.5f;
- P.d -= 5;
- return FragmentOutput(fragmentInput.input, fragmentInput.pos);
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint},
- {1, 2, core::TexelFormat::kR32Sint},
- {2, 3, core::TexelFormat::kR32Float},
- {3, 4, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, ROV_Format_Different_From_Pixel_Local_Member_Format) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
- b : i32,
- c : f32,
- d : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-struct FragmentInput {
- @location(0) input : vec4f,
- @builtin(position) pos : vec4f,
-}
-
-@fragment
-fn F(fragmentInput : FragmentInput) -> @location(0) vec4f {
- P.a += 42;
- P.b -= 21;
- P.c += 12.5f;
- P.d -= 5;
- return fragmentInput.input + fragmentInput.pos;
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32sint, read_write>;
-
-@binding(2) @group(0) @internal(rov) var pixel_local_b : texture_storage_2d<r32float, read_write>;
-
-@binding(3) @group(0) @internal(rov) var pixel_local_c : texture_storage_2d<r32uint, read_write>;
-
-@binding(4) @group(0) @internal(rov) var pixel_local_d : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = bitcast<u32>(textureLoad(pixel_local_a, rov_texcoord).x);
- P.b = bitcast<i32>(textureLoad(pixel_local_b, rov_texcoord).x);
- P.c = bitcast<f32>(textureLoad(pixel_local_c, rov_texcoord).x);
- P.d = textureLoad(pixel_local_d, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4i(bitcast<i32>(P.a)));
- textureStore(pixel_local_b, rov_texcoord, vec4f(bitcast<f32>(P.b)));
- textureStore(pixel_local_c, rov_texcoord, vec4u(bitcast<u32>(P.c)));
- textureStore(pixel_local_d, rov_texcoord, vec4u(P.d));
-}
-
-struct F_res {
- @location(0)
- output_0 : vec4<f32>,
-}
-
-@fragment
-fn F(fragmentInput : FragmentInput) -> F_res {
- let hlsl_sv_position = fragmentInput.pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- let result = F_inner(fragmentInput);
- store_into_pixel_local_storage(hlsl_sv_position);
- return F_res(result);
-}
-
-struct PixelLocal {
- a : u32,
- b : i32,
- c : f32,
- d : u32,
-}
-
-var<private> P : PixelLocal;
-
-struct FragmentInput {
- @location(0)
- input : vec4f,
- @builtin(position)
- pos : vec4f,
-}
-
-fn F_inner(fragmentInput : FragmentInput) -> vec4f {
- P.a += 42;
- P.b -= 21;
- P.c += 12.5f;
- P.d -= 5;
- return (fragmentInput.input + fragmentInput.pos);
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Sint},
- {1, 2, core::TexelFormat::kR32Float},
- {2, 3, core::TexelFormat::kR32Uint},
- {3, 4, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, UseInCallee) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-fn X() {
- P.a += 42;
-}
-
-@fragment
-fn F() {
- X();
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-@fragment
-fn F(@builtin(position) my_pos : vec4<f32>) {
- let hlsl_sv_position = my_pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- F_inner();
- store_into_pixel_local_storage(hlsl_sv_position);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-fn X() {
- P.a += 42;
-}
-
-fn F_inner() {
- X();
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, ROVLoadFunctionNameUsed) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- P.a += u32(my_input.x);
-}
-
-@fragment
-fn F() {
- load_from_pixel_local_storage(vec4f(1.0, 0.0, 0.0, 1.0));
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage_1(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-@fragment
-fn F(@builtin(position) my_pos : vec4<f32>) {
- let hlsl_sv_position = my_pos;
- load_from_pixel_local_storage_1(hlsl_sv_position);
- F_inner();
- store_into_pixel_local_storage(hlsl_sv_position);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- P.a += u32(my_input.x);
-}
-
-fn F_inner() {
- load_from_pixel_local_storage(vec4f(1.0, 0.0, 0.0, 1.0));
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, ROVStoreFunctionNameUsed) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- P.a += u32(my_input.x);
-}
-
-@fragment
-fn F() {
- store_into_pixel_local_storage(vec4f(1.0, 0.0, 0.0, 1.0));
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage_1(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-@fragment
-fn F(@builtin(position) my_pos : vec4<f32>) {
- let hlsl_sv_position = my_pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- F_inner();
- store_into_pixel_local_storage_1(hlsl_sv_position);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- P.a += u32(my_input.x);
-}
-
-fn F_inner() {
- store_into_pixel_local_storage(vec4f(1.0, 0.0, 0.0, 1.0));
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, NewBuiltinPositionVariableNamesUsed) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-@fragment
-fn F(@location(0) my_pos : vec4f) {
- let hlsl_sv_position = my_pos * 2;
- P.a += u32(hlsl_sv_position.y);
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-@fragment
-fn F(@location(0) my_pos : vec4f, @builtin(position) my_pos_1 : vec4<f32>) {
- let hlsl_sv_position_1 = my_pos_1;
- load_from_pixel_local_storage(hlsl_sv_position_1);
- F_inner(my_pos);
- store_into_pixel_local_storage(hlsl_sv_position_1);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-fn F_inner(my_pos : vec4f) {
- let hlsl_sv_position = (my_pos * 2);
- P.a += u32(hlsl_sv_position.y);
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, WithInvariantBuiltinInputParameter) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-@fragment
-fn F(@invariant @builtin(position) pos : vec4f) {
- P.a += u32(pos.x);
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-@fragment
-fn F(@invariant @builtin(position) pos : vec4f) {
- let hlsl_sv_position = pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- F_inner(pos);
- store_into_pixel_local_storage(hlsl_sv_position);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-fn F_inner(pos : vec4f) {
- P.a += u32(pos.x);
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, WithInvariantBuiltinInputStructParameter) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-struct In {
- @invariant @builtin(position) pos : vec4f,
-}
-
-@fragment
-fn F(in : In) {
- P.a += u32(in.pos.x);
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-@fragment
-fn F(in : In) {
- let hlsl_sv_position = in.pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- F_inner(in);
- store_into_pixel_local_storage(hlsl_sv_position);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-struct In {
- @invariant @builtin(position)
- pos : vec4f,
-}
-
-fn F_inner(in : In) {
- P.a += u32(in.pos.x);
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, WithLocationInputParameter) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-@fragment
-fn F(@location(0) a : vec4f, @interpolate(flat) @location(1) b : vec4f) {
- P.a += u32(a.x) + u32(b.y);
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-@fragment
-fn F(@location(0) a : vec4f, @interpolate(flat) @location(1) b : vec4f, @builtin(position) my_pos : vec4<f32>) {
- let hlsl_sv_position = my_pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- F_inner(a, b);
- store_into_pixel_local_storage(hlsl_sv_position);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-fn F_inner(a : vec4f, b : vec4f) {
- P.a += (u32(a.x) + u32(b.y));
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, WithLocationInputStructParameter) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-struct In {
- @location(0) a : vec4f,
- @interpolate(flat) @location(1) b : vec4f,
-}
-
-@fragment
-fn F(in : In) {
- P.a += u32(in.a.x) + u32(in.b.y);
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-@fragment
-fn F(in : In, @builtin(position) my_pos : vec4<f32>) {
- let hlsl_sv_position = my_pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- F_inner(in);
- store_into_pixel_local_storage(hlsl_sv_position);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-struct In {
- @location(0)
- a : vec4f,
- @interpolate(flat) @location(1)
- b : vec4f,
-}
-
-fn F_inner(in : In) {
- P.a += (u32(in.a.x) + u32(in.b.y));
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, WithBuiltinAndLocationInputParameter) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-@fragment
-fn F(@builtin(position) pos : vec4f, @location(0) uv : vec4f) {
- P.a += u32(pos.x) + u32(uv.x);
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-@fragment
-fn F(@builtin(position) pos : vec4f, @location(0) uv : vec4f) {
- let hlsl_sv_position = pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- F_inner(pos, uv);
- store_into_pixel_local_storage(hlsl_sv_position);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-fn F_inner(pos : vec4f, uv : vec4f) {
- P.a += (u32(pos.x) + u32(uv.x));
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(HLSLPixelLocalTest, WithBuiltinAndLocationInputStructParameter) {
- auto* src = R"(
-enable chromium_experimental_pixel_local;
-
-struct PixelLocal {
- a : u32,
-}
-
-var<pixel_local> P : PixelLocal;
-
-struct In {
- @builtin(position) pos : vec4f,
- @location(0) uv : vec4f,
-}
-
-@fragment
-fn F(in : In) {
- P.a += u32(in.pos.x) + u32(in.uv.x);
-}
-)";
-
- auto* expect =
- R"(
-enable chromium_experimental_pixel_local;
-
-@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
-
-fn load_from_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- P.a = textureLoad(pixel_local_a, rov_texcoord).x;
-}
-
-fn store_into_pixel_local_storage(my_input : vec4<f32>) {
- let rov_texcoord = vec2u(my_input.xy);
- textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
-}
-
-@fragment
-fn F(in : In) {
- let hlsl_sv_position = in.pos;
- load_from_pixel_local_storage(hlsl_sv_position);
- F_inner(in);
- store_into_pixel_local_storage(hlsl_sv_position);
-}
-
-struct PixelLocal {
- a : u32,
-}
-
-var<private> P : PixelLocal;
-
-struct In {
- @builtin(position)
- pos : vec4f,
- @location(0)
- uv : vec4f,
-}
-
-fn F_inner(in : In) {
- P.a += (u32(in.pos.x) + u32(in.uv.x));
-}
-)";
-
- auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
-
- EXPECT_EQ(expect, str(got));
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
deleted file mode 100644
index 605136e..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright 2022 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/hlsl/writer/ast_raise/truncate_interstage_variables.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "src/tint/lang/wgsl/program/clone_context.h"
-#include "src/tint/lang/wgsl/program/program_builder.h"
-#include "src/tint/lang/wgsl/resolver/resolve.h"
-#include "src/tint/lang/wgsl/sem/call.h"
-#include "src/tint/lang/wgsl/sem/function.h"
-#include "src/tint/lang/wgsl/sem/member_accessor_expression.h"
-#include "src/tint/lang/wgsl/sem/statement.h"
-#include "src/tint/lang/wgsl/sem/variable.h"
-#include "src/tint/utils/text/unicode.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::TruncateInterstageVariables);
-TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::TruncateInterstageVariables::Config);
-
-namespace tint::hlsl::writer {
-
-namespace {
-
-struct TruncatedStructAndConverter {
- /// The symbol of the truncated structure.
- Symbol truncated_struct;
- /// The symbol of the helper function that takes the original structure as a single argument and
- /// returns the truncated structure type.
- Symbol truncate_fn;
-};
-
-} // anonymous namespace
-
-TruncateInterstageVariables::TruncateInterstageVariables() = default;
-TruncateInterstageVariables::~TruncateInterstageVariables() = default;
-
-ast::transform::Transform::ApplyResult TruncateInterstageVariables::Apply(
- const Program& src,
- const ast::transform::DataMap& config,
- ast::transform::DataMap&) const {
- ProgramBuilder b;
- program::CloneContext ctx{&b, &src, /* auto_clone_symbols */ true};
-
- const auto* data = config.Get<Config>();
- if (data == nullptr) {
- b.Diagnostics().AddError(Source{})
- << "missing transform data for "
- << tint::TypeInfo::Of<TruncateInterstageVariables>().name;
- return resolver::Resolve(b);
- }
-
- auto& sem = ctx.src->Sem();
-
- bool should_run = false;
-
- Hashmap<const sem::Function*, Symbol, 4u> entry_point_functions_to_truncate_functions;
- Hashmap<const sem::Struct*, TruncatedStructAndConverter, 4u>
- old_shader_io_structs_to_new_struct_and_truncate_functions;
-
- for (auto* func_ast : ctx.src->AST().Functions()) {
- if (!func_ast->IsEntryPoint()) {
- continue;
- }
-
- if (func_ast->PipelineStage() != ast::PipelineStage::kVertex) {
- // Currently only vertex stage could have interstage output variables that need
- // truncated.
- continue;
- }
-
- auto* func_sem = sem.Get(func_ast);
- auto* str = func_sem->ReturnType()->As<sem::Struct>();
-
- // This transform is run after CanonicalizeEntryPointIO transform,
- // So it is guaranteed that entry point inputs are already grouped in a struct.
- if (DAWN_UNLIKELY(!str)) {
- TINT_ICE() << "Entrypoint function return type is non-struct.\n"
- << "TruncateInterstageVariables transform needs to run after "
- "CanonicalizeEntryPointIO transform.";
- }
-
- // A prepass to check if any interstage variable locations in the entry point needs
- // truncating. If not we don't really need to handle this entry point.
- Hashset<const sem::StructMember*, 16u> omit_members;
-
- for (auto* member : str->Members()) {
- if (auto location = member->Attributes().location) {
- const size_t kMaxLocation = data->interstage_locations.size() - 1u;
- if (location.value() > kMaxLocation) {
- b.Diagnostics().AddError(Source{})
- << "The location (" << location.value() << ") of " << member->Name().Name()
- << " in " << str->Name().Name() << " exceeds the maximum value ("
- << kMaxLocation << ").";
- return resolver::Resolve(b);
- }
- if (!data->interstage_locations.test(location.value())) {
- omit_members.Add(member);
- }
- }
- }
-
- if (omit_members.IsEmpty()) {
- continue;
- }
-
- // Now we are sure the transform needs to be run.
- should_run = true;
-
- // Get or create a new truncated struct/truncate function for the interstage inputs &
- // outputs.
- auto entry = old_shader_io_structs_to_new_struct_and_truncate_functions.GetOrAdd(str, [&] {
- auto new_struct_sym = b.Symbols().New();
-
- Vector<const ast::StructMember*, 20> truncated_members;
- Vector<const ast::Expression*, 20> initializer_exprs;
-
- for (auto* member : str->Members()) {
- if (omit_members.Contains(member)) {
- continue;
- }
-
- truncated_members.Push(ctx.Clone(member->Declaration()));
- initializer_exprs.Push(b.MemberAccessor("io", ctx.Clone(member->Name())));
- }
-
- // Create the new shader io struct.
- b.Structure(new_struct_sym, std::move(truncated_members));
-
- // Create the mapping function to truncate the shader io.
- auto mapping_fn_sym = b.Symbols().New("truncate_shader_output");
- b.Func(mapping_fn_sym, Vector{b.Param("io", ctx.Clone(func_ast->return_type))},
- b.ty(new_struct_sym),
- Vector{
- b.Return(b.Call(new_struct_sym, std::move(initializer_exprs))),
- });
- return TruncatedStructAndConverter{new_struct_sym, mapping_fn_sym};
- });
-
- ctx.Replace(func_ast->return_type.expr, b.Expr(entry.truncated_struct));
-
- entry_point_functions_to_truncate_functions.Add(func_sem, entry.truncate_fn);
- }
-
- if (!should_run) {
- return SkipTransform;
- }
-
- // Replace return statements with new truncated shader IO struct
- ctx.ReplaceAll(
- [&](const ast::ReturnStatement* return_statement) -> const ast::ReturnStatement* {
- auto* return_sem = sem.Get(return_statement);
- if (auto mapping_fn_sym =
- entry_point_functions_to_truncate_functions.Get(return_sem->Function())) {
- return b.Return(return_statement->source,
- b.Call(*mapping_fn_sym, ctx.Clone(return_statement->value)));
- }
- return nullptr;
- });
-
- // Remove IO attributes from old shader IO struct which is not used as entry point output
- // anymore.
- for (auto& it : old_shader_io_structs_to_new_struct_and_truncate_functions) {
- const ast::Struct* struct_ty = it.key->Declaration();
- for (auto* member : struct_ty->members) {
- for (auto* attr : member->attributes) {
- if (attr->IsAnyOf<ast::BuiltinAttribute, ast::LocationAttribute,
- ast::InterpolateAttribute, ast::InvariantAttribute>()) {
- ctx.Remove(member->attributes, attr);
- }
- }
- }
- }
-
- ctx.Clone();
- return resolver::Resolve(b);
-}
-
-TruncateInterstageVariables::Config::Config() = default;
-
-TruncateInterstageVariables::Config::Config(const Config&) = default;
-
-TruncateInterstageVariables::Config::~Config() = default;
-
-TruncateInterstageVariables::Config& TruncateInterstageVariables::Config::operator=(const Config&) =
- default;
-
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h
deleted file mode 100644
index 17b1f10..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2022 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_LANG_HLSL_WRITER_AST_RAISE_TRUNCATE_INTERSTAGE_VARIABLES_H_
-#define SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_TRUNCATE_INTERSTAGE_VARIABLES_H_
-
-#include <bitset>
-
-#include "src/tint/api/common/binding_point.h"
-#include "src/tint/lang/wgsl/ast/transform/transform.h"
-
-namespace tint::hlsl::writer {
-
-/// TruncateInterstageVariables is a transform that truncate interstage variables.
-/// It must be run after CanonicalizeEntryPointIO which guarantees all interstage variables of
-/// a given entry point are grouped into one shader IO struct.
-/// It replaces `original shader IO struct` with a `new wrapper struct` containing builtin IOs
-/// and user-defined IO whose locations are marked in the interstage_locations bitset from the
-/// config. The return statements of `original shader IO struct` are wrapped by a mapping function
-/// that initializes the members of `new wrapper struct` with values from `original shader IO
-/// struct`. IO attributes of members in `original shader IO struct` are removed, other attributes
-/// still preserve.
-///
-/// For example:
-///
-/// ```
-/// struct ShaderIO {
-/// @builtin(position) @invariant pos: vec4<f32>,
-/// @location(1) f_1: f32,
-/// @location(3) @align(16) f_3: f32,
-/// @location(5) @interpolate(flat) @align(16) @size(16) f_5: u32,
-/// }
-/// @vertex
-/// fn f() -> ShaderIO {
-/// var io: ShaderIO;
-/// io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
-/// io.f_1 = 1.0;
-/// io.f_3 = io.f_1 + 3.0;
-/// io.f_5 = 1u;
-/// return io;
-/// }
-/// ```
-///
-/// With config.interstage_locations[3] and [5] set to true, is transformed to:
-///
-/// ```
-/// struct tint_symbol {
-/// @builtin(position) @invariant
-/// pos : vec4<f32>,
-/// @location(3) @align(16)
-/// f_3 : f32,
-/// @location(5) @interpolate(flat) @align(16) @size(16)
-/// f_5 : u32,
-/// }
-///
-/// fn truncate_shader_output(io : ShaderIO) -> tint_symbol {
-/// return tint_symbol(io.pos, io.f_3, io.f_5);
-/// }
-///
-/// struct ShaderIO {
-/// pos : vec4<f32>,
-/// f_1 : f32,
-/// @align(16)
-/// f_3 : f32,
-/// @align(16) @size(16)
-/// f_5 : u32,
-/// }
-///
-/// @vertex
-/// fn f() -> tint_symbol {
-/// var io : ShaderIO;
-/// io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
-/// io.f_1 = 1.0;
-/// io.f_3 = (io.f_1 + 3.0);
-/// io.f_5 = 1u;
-/// return truncate_shader_output(io);
-/// }
-/// ```
-///
-class TruncateInterstageVariables final
- : public Castable<TruncateInterstageVariables, ast::transform::Transform> {
- public:
- /// Configuration options for the transform
- struct Config final : public Castable<Config, ast::transform::Data> {
- /// Constructor
- Config();
-
- /// Copy constructor
- Config(const Config&);
-
- /// Destructor
- ~Config() override;
-
- /// Assignment operator
- /// @returns this Config
- Config& operator=(const Config&);
-
- /// Indicate which interstage io locations are actually used by the later stage.
- /// There can be at most 30 user defined interstage variables with locations.
- std::bitset<30> interstage_locations;
-
- /// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(Config, interstage_locations);
- };
-
- /// Constructor using a the configuration provided in the input Data
- TruncateInterstageVariables();
-
- /// Destructor
- ~TruncateInterstageVariables() override;
-
- /// @copydoc ast::transform::Transform::Apply
- ApplyResult Apply(const Program& program,
- const ast::transform::DataMap& inputs,
- ast::transform::DataMap& outputs) const override;
-};
-
-} // namespace tint::hlsl::writer
-
-#endif // SRC_TINT_LANG_HLSL_WRITER_AST_RAISE_TRUNCATE_INTERSTAGE_VARIABLES_H_
diff --git a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables_test.cc b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables_test.cc
deleted file mode 100644
index f5cd0c1..0000000
--- a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables_test.cc
+++ /dev/null
@@ -1,641 +0,0 @@
-// Copyright 2022 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/hlsl/writer/ast_raise/truncate_interstage_variables.h"
-#include "src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.h"
-
-#include "gmock/gmock.h"
-#include "src/tint/lang/wgsl/ast/transform/helper_test.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-using ::testing::ContainerEq;
-
-using TruncateInterstageVariablesTest = ast::transform::TransformTest;
-
-TEST(TintCheckAllFieldsReflected, HlslWriterAstRaiseTruncateInterstageVariablesTest) {
- TINT_ASSERT_ALL_FIELDS_REFLECTED(TruncateInterstageVariables::Config);
-}
-
-TEST_F(TruncateInterstageVariablesTest, ShouldRunVertex) {
- auto* src = R"(
-struct ShaderIO {
- @builtin(position) pos: vec4<f32>,
- @location(0) f_0: f32,
- @location(2) f_2: f32,
-}
-@vertex
-fn f() -> ShaderIO {
- var io: ShaderIO;
- io.f_0 = 1.0;
- io.f_2 = io.f_2 + 3.0;
- return io;
-}
-)";
-
- {
- auto* expect =
- "error: missing transform data for tint::hlsl::writer::TruncateInterstageVariables";
- auto got = Run<TruncateInterstageVariables>(src);
- EXPECT_EQ(expect, str(got));
- }
-
- {
- // Empty interstage_locations: truncate all interstage variables, should run
- TruncateInterstageVariables::Config cfg;
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
- EXPECT_TRUE(ShouldRun<TruncateInterstageVariables>(src, data));
- }
-
- {
- // All existing interstage_locations are marked: should not run
- TruncateInterstageVariables::Config cfg;
- cfg.interstage_locations[0] = true;
- cfg.interstage_locations[2] = true;
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
- EXPECT_FALSE(ShouldRun<TruncateInterstageVariables>(src, data));
- }
-
- {
- // Partial interstage_locations are marked: should run
- TruncateInterstageVariables::Config cfg;
- cfg.interstage_locations[2] = true;
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
- EXPECT_TRUE(ShouldRun<TruncateInterstageVariables>(src, data));
- }
-}
-
-TEST_F(TruncateInterstageVariablesTest, ShouldRunFragment) {
- auto* src = R"(
-struct ShaderIO {
- @location(0) f_0: f32,
- @location(2) f_2: f32,
-}
-@fragment
-fn f(io: ShaderIO) -> @location(1) vec4<f32> {
- return vec4<f32>(io.f_0, io.f_2, 0.0, 1.0);
-}
-)";
-
- TruncateInterstageVariables::Config cfg;
- cfg.interstage_locations[2] = true;
-
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
-
- EXPECT_FALSE(ShouldRun<TruncateInterstageVariables>(src, data));
-}
-
-// Test that this transform should run after canoicalize entry point io, where shader io is already
-// grouped into a struct.
-TEST_F(TruncateInterstageVariablesTest, ShouldRunAfterCanonicalizeEntryPointIO) {
- auto* src = R"(
-@vertex
-fn f() -> @builtin(position) vec4<f32> {
- return vec4<f32>(1.0, 1.0, 1.0, 1.0);
-}
-)";
-
- TruncateInterstageVariables::Config cfg;
- cfg.interstage_locations[0] = true;
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
-
- auto got = Run<ast::transform::CanonicalizeEntryPointIO>(src, data);
-
- // Inevitably entry point can write only one variable if not using struct
- // So the truncate won't run.
- EXPECT_FALSE(ShouldRun<TruncateInterstageVariables>(str(got), data));
-}
-
-TEST_F(TruncateInterstageVariablesTest, BasicVertexTrimLocationInMid) {
- auto* src = R"(
-struct ShaderIO {
- @builtin(position) pos: vec4<f32>,
- @location(1) f_1: f32,
- @location(3) f_3: f32,
-}
-@vertex
-fn f() -> ShaderIO {
- var io: ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = io.f_1 + 3.0;
- return io;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol {
- @builtin(position)
- pos : vec4<f32>,
- @location(1)
- f_1 : f32,
-}
-
-fn truncate_shader_output(io : ShaderIO) -> tint_symbol {
- return tint_symbol(io.pos, io.f_1);
-}
-
-struct ShaderIO {
- pos : vec4<f32>,
- f_1 : f32,
- f_3 : f32,
-}
-
-@vertex
-fn f() -> tint_symbol {
- var io : ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = (io.f_1 + 3.0);
- return truncate_shader_output(io);
-}
-)";
-
- TruncateInterstageVariables::Config cfg;
- // fragment has input at @location(1)
- cfg.interstage_locations[1] = true;
-
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
-
- auto got = Run<TruncateInterstageVariables>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(TruncateInterstageVariablesTest, BasicVertexTrimLocationAtEnd) {
- auto* src = R"(
-struct ShaderIO {
- @builtin(position) pos: vec4<f32>,
- @location(1) f_1: f32,
- @location(3) f_3: f32,
-}
-@vertex
-fn f() -> ShaderIO {
- var io: ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = io.f_1 + 3.0;
- return io;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol {
- @builtin(position)
- pos : vec4<f32>,
- @location(3)
- f_3 : f32,
-}
-
-fn truncate_shader_output(io : ShaderIO) -> tint_symbol {
- return tint_symbol(io.pos, io.f_3);
-}
-
-struct ShaderIO {
- pos : vec4<f32>,
- f_1 : f32,
- f_3 : f32,
-}
-
-@vertex
-fn f() -> tint_symbol {
- var io : ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = (io.f_1 + 3.0);
- return truncate_shader_output(io);
-}
-)";
-
- TruncateInterstageVariables::Config cfg;
- // fragment has input at @location(3)
- cfg.interstage_locations[3] = true;
-
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
-
- auto got = Run<TruncateInterstageVariables>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(TruncateInterstageVariablesTest, TruncateAllLocations) {
- auto* src = R"(
-struct ShaderIO {
- @builtin(position) pos: vec4<f32>,
- @location(1) f_1: f32,
- @location(3) f_3: f32,
-}
-@vertex
-fn f() -> ShaderIO {
- var io: ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = io.f_1 + 3.0;
- return io;
-}
-)";
-
- {
- auto* expect = R"(
-struct tint_symbol {
- @builtin(position)
- pos : vec4<f32>,
-}
-
-fn truncate_shader_output(io : ShaderIO) -> tint_symbol {
- return tint_symbol(io.pos);
-}
-
-struct ShaderIO {
- pos : vec4<f32>,
- f_1 : f32,
- f_3 : f32,
-}
-
-@vertex
-fn f() -> tint_symbol {
- var io : ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = (io.f_1 + 3.0);
- return truncate_shader_output(io);
-}
-)";
-
- TruncateInterstageVariables::Config cfg;
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
-
- auto got = Run<TruncateInterstageVariables>(src, data);
-
- EXPECT_EQ(expect, str(got));
- }
-}
-
-// Test that the transform only removes IO attributes and preserve other attributes in the old
-// Shader IO struct.
-TEST_F(TruncateInterstageVariablesTest, RemoveIOAttributes) {
- auto* src = R"(
-struct ShaderIO {
- @builtin(position) @invariant pos: vec4<f32>,
- @location(1) f_1: f32,
- @location(3) @align(16) f_3: f32,
- @location(5) @interpolate(flat) @align(16) @size(16) f_5: u32,
-}
-@vertex
-fn f() -> ShaderIO {
- var io: ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = io.f_1 + 3.0;
- io.f_5 = 1u;
- return io;
-}
-)";
-
- {
- auto* expect = R"(
-struct tint_symbol {
- @builtin(position) @invariant
- pos : vec4<f32>,
- @location(3) @align(16)
- f_3 : f32,
- @location(5) @interpolate(flat) @align(16) @size(16)
- f_5 : u32,
-}
-
-fn truncate_shader_output(io : ShaderIO) -> tint_symbol {
- return tint_symbol(io.pos, io.f_3, io.f_5);
-}
-
-struct ShaderIO {
- pos : vec4<f32>,
- f_1 : f32,
- @align(16)
- f_3 : f32,
- @align(16) @size(16)
- f_5 : u32,
-}
-
-@vertex
-fn f() -> tint_symbol {
- var io : ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = (io.f_1 + 3.0);
- io.f_5 = 1u;
- return truncate_shader_output(io);
-}
-)";
-
- TruncateInterstageVariables::Config cfg;
- // Missing @location[1] intentionally to make sure the transform run.
- cfg.interstage_locations[3] = true;
- cfg.interstage_locations[5] = true;
-
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
-
- auto got = Run<TruncateInterstageVariables>(src, data);
-
- EXPECT_EQ(expect, str(got));
- }
-}
-
-TEST_F(TruncateInterstageVariablesTest, MultipleEntryPointsSharingStruct) {
- auto* src = R"(
-struct ShaderIO {
- @builtin(position) pos: vec4<f32>,
- @location(1) f_1: f32,
- @location(3) f_3: f32,
- @location(5) f_5: f32,
-}
-
-@vertex
-fn f1() -> ShaderIO {
- var io: ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = 1.0;
- return io;
-}
-
-@vertex
-fn f2() -> ShaderIO {
- var io: ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_5 = 2.0;
- return io;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol {
- @builtin(position)
- pos : vec4<f32>,
- @location(3)
- f_3 : f32,
-}
-
-fn truncate_shader_output(io : ShaderIO) -> tint_symbol {
- return tint_symbol(io.pos, io.f_3);
-}
-
-struct ShaderIO {
- pos : vec4<f32>,
- f_1 : f32,
- f_3 : f32,
- f_5 : f32,
-}
-
-@vertex
-fn f1() -> tint_symbol {
- var io : ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = 1.0;
- return truncate_shader_output(io);
-}
-
-@vertex
-fn f2() -> tint_symbol {
- var io : ShaderIO;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_5 = 2.0;
- return truncate_shader_output(io);
-}
-)";
-
- TruncateInterstageVariables::Config cfg;
- // fragment has input at @location(3)
- cfg.interstage_locations[3] = true;
-
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
-
- auto got = Run<TruncateInterstageVariables>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(TruncateInterstageVariablesTest, MultipleEntryPoints) {
- auto* src = R"(
-struct ShaderIO1 {
- @builtin(position) pos: vec4<f32>,
- @location(1) f_1: f32,
- @location(3) f_3: f32,
- @location(5) f_5: f32,
-}
-
-@vertex
-fn f1() -> ShaderIO1 {
- var io: ShaderIO1;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = 1.0;
- return io;
-}
-
-struct ShaderIO2 {
- @builtin(position) pos: vec4<f32>,
- @location(2) f_2: f32,
-}
-
-@vertex
-fn f2() -> ShaderIO2 {
- var io: ShaderIO2;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_2 = 2.0;
- return io;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol {
- @builtin(position)
- pos : vec4<f32>,
- @location(3)
- f_3 : f32,
-}
-
-fn truncate_shader_output(io : ShaderIO1) -> tint_symbol {
- return tint_symbol(io.pos, io.f_3);
-}
-
-struct tint_symbol_1 {
- @builtin(position)
- pos : vec4<f32>,
-}
-
-fn truncate_shader_output_1(io : ShaderIO2) -> tint_symbol_1 {
- return tint_symbol_1(io.pos);
-}
-
-struct ShaderIO1 {
- pos : vec4<f32>,
- f_1 : f32,
- f_3 : f32,
- f_5 : f32,
-}
-
-@vertex
-fn f1() -> tint_symbol {
- var io : ShaderIO1;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = 1.0;
- return truncate_shader_output(io);
-}
-
-struct ShaderIO2 {
- pos : vec4<f32>,
- f_2 : f32,
-}
-
-@vertex
-fn f2() -> tint_symbol_1 {
- var io : ShaderIO2;
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_2 = 2.0;
- return truncate_shader_output_1(io);
-}
-)";
-
- TruncateInterstageVariables::Config cfg;
- // fragment has input at @location(3)
- cfg.interstage_locations[3] = true;
-
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
-
- auto got = Run<TruncateInterstageVariables>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(TruncateInterstageVariablesTest, MultipleReturnStatements) {
- auto* src = R"(
-struct ShaderIO {
- @builtin(position) pos: vec4<f32>,
- @location(1) f_1: f32,
- @location(3) f_3: f32,
-}
-@vertex
-fn f(@builtin(vertex_index) vid: u32) -> ShaderIO {
- var io: ShaderIO;
- if (vid > 10u) {
- io.f_1 = 2.0;
- return io;
- }
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = io.f_1 + 3.0;
- return io;
-}
-)";
-
- auto* expect = R"(
-struct tint_symbol {
- @builtin(position)
- pos : vec4<f32>,
- @location(3)
- f_3 : f32,
-}
-
-fn truncate_shader_output(io : ShaderIO) -> tint_symbol {
- return tint_symbol(io.pos, io.f_3);
-}
-
-struct ShaderIO {
- pos : vec4<f32>,
- f_1 : f32,
- f_3 : f32,
-}
-
-@vertex
-fn f(@builtin(vertex_index) vid : u32) -> tint_symbol {
- var io : ShaderIO;
- if ((vid > 10u)) {
- io.f_1 = 2.0;
- return truncate_shader_output(io);
- }
- io.pos = vec4<f32>(1.0, 1.0, 1.0, 1.0);
- io.f_1 = 1.0;
- io.f_3 = (io.f_1 + 3.0);
- return truncate_shader_output(io);
-}
-)";
-
- TruncateInterstageVariables::Config cfg;
- // fragment has input at @location(3)
- cfg.interstage_locations[3] = true;
-
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
-
- auto got = Run<TruncateInterstageVariables>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(TruncateInterstageVariablesTest, LocationOutOfRange) {
- auto* src = R"(
-struct ShaderIO {
- @builtin(position) pos: vec4<f32>,
- @location(0) f_0: f32,
- @location(30) f_2: f32,
-}
-@vertex
-fn f() -> ShaderIO {
- var io: ShaderIO;
- io.f_0 = 1.0;
- io.f_2 = io.f_2 + 3.0;
- return io;
-}
-)";
-
- // Return error when location >= 30 (maximum supported number of inter-stage shader variables)
- auto* expect = "error: The location (30) of f_2 in ShaderIO exceeds the maximum value (29).";
-
- TruncateInterstageVariables::Config cfg;
- ast::transform::DataMap data;
- data.Add<TruncateInterstageVariables::Config>(cfg);
-
- auto got = Run<TruncateInterstageVariables>(src, data);
- EXPECT_EQ(expect, str(got));
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/writer.cc b/src/tint/lang/hlsl/writer/writer.cc
index 1d09c2a..2d09c13 100644
--- a/src/tint/lang/hlsl/writer/writer.cc
+++ b/src/tint/lang/hlsl/writer/writer.cc
@@ -34,10 +34,9 @@
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/core/ir/var.h"
#include "src/tint/lang/core/type/input_attachment.h"
-#include "src/tint/lang/hlsl/writer/ast_printer/ast_printer.h"
+#include "src/tint/lang/core/type/pointer.h"
#include "src/tint/lang/hlsl/writer/printer/printer.h"
#include "src/tint/lang/hlsl/writer/raise/raise.h"
-#include "src/tint/lang/wgsl/ast/pipeline_stage.h"
namespace tint::hlsl::writer {
@@ -102,38 +101,4 @@
return Print(ir, options);
}
-Result<Output> Generate(const Program& program, const Options& options) {
- if (!program.IsValid()) {
- return Failure{program.Diagnostics().Str()};
- }
-
- // Sanitize the program.
- auto sanitized_result = Sanitize(program, options);
- if (!sanitized_result.program.IsValid()) {
- return Failure{sanitized_result.program.Diagnostics().Str()};
- }
-
- // Generate the HLSL code.
- auto impl = std::make_unique<ASTPrinter>(sanitized_result.program);
- if (!impl->Generate()) {
- return Failure{impl->Diagnostics().Str()};
- }
-
- Output output;
- output.hlsl = impl->Result();
-
- // 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()});
- }
- }
-
- output.used_array_length_from_uniform_indices =
- std::move(sanitized_result.used_array_length_from_uniform_indices);
-
- return output;
-}
-
} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/writer.h b/src/tint/lang/hlsl/writer/writer.h
index bb1a7f2..a637e76 100644
--- a/src/tint/lang/hlsl/writer/writer.h
+++ b/src/tint/lang/hlsl/writer/writer.h
@@ -33,9 +33,6 @@
#include "src/tint/utils/result.h"
// Forward declarations
-namespace tint {
-class Program;
-} // namespace tint
namespace tint::core::ir {
class Module;
} // namespace tint::core::ir
@@ -55,13 +52,6 @@
/// @returns the resulting HLSL and supplementary information, or failure
Result<Output> Generate(core::ir::Module& ir, const Options& options);
-/// Generate HLSL for a program, according to a set of configuration options.
-/// The result will contain the HLSL and supplementary information, or failure.
-/// @param program the program to translate to HLSL
-/// @param options the configuration options to use when generating HLSL
-/// @returns the resulting HLSL and supplementary information, or failure
-Result<Output> Generate(const Program& program, const Options& options);
-
} // namespace tint::hlsl::writer
#endif // SRC_TINT_LANG_HLSL_WRITER_WRITER_H_
diff --git a/src/tint/lang/hlsl/writer/writer_ast_fuzz.cc b/src/tint/lang/hlsl/writer/writer_ast_fuzz.cc
deleted file mode 100644
index f011ab4..0000000
--- a/src/tint/lang/hlsl/writer/writer_ast_fuzz.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2024 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-// list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// GEN_BUILD:CONDITION(tint_build_wgsl_reader)
-
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <unordered_map>
-
-#include "src/tint/cmd/fuzz/wgsl/fuzz.h"
-#include "src/tint/lang/hlsl/validate/validate.h"
-#include "src/tint/lang/hlsl/writer/writer.h"
-#include "src/tint/lang/wgsl/ast/module.h"
-#include "src/tint/lang/wgsl/ast/transform/renamer.h"
-#include "src/tint/utils/command/command.h"
-#include "src/tint/utils/text/string.h"
-
-namespace tint::hlsl::writer {
-namespace {
-
-bool CanRun(const Program& program) {
- if (program.AST().HasOverrides()) {
- return false;
- }
-
- // The PixelLocal transform assumes only a single entry point, so check for multiple entry
- // points if chromium_experimental_pixel_local is enabled.
- uint32_t num_entry_points = 0;
- for (auto* fn : program.AST().Functions()) {
- if (fn->PipelineStage() != ast::PipelineStage::kNone) {
- num_entry_points++;
- }
- }
- for (auto* enable : program.AST().Enables()) {
- if (enable->HasExtension(tint::wgsl::Extension::kChromiumExperimentalSubgroupMatrix)) {
- return false;
- }
- if (enable->HasExtension(tint::wgsl::Extension::kChromiumExperimentalPixelLocal)) {
- if (num_entry_points > 1) {
- return false;
- }
- break;
- }
- }
-
- return true;
-}
-
-void ASTFuzzer(const tint::Program& program,
- const fuzz::wgsl::Context& context,
- const Options& options) {
- if (!CanRun(program)) {
- return;
- }
-
- // Currently disabled, as DXC can error on HLSL emitted by Tint. For example: post optimization
- // infinite loops will fail to compile, but these are beyond Tint's analysis capabilities.
- constexpr bool must_validate = false;
-
- const char* dxc_path = validate::kDxcDLLName;
- if (!context.options.dxc.empty()) {
- dxc_path = context.options.dxc.c_str();
- }
- auto dxc = tint::Command::LookPath(dxc_path);
-
- Result<tint::hlsl::writer::Output> res;
- if (dxc.Found()) {
- // If validating with DXC, run renamer transform first to avoid DXC validation failures.
- ast::transform::DataMap inputs, outputs;
- inputs.Add<ast::transform::Renamer::Config>(ast::transform::Renamer::Target::kHlslKeywords);
- if (auto renamer_res = tint::ast::transform::Renamer{}.Apply(program, inputs, outputs)) {
- if (!renamer_res->IsValid()) {
- TINT_ICE() << renamer_res->Diagnostics();
- }
- res = tint::hlsl::writer::Generate(*renamer_res, options);
- }
- } else {
- res = tint::hlsl::writer::Generate(program, options);
- }
-
- if (res != Success) {
- return;
- }
-
- if (context.options.dump) {
- std::cout << "Dumping generated HLSL:\n" << res->hlsl << "\n";
- }
-
- if (dxc.Found()) {
- uint32_t hlsl_shader_model = 60;
- bool require_16bit_types = false;
- auto enable_list = program.AST().Enables();
- for (auto* enable : enable_list) {
- if (enable->HasExtension(tint::wgsl::Extension::kF16)) {
- hlsl_shader_model = 62;
- require_16bit_types = true;
- break;
- }
- }
-
- auto validate_res = validate::ValidateUsingDXC(dxc.Path(), res->hlsl, res->entry_points,
- require_16bit_types, hlsl_shader_model);
-
- if (must_validate && validate_res.failed) {
- size_t line_num = 1;
- std::stringstream err;
- err << "DXC was expected to succeed, but failed:\n\n";
- for (auto line : Split(res->hlsl, "\n")) {
- err << line_num++ << ": " << line << "\n";
- }
- err << "\n\n" << validate_res.output;
- TINT_ICE() << err.str();
- }
-
- } else if (must_validate) {
- TINT_ICE() << "cannot validate with DXC as it was not found at: " << dxc_path;
- }
-}
-
-} // namespace
-} // namespace tint::hlsl::writer
-
-TINT_WGSL_PROGRAM_FUZZER(tint::hlsl::writer::ASTFuzzer);