[ir] Add ReferencedModuleVars helper
This is a stateful helper that returns (and caches) the module-scope
variables that are transitively referenced by a function. Some work is
done on creation to determine which variables are directly referenced
by which blocks. The remaining work is done when the references for a
function are actually requested.
Update the ZeroInitializeWorkgroupMemory transform to use this helper.
Change-Id: I522d6521a61a94bf255ca9d9ff3d7d5998a2b69e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/169222
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/cmd/test/BUILD.bazel b/src/tint/cmd/test/BUILD.bazel
index c99263c..b6d308b 100644
--- a/src/tint/cmd/test/BUILD.bazel
+++ b/src/tint/cmd/test/BUILD.bazel
@@ -48,6 +48,7 @@
"//src/tint/cmd/common:test",
"//src/tint/lang/core/constant:test",
"//src/tint/lang/core/intrinsic:test",
+ "//src/tint/lang/core/ir/transform/common:test",
"//src/tint/lang/core/ir/transform:test",
"//src/tint/lang/core/ir:test",
"//src/tint/lang/core/type:test",
diff --git a/src/tint/cmd/test/BUILD.cmake b/src/tint/cmd/test/BUILD.cmake
index 0cb839e..94c5d90 100644
--- a/src/tint/cmd/test/BUILD.cmake
+++ b/src/tint/cmd/test/BUILD.cmake
@@ -49,6 +49,7 @@
tint_cmd_common_test
tint_lang_core_constant_test
tint_lang_core_intrinsic_test
+ tint_lang_core_ir_transform_common_test
tint_lang_core_ir_transform_test
tint_lang_core_ir_test
tint_lang_core_type_test
diff --git a/src/tint/cmd/test/BUILD.gn b/src/tint/cmd/test/BUILD.gn
index 54897e3..b8647d4 100644
--- a/src/tint/cmd/test/BUILD.gn
+++ b/src/tint/cmd/test/BUILD.gn
@@ -57,6 +57,7 @@
"${tint_src_dir}/lang/core/intrinsic:unittests",
"${tint_src_dir}/lang/core/ir:unittests",
"${tint_src_dir}/lang/core/ir/transform:unittests",
+ "${tint_src_dir}/lang/core/ir/transform/common:unittests",
"${tint_src_dir}/lang/core/type:unittests",
"${tint_src_dir}/lang/hlsl/writer/common:unittests",
"${tint_src_dir}/lang/msl/ir:unittests",
diff --git a/src/tint/lang/core/ir/transform/BUILD.bazel b/src/tint/lang/core/ir/transform/BUILD.bazel
index 467e451..3ea71c4 100644
--- a/src/tint/lang/core/ir/transform/BUILD.bazel
+++ b/src/tint/lang/core/ir/transform/BUILD.bazel
@@ -85,6 +85,7 @@
"//src/tint/lang/core/constant",
"//src/tint/lang/core/intrinsic",
"//src/tint/lang/core/ir",
+ "//src/tint/lang/core/ir/transform/common",
"//src/tint/lang/core/type",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
diff --git a/src/tint/lang/core/ir/transform/BUILD.cmake b/src/tint/lang/core/ir/transform/BUILD.cmake
index 1ae8efb..f3a8b32 100644
--- a/src/tint/lang/core/ir/transform/BUILD.cmake
+++ b/src/tint/lang/core/ir/transform/BUILD.cmake
@@ -34,6 +34,8 @@
# Do not modify this file directly
################################################################################
+include(lang/core/ir/transform/common/BUILD.cmake)
+
################################################################################
# Target: tint_lang_core_ir_transform
# Kind: lib
@@ -84,6 +86,7 @@
tint_lang_core_constant
tint_lang_core_intrinsic
tint_lang_core_ir
+ tint_lang_core_ir_transform_common
tint_lang_core_type
tint_utils_containers
tint_utils_diagnostic
diff --git a/src/tint/lang/core/ir/transform/BUILD.gn b/src/tint/lang/core/ir/transform/BUILD.gn
index 95de9fc..db194b7 100644
--- a/src/tint/lang/core/ir/transform/BUILD.gn
+++ b/src/tint/lang/core/ir/transform/BUILD.gn
@@ -88,6 +88,7 @@
"${tint_src_dir}/lang/core/constant",
"${tint_src_dir}/lang/core/intrinsic",
"${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/ir/transform/common",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
diff --git a/src/tint/lang/core/ir/transform/common/BUILD.bazel b/src/tint/lang/core/ir/transform/common/BUILD.bazel
new file mode 100644
index 0000000..f05642f
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/common/BUILD.bazel
@@ -0,0 +1,103 @@
+# 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.
+
+################################################################################
+# 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 = "common",
+ srcs = [
+ "referenced_module_vars.cc",
+ ],
+ hdrs = [
+ "referenced_module_vars.h",
+ ],
+ deps = [
+ "//src/tint/api/common",
+ "//src/tint/lang/core",
+ "//src/tint/lang/core/constant",
+ "//src/tint/lang/core/ir",
+ "//src/tint/lang/core/type",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/id",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/symbol",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+cc_library(
+ name = "test",
+ alwayslink = True,
+ srcs = [
+ "referenced_module_vars_test.cc",
+ ],
+ deps = [
+ "//src/tint/api/common",
+ "//src/tint/lang/core",
+ "//src/tint/lang/core/constant",
+ "//src/tint/lang/core/intrinsic",
+ "//src/tint/lang/core/ir",
+ "//src/tint/lang/core/ir/transform/common",
+ "//src/tint/lang/core/ir:test",
+ "//src/tint/lang/core/type",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/id",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/symbol",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ "@gtest",
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+
diff --git a/src/tint/lang/core/ir/transform/common/BUILD.cmake b/src/tint/lang/core/ir/transform/common/BUILD.cmake
new file mode 100644
index 0000000..7004d86
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/common/BUILD.cmake
@@ -0,0 +1,101 @@
+# 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.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+################################################################################
+# Target: tint_lang_core_ir_transform_common
+# Kind: lib
+################################################################################
+tint_add_target(tint_lang_core_ir_transform_common lib
+ lang/core/ir/transform/common/referenced_module_vars.cc
+ lang/core/ir/transform/common/referenced_module_vars.h
+)
+
+tint_target_add_dependencies(tint_lang_core_ir_transform_common lib
+ tint_api_common
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_ir
+ tint_lang_core_type
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_symbol
+ tint_utils_text
+ tint_utils_traits
+)
+
+################################################################################
+# Target: tint_lang_core_ir_transform_common_test
+# Kind: test
+################################################################################
+tint_add_target(tint_lang_core_ir_transform_common_test test
+ lang/core/ir/transform/common/referenced_module_vars_test.cc
+)
+
+tint_target_add_dependencies(tint_lang_core_ir_transform_common_test test
+ tint_api_common
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_intrinsic
+ tint_lang_core_ir
+ tint_lang_core_ir_transform_common
+ tint_lang_core_ir_test
+ tint_lang_core_type
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_symbol
+ tint_utils_text
+ tint_utils_traits
+)
+
+tint_target_add_external_dependencies(tint_lang_core_ir_transform_common_test test
+ "gtest"
+)
diff --git a/src/tint/lang/core/ir/transform/common/BUILD.gn b/src/tint/lang/core/ir/transform/common/BUILD.gn
new file mode 100644
index 0000000..d050caf
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/common/BUILD.gn
@@ -0,0 +1,99 @@
+# 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.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+import("../../../../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+
+if (tint_build_unittests || tint_build_benchmarks) {
+ import("//testing/test.gni")
+}
+
+libtint_source_set("common") {
+ sources = [
+ "referenced_module_vars.cc",
+ "referenced_module_vars.h",
+ ]
+ deps = [
+ "${tint_src_dir}/api/common",
+ "${tint_src_dir}/lang/core",
+ "${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+}
+if (tint_build_unittests) {
+ tint_unittests_source_set("unittests") {
+ sources = [ "referenced_module_vars_test.cc" ]
+ deps = [
+ "${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/intrinsic",
+ "${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/ir:unittests",
+ "${tint_src_dir}/lang/core/ir/transform/common",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+ }
+}
diff --git a/src/tint/lang/core/ir/transform/common/referenced_module_vars.cc b/src/tint/lang/core/ir/transform/common/referenced_module_vars.cc
new file mode 100644
index 0000000..b97b9dd
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/common/referenced_module_vars.cc
@@ -0,0 +1,75 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/core/ir/transform/common/referenced_module_vars.h"
+
+#include "src/tint/lang/core/ir/control_instruction.h"
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/core/ir/user_call.h"
+#include "src/tint/lang/core/ir/var.h"
+#include "src/tint/utils/rtti/switch.h"
+
+namespace tint::core::ir {
+
+const ReferencedModuleVars::VarSet& ReferencedModuleVars::TransitiveReferences(Function* func) {
+ return transitive_references_.GetOrAdd(func, [&] {
+ VarSet vars;
+ GetTransitiveReferences(func->Block(), vars);
+ return vars;
+ });
+}
+
+/// Get the set of variables transitively referenced by @p block.
+/// @param block the block
+/// @param vars the set of transitively referenced variables to populate
+void ReferencedModuleVars::GetTransitiveReferences(Block* block, VarSet& vars) {
+ // Add directly referenced vars.
+ if (auto itr = block_to_direct_vars_.Get(block)) {
+ for (auto& var : *itr) {
+ vars.Add(var);
+ }
+ }
+
+ // Loop over instructions in the block to find indirectly referenced vars.
+ for (auto* inst : *block) {
+ tint::Switch(
+ inst,
+ [&](UserCall* call) {
+ // Get variables referenced by a function called from this block.
+ const auto& callee_vars = TransitiveReferences(call->Target());
+ for (auto* var : callee_vars) {
+ vars.Add(var);
+ }
+ },
+ [&](ControlInstruction* ctrl) {
+ // Recurse into control instructions and gather their referenced vars.
+ ctrl->ForeachBlock([&](Block* blk) { GetTransitiveReferences(blk, vars); });
+ });
+ }
+}
+
+} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/transform/common/referenced_module_vars.h b/src/tint/lang/core/ir/transform/common/referenced_module_vars.h
new file mode 100644
index 0000000..a48b0a7
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/common/referenced_module_vars.h
@@ -0,0 +1,105 @@
+// 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.
+
+#ifndef SRC_TINT_LANG_CORE_IR_TRANSFORM_COMMON_REFERENCED_MODULE_VARS_H_
+#define SRC_TINT_LANG_CORE_IR_TRANSFORM_COMMON_REFERENCED_MODULE_VARS_H_
+
+#include <functional>
+
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/core/ir/var.h"
+#include "src/tint/utils/containers/hashmap.h"
+#include "src/tint/utils/containers/unique_vector.h"
+
+// Forward declarations.
+namespace tint::core::ir {
+class Block;
+class Function;
+} // namespace tint::core::ir
+
+namespace tint::core::ir {
+
+/// ReferencedModuleVars is a helper to determine the set of module-scope variables that are
+/// transitively referenced by functions in a module.
+/// References are determined lazily and cached for future requests.
+///
+/// Note: changes to the module can invalidate the cached data. This is intended to be created by
+/// a transform that need this information, and discarded when that transform completes. Tracking
+/// this information inside the IR module would add overhead any time an instruction is added or
+/// removed from the module. Since only a few transforms need this information, we expect it to be
+/// more efficient to generate it as and when needed instead.
+class ReferencedModuleVars {
+ public:
+ /// The signature of a predicate used to filter variables.
+ /// A predicate function should return `true` when the variable should be added to the set.
+ using Predicate = std::function<bool(const Var*)>;
+
+ /// A set of a variables referenced by a function (in declaration order).
+ using VarSet = UniqueVector<Var*, 16>;
+
+ /// Constructor.
+ /// @param ir the module
+ /// @param pred an optional predicate function for filtering variables
+ /// Note: @p pred is not stored by the class, so can be a lambda that captures by reference.
+ explicit ReferencedModuleVars(Module& ir, Predicate&& pred = {}) : ir_(ir) {
+ // Loop over module-scope variables, recording the blocks that they are referenced from.
+ for (auto inst : *ir_.root_block) {
+ if (auto* var = inst->As<Var>()) {
+ if (!pred || pred(var)) {
+ var->Result(0)->ForEachUse([&](const Usage& use) {
+ block_to_direct_vars_.GetOrAddZero(use.instruction->Block()).Add(var);
+ });
+ }
+ }
+ }
+ }
+
+ /// Get the set of transitively referenced module-scope variables for a function, filtered by
+ /// the predicate function if provided.
+ /// @param func the function
+ /// @returns the set of (possibly filtered) transitively reference module-scope variables
+ const VarSet& TransitiveReferences(Function* func);
+
+ private:
+ /// The module.
+ Module& ir_;
+
+ /// A map from blocks to their directly referenced variables.
+ Hashmap<Block*, VarSet, 64> block_to_direct_vars_{};
+
+ /// A map from functions to their transitively referenced variables.
+ Hashmap<Function*, VarSet, 8> transitive_references_;
+
+ /// Get the set of transitively referenced module-scope variables for a block.
+ /// @param block the block
+ /// @param vars the set of transitively reference module-scope variables to populate
+ void GetTransitiveReferences(Block* block, VarSet& vars);
+};
+
+} // namespace tint::core::ir
+
+#endif // SRC_TINT_LANG_CORE_IR_TRANSFORM_COMMON_REFERENCED_MODULE_VARS_H_
diff --git a/src/tint/lang/core/ir/transform/common/referenced_module_vars_test.cc b/src/tint/lang/core/ir/transform/common/referenced_module_vars_test.cc
new file mode 100644
index 0000000..3a5a032
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/common/referenced_module_vars_test.cc
@@ -0,0 +1,422 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/core/ir/transform/common/referenced_module_vars.h"
+
+#include <string>
+
+#include "gmock/gmock.h"
+#include "src/tint/lang/core/ir/disassembly.h"
+#include "src/tint/lang/core/ir/ir_helper_test.h"
+
+namespace tint::core::ir {
+namespace {
+
+using ::testing::ElementsAre;
+
+using namespace tint::core::fluent_types; // NOLINT
+using namespace tint::core::number_suffixes; // NOLINT
+
+class IR_ReferencedModuleVarsTest : public IRTestHelper {
+ protected:
+ /// @returns the module as a disassembled string
+ std::string Disassemble() const { return "\n" + ir::Disassemble(mod).Plain(); }
+};
+
+TEST_F(IR_ReferencedModuleVarsTest, EmptyRootBlock) {
+ auto* foo = b.Function("foo", ty.void_());
+ b.Append(foo->Block(), [&] { //
+ b.Return(foo);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, Disassemble());
+
+ ReferencedModuleVars vars(mod);
+ auto& foo_vars = vars.TransitiveReferences(foo);
+ EXPECT_TRUE(foo_vars.IsEmpty());
+}
+
+TEST_F(IR_ReferencedModuleVarsTest, DirectUse) {
+ // Referenced.
+ auto* var_a = mod.root_block->Append(b.Var<workgroup, u32>("a"));
+ auto* var_b = mod.root_block->Append(b.Var<workgroup, u32>("b"));
+ // Not referenced.
+ mod.root_block->Append(b.Var<workgroup, u32>("c"));
+
+ auto* foo = b.Function("foo", ty.void_());
+ b.Append(foo->Block(), [&] { //
+ b.Load(var_a);
+ b.Load(var_b);
+ b.Return(foo);
+ });
+
+ auto* src = R"(
+$B1: { # root
+ %a:ptr<workgroup, u32, read_write> = var
+ %b:ptr<workgroup, u32, read_write> = var
+ %c:ptr<workgroup, u32, read_write> = var
+}
+
+%foo = func():void {
+ $B2: {
+ %5:u32 = load %a
+ %6:u32 = load %b
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, Disassemble());
+
+ ReferencedModuleVars vars(mod);
+ EXPECT_THAT(vars.TransitiveReferences(foo), ElementsAre(var_a, var_b));
+}
+
+TEST_F(IR_ReferencedModuleVarsTest, DirectUse_DeclarationOrder) {
+ auto* var_a = mod.root_block->Append(b.Var<workgroup, u32>("a"));
+ auto* var_b = mod.root_block->Append(b.Var<workgroup, u32>("b"));
+ auto* var_c = mod.root_block->Append(b.Var<workgroup, u32>("c"));
+ auto* var_d = mod.root_block->Append(b.Var<workgroup, u32>("d"));
+ auto* var_e = mod.root_block->Append(b.Var<workgroup, u32>("e"));
+
+ auto* foo = b.Function("foo", ty.void_());
+ b.Append(foo->Block(), [&] { //
+ b.Load(var_b);
+ b.Load(var_e);
+ b.Load(var_d);
+ b.Load(var_c);
+ b.Load(var_a);
+ b.Return(foo);
+ });
+
+ auto* src = R"(
+$B1: { # root
+ %a:ptr<workgroup, u32, read_write> = var
+ %b:ptr<workgroup, u32, read_write> = var
+ %c:ptr<workgroup, u32, read_write> = var
+ %d:ptr<workgroup, u32, read_write> = var
+ %e:ptr<workgroup, u32, read_write> = var
+}
+
+%foo = func():void {
+ $B2: {
+ %7:u32 = load %b
+ %8:u32 = load %e
+ %9:u32 = load %d
+ %10:u32 = load %c
+ %11:u32 = load %a
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, Disassemble());
+
+ ReferencedModuleVars vars(mod);
+ EXPECT_THAT(vars.TransitiveReferences(foo), ElementsAre(var_a, var_b, var_c, var_d, var_e));
+}
+
+TEST_F(IR_ReferencedModuleVarsTest, DirectUse_MultipleFunctions) {
+ auto* var_a = mod.root_block->Append(b.Var<workgroup, u32>("a"));
+ auto* var_b = mod.root_block->Append(b.Var<workgroup, u32>("b"));
+ auto* var_c = mod.root_block->Append(b.Var<workgroup, u32>("c"));
+
+ auto* foo = b.Function("foo", ty.void_());
+ b.Append(foo->Block(), [&] { //
+ b.Load(var_a);
+ b.Load(var_b);
+ b.Return(foo);
+ });
+
+ auto* bar = b.Function("bar", ty.void_());
+ b.Append(bar->Block(), [&] { //
+ b.Load(var_a);
+ b.Load(var_c);
+ b.Return(bar);
+ });
+
+ auto* zoo = b.Function("zoo", ty.void_());
+ b.Append(zoo->Block(), [&] { //
+ b.Return(zoo);
+ });
+
+ auto* src = R"(
+$B1: { # root
+ %a:ptr<workgroup, u32, read_write> = var
+ %b:ptr<workgroup, u32, read_write> = var
+ %c:ptr<workgroup, u32, read_write> = var
+}
+
+%foo = func():void {
+ $B2: {
+ %5:u32 = load %a
+ %6:u32 = load %b
+ ret
+ }
+}
+%bar = func():void {
+ $B3: {
+ %8:u32 = load %a
+ %9:u32 = load %c
+ ret
+ }
+}
+%zoo = func():void {
+ $B4: {
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, Disassemble());
+
+ ReferencedModuleVars vars(mod);
+ EXPECT_THAT(vars.TransitiveReferences(foo), ElementsAre(var_a, var_b));
+ EXPECT_THAT(vars.TransitiveReferences(bar), ElementsAre(var_a, var_c));
+ EXPECT_TRUE(vars.TransitiveReferences(zoo).IsEmpty());
+}
+
+TEST_F(IR_ReferencedModuleVarsTest, DirectUse_NestedInControlFlow) {
+ auto* var_a = mod.root_block->Append(b.Var<workgroup, u32>("a"));
+ auto* var_b = mod.root_block->Append(b.Var<workgroup, u32>("b"));
+ auto* var_c = mod.root_block->Append(b.Var<workgroup, u32>("c"));
+ auto* var_d = mod.root_block->Append(b.Var<workgroup, u32>("c"));
+
+ auto* foo = b.Function("foo", ty.void_());
+ b.Append(foo->Block(), [&] { //
+ auto* ifelse = b.If(true);
+ b.Append(ifelse->True(), [&] {
+ b.Load(var_a);
+ b.ExitIf(ifelse);
+ });
+ b.Append(ifelse->False(), [&] {
+ auto* loop = b.Loop();
+ b.Append(loop->Initializer(), [&] {
+ b.Load(var_b);
+ b.NextIteration(loop);
+ });
+ b.Append(loop->Body(), [&] {
+ b.Load(var_c);
+ b.Continue(loop);
+ });
+ b.Append(loop->Continuing(), [&] {
+ b.Load(var_d);
+ b.NextIteration(loop);
+ });
+ b.ExitIf(ifelse);
+ });
+ b.Return(foo);
+ });
+
+ auto* src = R"(
+$B1: { # root
+ %a:ptr<workgroup, u32, read_write> = var
+ %b:ptr<workgroup, u32, read_write> = var
+ %c:ptr<workgroup, u32, read_write> = var
+ %c_1:ptr<workgroup, u32, read_write> = var # %c_1: 'c'
+}
+
+%foo = func():void {
+ $B2: {
+ if true [t: $B3, f: $B4] { # if_1
+ $B3: { # true
+ %6:u32 = load %a
+ exit_if # if_1
+ }
+ $B4: { # false
+ loop [i: $B5, b: $B6, c: $B7] { # loop_1
+ $B5: { # initializer
+ %7:u32 = load %b
+ next_iteration # -> $B6
+ }
+ $B6: { # body
+ %8:u32 = load %c
+ continue # -> $B7
+ }
+ $B7: { # continuing
+ %9:u32 = load %c_1
+ next_iteration # -> $B6
+ }
+ }
+ exit_if # if_1
+ }
+ }
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, Disassemble());
+
+ ReferencedModuleVars vars(mod);
+ EXPECT_THAT(vars.TransitiveReferences(foo), ElementsAre(var_a, var_b, var_c, var_d));
+}
+
+TEST_F(IR_ReferencedModuleVarsTest, IndirectUse) {
+ // Directly used by foo.
+ auto* var_a = mod.root_block->Append(b.Var<workgroup, u32>("a"));
+ // Directly used by bar, called by zoo and foo.
+ auto* var_b = mod.root_block->Append(b.Var<workgroup, u32>("b"));
+ // Not used.
+ mod.root_block->Append(b.Var<workgroup, u32>("c"));
+
+ auto* bar = b.Function("bar", ty.void_());
+ b.Append(bar->Block(), [&] { //
+ b.Load(var_b);
+ b.Return(bar);
+ });
+
+ auto* zoo = b.Function("zoo", ty.void_());
+ b.Append(zoo->Block(), [&] { //
+ b.Call(bar);
+ b.Return(zoo);
+ });
+
+ auto* foo = b.Function("foo", ty.void_());
+ b.Append(foo->Block(), [&] { //
+ b.Load(var_a);
+ b.Call(zoo);
+ b.Return(foo);
+ });
+
+ auto* src = R"(
+$B1: { # root
+ %a:ptr<workgroup, u32, read_write> = var
+ %b:ptr<workgroup, u32, read_write> = var
+ %c:ptr<workgroup, u32, read_write> = var
+}
+
+%bar = func():void {
+ $B2: {
+ %5:u32 = load %b
+ ret
+ }
+}
+%zoo = func():void {
+ $B3: {
+ %7:void = call %bar
+ ret
+ }
+}
+%foo = func():void {
+ $B4: {
+ %9:u32 = load %a
+ %10:void = call %zoo
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, Disassemble());
+
+ ReferencedModuleVars vars(mod);
+ EXPECT_THAT(vars.TransitiveReferences(bar), ElementsAre(var_b));
+ EXPECT_THAT(vars.TransitiveReferences(zoo), ElementsAre(var_b));
+ EXPECT_THAT(vars.TransitiveReferences(foo), ElementsAre(var_a, var_b));
+}
+
+TEST_F(IR_ReferencedModuleVarsTest, NoFunctionVars) {
+ auto* var_a = mod.root_block->Append(b.Var<workgroup, u32>("a"));
+
+ auto* foo = b.Function("foo", ty.void_());
+ b.Append(foo->Block(), [&] { //
+ auto* var_b = b.Var<function, u32>("b");
+ b.Load(var_a);
+ b.Load(var_b);
+ b.Return(foo);
+ });
+
+ auto* src = R"(
+$B1: { # root
+ %a:ptr<workgroup, u32, read_write> = var
+}
+
+%foo = func():void {
+ $B2: {
+ %b:ptr<function, u32, read_write> = var
+ %4:u32 = load %a
+ %5:u32 = load %b
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, Disassemble());
+
+ ReferencedModuleVars vars(mod);
+ EXPECT_THAT(vars.TransitiveReferences(foo), ElementsAre(var_a));
+}
+
+TEST_F(IR_ReferencedModuleVarsTest, Predicate) {
+ auto* var_a = mod.root_block->Append(b.Var<workgroup, u32>("a"));
+ auto* var_b = mod.root_block->Append(b.Var<private_, u32>("b"));
+ auto* var_c = mod.root_block->Append(b.Var<workgroup, u32>("c"));
+ auto* var_d = mod.root_block->Append(b.Var<private_, u32>("d"));
+ auto* var_e = mod.root_block->Append(b.Var<workgroup, u32>("e"));
+
+ auto* foo = b.Function("foo", ty.void_());
+ b.Append(foo->Block(), [&] { //
+ b.Load(var_a);
+ b.Load(var_b);
+ b.Load(var_c);
+ b.Load(var_d);
+ b.Load(var_e);
+ b.Return(foo);
+ });
+
+ auto* src = R"(
+$B1: { # root
+ %a:ptr<workgroup, u32, read_write> = var
+ %b:ptr<private, u32, read_write> = var
+ %c:ptr<workgroup, u32, read_write> = var
+ %d:ptr<private, u32, read_write> = var
+ %e:ptr<workgroup, u32, read_write> = var
+}
+
+%foo = func():void {
+ $B2: {
+ %7:u32 = load %a
+ %8:u32 = load %b
+ %9:u32 = load %c
+ %10:u32 = load %d
+ %11:u32 = load %e
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, Disassemble());
+
+ ReferencedModuleVars vars(mod, [](const Var* var) {
+ auto* view = var->Result(0)->Type()->As<type::MemoryView>();
+ return view->AddressSpace() == AddressSpace::kPrivate;
+ });
+ EXPECT_THAT(vars.TransitiveReferences(foo), ElementsAre(var_b, var_d));
+}
+
+} // namespace
+} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
index 26cbf76..8969c9f 100644
--- a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
@@ -32,6 +32,7 @@
#include "src/tint/lang/core/ir/builder.h"
#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/core/ir/transform/common/referenced_module_vars.h"
#include "src/tint/lang/core/ir/validator.h"
#include "src/tint/utils/containers/reverse.h"
@@ -61,17 +62,12 @@
/// The type manager.
core::type::Manager& ty{ir.Types()};
- /// VarSet is a hash set of workgroup variables.
- using VarSet = Hashset<Var*, 8>;
-
- /// A map from variable to an ID used for sorting.
- Hashmap<Var*, uint32_t, 8> var_to_id{};
-
- /// A map from blocks to their directly referenced workgroup variables.
- Hashmap<Block*, VarSet, 64> block_to_direct_vars{};
-
- /// A map from functions to their transitively referenced workgroup variables.
- Hashmap<Function*, VarSet, 8> function_to_transitive_vars{};
+ /// The mapping from functions to their transitively referenced workgroup variables.
+ ReferencedModuleVars referenced_module_vars_{
+ ir, [](const Var* var) {
+ auto* view = var->Result(0)->Type()->As<type::MemoryView>();
+ return view && view->AddressSpace() == AddressSpace::kWorkgroup;
+ }};
/// ArrayIndex represents a required array index for an access instruction.
struct ArrayIndex {
@@ -104,22 +100,6 @@
if (ir.root_block->IsEmpty()) {
return;
}
-
- // Loop over module-scope variables, looking for workgroup variables.
- uint32_t next_id = 0;
- for (auto inst : *ir.root_block) {
- if (auto* var = inst->As<Var>()) {
- auto* ptr = var->Result(0)->Type()->As<core::type::Pointer>();
- if (ptr && ptr->AddressSpace() == core::AddressSpace::kWorkgroup) {
- // Record the usage of the variable for each block that references it.
- var->Result(0)->ForEachUse([&](const Usage& use) {
- block_to_direct_vars.GetOrAddZero(use.instruction->Block()).Add(var);
- });
- var_to_id.Add(var, next_id++);
- }
- }
- }
-
// Process each entry point function.
for (auto& func : ir.functions) {
if (func->Stage() == Function::PipelineStage::kCompute) {
@@ -132,20 +112,14 @@
/// @param func the entry point function
void ProcessEntryPoint(Function* func) {
// Get list of transitively referenced workgroup variables.
- auto vars = GetReferencedVars(func);
+ const auto& vars = referenced_module_vars_.TransitiveReferences(func);
if (vars.IsEmpty()) {
return;
}
- // Sort the variables to get deterministic output in tests.
- auto sorted_vars = vars.Vector();
- sorted_vars.Sort([&](Var* first, Var* second) {
- return *var_to_id.Get(first) < *var_to_id.Get(second);
- });
-
// Build list of store descriptors for all workgroup variables.
StoreMap stores;
- for (auto* var : sorted_vars) {
+ for (auto* var : vars) {
PrepareStores(var, var->Result(0)->Type()->UnwrapPtr(), 1, {}, stores);
}
@@ -188,46 +162,6 @@
});
}
- /// Get the set of workgroup variables transitively referenced by @p func.
- /// @param func the function
- /// @returns the set of transitively referenced workgroup variables
- VarSet GetReferencedVars(Function* func) {
- return function_to_transitive_vars.GetOrAdd(func, [&] {
- VarSet vars;
- GetReferencedVars(func->Block(), vars);
- return vars;
- });
- }
-
- /// Get the set of workgroup variables transitively referenced by @p block.
- /// @param block the block
- /// @param vars the set of transitively referenced workgroup variables to populate
- void GetReferencedVars(Block* block, VarSet& vars) {
- // Add directly referenced vars.
- if (auto itr = block_to_direct_vars.Get(block)) {
- for (auto& var : *itr) {
- vars.Add(var);
- }
- }
-
- // Loop over instructions in the block.
- for (auto* inst : *block) {
- tint::Switch(
- inst,
- [&](UserCall* call) {
- // Get variables referenced by a function called from this block.
- auto callee_vars = GetReferencedVars(call->Target());
- for (auto& var : callee_vars) {
- vars.Add(var);
- }
- },
- [&](ControlInstruction* ctrl) {
- // Recurse into control instructions and gather their referenced vars.
- ctrl->ForeachBlock([&](Block* blk) { GetReferencedVars(blk, vars); });
- });
- }
- }
-
/// Recursively generate store descriptors for a workgroup variable.
/// Determines the combined array iteration count of each inner element.
/// @param var the workgroup variable
diff --git a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory_test.cc b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory_test.cc
index bf1a82b..1843665 100644
--- a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory_test.cc
+++ b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory_test.cc
@@ -102,6 +102,48 @@
EXPECT_EQ(expect, str());
}
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, NonWorkgroupVar) {
+ auto* var = b.Var("pvar", ty.ptr(private_, ty.bool_()));
+ mod.root_block->Append(var);
+
+ auto* func = MakeEntryPoint("main", 1, 1, 1);
+ b.Append(func->Block(), [&] { //
+ b.Load(var);
+ b.Return(func);
+ });
+
+ auto* src = R"(
+$B1: { # root
+ %pvar:ptr<private, bool, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void {
+ $B2: {
+ %3:bool = load %pvar
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+$B1: { # root
+ %pvar:ptr<private, bool, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void {
+ $B2: {
+ %3:bool = load %pvar
+ ret
+ }
+}
+)";
+
+ Run(ZeroInitWorkgroupMemory);
+
+ EXPECT_EQ(expect, str());
+}
+
TEST_F(IR_ZeroInitWorkgroupMemoryTest, ScalarBool) {
auto* var = MakeVar("wgvar", ty.bool_());