Import Tint changes from Dawn
Changes:
- ca3c3f474ad7a599843ea0281c92a43b12ac9af9 Update ir::builder includes. by dan sinclair <dsinclair@chromium.org>
- 1caf8c690ce75667a38d7fce4ab2886f8fc66b98 Cleanup some includes by dan sinclair <dsinclair@chromium.org>
- 2320e63eb964badefc9166be1c07d0a516b87e63 Add check for option to tint::glsl::writer::ASTFuzzer by Ryan Harrison <rharrison@chromium.org>
- 9f0b65f8a6eefb2b7960522c701946c60fa07489 Remove unused inferred template default parameter. by dan sinclair <dsinclair@chromium.org>
- 7eb5f8c515572ac254338f18feae8dc1f47c69b7 [spirv] Fix terminator creation in MergeReturn by James Price <jrprice@google.com>
- e93ab20875ca3303ab2a1bc543debdda83c755f6 [tint][wgsl][fuzz] Add more to dictionary.txt by Ben Clayton <bclayton@google.com>
- 1b0c89597857ca23dbdd33f2b472b222915af08e [ir] Fix store target validation highlight by James Price <jrprice@google.com>
- 77ac3f1ee9557561e80f8df2391381496a96d01f [ir] Add RemoveTerminatorArgs transform by James Price <jrprice@google.com>
- 1ffa4e1ee10b3c2a81d64ecb3efc46b827874d2d [tintd] Allow all extensions and features by James Price <jrprice@google.com>
GitOrigin-RevId: ca3c3f474ad7a599843ea0281c92a43b12ac9af9
Change-Id: I2b9f8c7144fe38fe5c32b1b93139ed6c648f2ca6
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/191080
Commit-Queue: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/cmd/fuzz/wgsl/dictionary.txt b/src/tint/cmd/fuzz/wgsl/dictionary.txt
index a9118b3..1adc488 100644
--- a/src/tint/cmd/fuzz/wgsl/dictionary.txt
+++ b/src/tint/cmd/fuzz/wgsl/dictionary.txt
@@ -57,7 +57,10 @@
"/"
"// AAAA"
"// AAAB"
+"// ABBB"
"// BAAA"
+"// BBBA"
+"// BBBB"
"/="
":"
";"
@@ -215,6 +218,7 @@
"fma"
"fn"
"for"
+"for (;true;) {}"
"fract"
"frag_depth"
"fragment"
diff --git a/src/tint/cmd/fuzz/wgsl/dictionary.txt.tmpl b/src/tint/cmd/fuzz/wgsl/dictionary.txt.tmpl
index e5605d7..2655ada 100644
--- a/src/tint/cmd/fuzz/wgsl/dictionary.txt.tmpl
+++ b/src/tint/cmd/fuzz/wgsl/dictionary.txt.tmpl
@@ -108,8 +108,16 @@
{{- /* =========================== Base64 comments =========================== */ -}}
{{- $tokens = Append $tokens
"// AAAA"
- "// BAAA"
"// AAAB"
+ "// ABBB"
+ "// BAAA"
+ "// BBBA"
+ "// BBBB"
+-}}
+
+{{- /* ========================= Interesting patterns ======================== */ -}}
+{{- $tokens = Append $tokens
+ "for (;true;) {}"
-}}
{{- /* ========================== Builtin functions ========================== */ -}}
diff --git a/src/tint/lang/core/fluent_types.h b/src/tint/lang/core/fluent_types.h
index 2d347a0..a67135a 100644
--- a/src/tint/lang/core/fluent_types.h
+++ b/src/tint/lang/core/fluent_types.h
@@ -50,7 +50,7 @@
/// @tparam T the array element type
/// @tparam N the array length. 0 represents a runtime-sized array.
/// @see https://www.w3.org/TR/WGSL/#array-types
-template <typename T = Infer, uint32_t N = 0>
+template <typename T, uint32_t N = 0>
struct array {
/// the array element type
using type = T;
@@ -70,7 +70,7 @@
/// A 'fluent' type helper used to construct an ast::Vector or type::Vector.
/// @tparam N the vector width
/// @tparam T the vector element type
-template <uint32_t N, typename T = Infer>
+template <uint32_t N, typename T>
struct vec {
/// the vector width
static constexpr uint32_t width = N;
@@ -83,7 +83,7 @@
/// @tparam R the number of rows of the matrix
/// @tparam T the matrix element type
/// @see https://www.w3.org/TR/WGSL/#matrix-types
-template <uint32_t C, uint32_t R, typename T = Infer>
+template <uint32_t C, uint32_t R, typename T>
struct mat {
/// the number of columns of the matrix
static constexpr uint32_t columns = C;
diff --git a/src/tint/lang/core/ir/builder.h b/src/tint/lang/core/ir/builder.h
index 48cad54..9e4f75e 100644
--- a/src/tint/lang/core/ir/builder.h
+++ b/src/tint/lang/core/ir/builder.h
@@ -30,9 +30,8 @@
#include <utility>
-#include "src/tint/lang/core/constant/composite.h"
-#include "src/tint/lang/core/constant/scalar.h"
-#include "src/tint/lang/core/constant/splat.h"
+#include "src/tint/lang/core/constant/scalar.h" // IWYU pragma: export
+#include "src/tint/lang/core/constant/splat.h" // IWYU pragma: export
#include "src/tint/lang/core/ir/access.h"
#include "src/tint/lang/core/ir/bitcast.h"
#include "src/tint/lang/core/ir/block_param.h"
@@ -69,16 +68,17 @@
#include "src/tint/lang/core/ir/user_call.h"
#include "src/tint/lang/core/ir/value.h"
#include "src/tint/lang/core/ir/var.h"
-#include "src/tint/lang/core/type/array.h"
-#include "src/tint/lang/core/type/bool.h"
-#include "src/tint/lang/core/type/f16.h"
-#include "src/tint/lang/core/type/f32.h"
-#include "src/tint/lang/core/type/i32.h"
+#include "src/tint/lang/core/type/array.h" // IWYU pragma: export
+#include "src/tint/lang/core/type/bool.h" // IWYU pragma: export
+#include "src/tint/lang/core/type/f16.h" // IWYU pragma: export
+#include "src/tint/lang/core/type/f32.h" // IWYU pragma: export
+#include "src/tint/lang/core/type/i32.h" // IWYU pragma: export
#include "src/tint/lang/core/type/matrix.h"
-#include "src/tint/lang/core/type/pointer.h"
-#include "src/tint/lang/core/type/u32.h"
+#include "src/tint/lang/core/type/memory_view.h"
+#include "src/tint/lang/core/type/pointer.h" // IWYU pragma: export
+#include "src/tint/lang/core/type/u32.h" // IWYU pragma: export
#include "src/tint/lang/core/type/vector.h"
-#include "src/tint/lang/core/type/void.h"
+#include "src/tint/lang/core/type/void.h" // IWYU pragma: export
#include "src/tint/utils/ice/ice.h"
#include "src/tint/utils/macros/scoped_assignment.h"
#include "src/tint/utils/rtti/switch.h"
diff --git a/src/tint/lang/core/ir/load_test.cc b/src/tint/lang/core/ir/load_test.cc
index 62977b3..5cf8a63 100644
--- a/src/tint/lang/core/ir/load_test.cc
+++ b/src/tint/lang/core/ir/load_test.cc
@@ -27,7 +27,6 @@
#include "gmock/gmock.h"
#include "src/tint/lang/core/ir/builder.h"
-#include "src/tint/lang/core/ir/instruction.h"
#include "src/tint/lang/core/ir/ir_helper_test.h"
namespace tint::core::ir {
diff --git a/src/tint/lang/core/ir/transform/BUILD.bazel b/src/tint/lang/core/ir/transform/BUILD.bazel
index 6444ea9..3bdcfad 100644
--- a/src/tint/lang/core/ir/transform/BUILD.bazel
+++ b/src/tint/lang/core/ir/transform/BUILD.bazel
@@ -52,6 +52,7 @@
"direct_variable_access.cc",
"multiplanar_external_texture.cc",
"preserve_padding.cc",
+ "remove_terminator_args.cc",
"robustness.cc",
"shader_io.cc",
"std140.cc",
@@ -73,6 +74,7 @@
"direct_variable_access.h",
"multiplanar_external_texture.h",
"preserve_padding.h",
+ "remove_terminator_args.h",
"robustness.h",
"shader_io.h",
"std140.h",
@@ -124,6 +126,7 @@
"helper_test.h",
"multiplanar_external_texture_test.cc",
"preserve_padding_test.cc",
+ "remove_terminator_args_test.cc",
"robustness_test.cc",
"std140_test.cc",
"value_to_let_test.cc",
diff --git a/src/tint/lang/core/ir/transform/BUILD.cmake b/src/tint/lang/core/ir/transform/BUILD.cmake
index d8c3431..6713300 100644
--- a/src/tint/lang/core/ir/transform/BUILD.cmake
+++ b/src/tint/lang/core/ir/transform/BUILD.cmake
@@ -67,6 +67,8 @@
lang/core/ir/transform/multiplanar_external_texture.h
lang/core/ir/transform/preserve_padding.cc
lang/core/ir/transform/preserve_padding.h
+ lang/core/ir/transform/remove_terminator_args.cc
+ lang/core/ir/transform/remove_terminator_args.h
lang/core/ir/transform/robustness.cc
lang/core/ir/transform/robustness.h
lang/core/ir/transform/shader_io.cc
@@ -124,6 +126,7 @@
lang/core/ir/transform/helper_test.h
lang/core/ir/transform/multiplanar_external_texture_test.cc
lang/core/ir/transform/preserve_padding_test.cc
+ lang/core/ir/transform/remove_terminator_args_test.cc
lang/core/ir/transform/robustness_test.cc
lang/core/ir/transform/std140_test.cc
lang/core/ir/transform/value_to_let_test.cc
@@ -204,6 +207,7 @@
lang/core/ir/transform/direct_variable_access_fuzz.cc
lang/core/ir/transform/multiplanar_external_texture_fuzz.cc
lang/core/ir/transform/preserve_padding_fuzz.cc
+ lang/core/ir/transform/remove_terminator_args_fuzz.cc
lang/core/ir/transform/robustness_fuzz.cc
lang/core/ir/transform/std140_fuzz.cc
lang/core/ir/transform/value_to_let_fuzz.cc
diff --git a/src/tint/lang/core/ir/transform/BUILD.gn b/src/tint/lang/core/ir/transform/BUILD.gn
index 16765ad..131161f 100644
--- a/src/tint/lang/core/ir/transform/BUILD.gn
+++ b/src/tint/lang/core/ir/transform/BUILD.gn
@@ -70,6 +70,8 @@
"multiplanar_external_texture.h",
"preserve_padding.cc",
"preserve_padding.h",
+ "remove_terminator_args.cc",
+ "remove_terminator_args.h",
"robustness.cc",
"robustness.h",
"shader_io.cc",
@@ -124,6 +126,7 @@
"helper_test.h",
"multiplanar_external_texture_test.cc",
"preserve_padding_test.cc",
+ "remove_terminator_args_test.cc",
"robustness_test.cc",
"std140_test.cc",
"value_to_let_test.cc",
@@ -195,6 +198,7 @@
"direct_variable_access_fuzz.cc",
"multiplanar_external_texture_fuzz.cc",
"preserve_padding_fuzz.cc",
+ "remove_terminator_args_fuzz.cc",
"robustness_fuzz.cc",
"std140_fuzz.cc",
"value_to_let_fuzz.cc",
diff --git a/src/tint/lang/core/ir/transform/remove_terminator_args.cc b/src/tint/lang/core/ir/transform/remove_terminator_args.cc
new file mode 100644
index 0000000..dfe865b
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/remove_terminator_args.cc
@@ -0,0 +1,177 @@
+// 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/remove_terminator_args.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/ir/builder.h"
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/core/ir/validator.h"
+
+using namespace tint::core::fluent_types; // NOLINT
+using namespace tint::core::number_suffixes; // NOLINT
+
+namespace tint::core::ir::transform {
+
+namespace {
+
+/// PIMPL state for the transform.
+struct State {
+ /// The IR module.
+ Module& ir;
+
+ /// The IR builder.
+ Builder b{ir};
+
+ /// The type manager.
+ core::type::Manager& ty{ir.Types()};
+
+ /// A list of terminators that need to have their arguments cleared.
+ Vector<Terminator*, 8> terminators_to_clear{};
+
+ /// Process the module.
+ void Process() {
+ // Loop over every instruction looking for control instructions.
+ for (auto* inst : ir.Instructions()) {
+ tint::Switch(
+ inst,
+ [&](If* i) { //
+ RemoveExitArgs(i);
+ },
+ [&](Loop* l) { //
+ RemoveExitArgs(l);
+ RemoveBlockParams(l->Body(), l->Initializer()->Front());
+ RemoveBlockParams(l->Continuing(), l->Body()->Front());
+ },
+ [&](Switch* s) { //
+ RemoveExitArgs(s);
+ });
+
+ // Remove arguments from all terminators that we found.
+ for (auto* terminator : terminators_to_clear) {
+ if (auto* breakif = terminator->As<BreakIf>()) {
+ // We retain the condition operand on break_if instructions.
+ breakif->SetOperands(Vector{breakif->Condition()});
+ } else {
+ terminator->ClearOperands();
+ }
+ }
+ terminators_to_clear.Clear();
+ }
+ }
+
+ /// Remove the arguments from all exit instructions inside a control instruction.
+ /// @param ci the control instruction
+ void RemoveExitArgs(ControlInstruction* ci) {
+ // Loop over all of the instruction results.
+ for (size_t i = 0; i < ci->Results().Length(); i++) {
+ auto* result = ci->Result(i);
+
+ // Create a variable to hold the result, and insert it before the control instruction.
+ auto* var = b.Var(ty.ptr<function>(result->Type()));
+ var->InsertBefore(ci);
+
+ // Store to the variable before each exit instruction.
+ for (auto exit : ci->Exits()) {
+ Value* value = nullptr;
+ if (auto* breakif = exit.Value()->As<BreakIf>()) {
+ value = breakif->ExitValues()[i];
+ } else {
+ value = exit.Value()->Args()[i];
+ }
+ if (value) {
+ auto* store = b.Store(var, value);
+ store->InsertBefore(exit.Value());
+ }
+ }
+
+ // Replace the original result with a load from the variable that we created above.
+ auto* load = b.LoadWithResult(result, var);
+ load->InsertAfter(ci);
+ }
+
+ // Remove the arguments from the exits and the results from the control instruction.
+ for (auto exit : ci->Exits()) {
+ terminators_to_clear.Push(exit);
+ }
+ ci->ClearResults();
+ }
+
+ /// Remove block parameters and arguments from all branches to a block.
+ /// @param block the block
+ /// @param var_insertion_point the insertion point for variables used to replace parameters
+ void RemoveBlockParams(MultiInBlock* block, Instruction* var_insertion_point) {
+ for (size_t i = 0; i < block->Params().Length(); i++) {
+ auto* param = block->Params()[i];
+
+ // Create a variable to hold the parameter value, and insert it in the parent block.
+ auto* var = b.Var(ty.ptr<function>(param->Type()));
+ var->InsertBefore(var_insertion_point);
+
+ // Store to the variable before each branch.
+ for (auto* branch : block->InboundSiblingBranches()) {
+ Value* value = nullptr;
+ if (auto* breakif = branch->As<BreakIf>()) {
+ value = breakif->NextIterValues()[i];
+ } else {
+ value = branch->Args()[i];
+ }
+ if (value) {
+ auto* store = b.Store(var, value);
+ store->InsertBefore(branch);
+ }
+ }
+
+ // Replace the original result with a load from the variable that we created above.
+ auto* load = b.Load(var);
+ load->InsertBefore(block->Front());
+ param->ReplaceAllUsesWith(load->Result(0));
+ }
+
+ // Remove the arguments from the branches and the parameters from the block.
+ for (auto exit : block->InboundSiblingBranches()) {
+ terminators_to_clear.Push(exit);
+ }
+ block->SetParams({});
+ }
+};
+
+} // namespace
+
+Result<SuccessType> RemoveTerminatorArgs(Module& ir) {
+ auto result = ValidateAndDumpIfNeeded(ir, "RemoveTerminatorArgs transform");
+ if (result != Success) {
+ return result;
+ }
+
+ State{ir}.Process();
+
+ return Success;
+}
+
+} // namespace tint::core::ir::transform
diff --git a/src/tint/lang/core/ir/transform/remove_terminator_args.h b/src/tint/lang/core/ir/transform/remove_terminator_args.h
new file mode 100644
index 0000000..98fbc65
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/remove_terminator_args.h
@@ -0,0 +1,49 @@
+// 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_REMOVE_TERMINATOR_ARGS_H_
+#define SRC_TINT_LANG_CORE_IR_TRANSFORM_REMOVE_TERMINATOR_ARGS_H_
+
+#include "src/tint/utils/result/result.h"
+
+// Forward declarations.
+namespace tint::core::ir {
+class Module;
+}
+
+namespace tint::core::ir::transform {
+
+/// RemoveTerminatorArgs is a transform that removes all arguments from terminator instructions and
+/// replaces them with stores to temporary variables instead. This is needed to prepare codegen for
+/// textual languages.
+/// @param module the module to transform
+/// @returns success or failure
+Result<SuccessType> RemoveTerminatorArgs(Module& module);
+
+} // namespace tint::core::ir::transform
+
+#endif // SRC_TINT_LANG_CORE_IR_TRANSFORM_REMOVE_TERMINATOR_ARGS_H_
diff --git a/src/tint/lang/core/ir/transform/remove_terminator_args_fuzz.cc b/src/tint/lang/core/ir/transform/remove_terminator_args_fuzz.cc
new file mode 100644
index 0000000..4cefe7f
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/remove_terminator_args_fuzz.cc
@@ -0,0 +1,50 @@
+// 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/remove_terminator_args.h"
+
+#include "src/tint/cmd/fuzz/ir/fuzz.h"
+#include "src/tint/lang/core/ir/validator.h"
+
+namespace tint::core::ir::transform {
+namespace {
+
+void RemoveTerminatorArgsFuzzer(Module& module) {
+ if (auto res = RemoveTerminatorArgs(module); res != Success) {
+ return;
+ }
+
+ Capabilities capabilities;
+ if (auto res = Validate(module, capabilities); res != Success) {
+ TINT_ICE() << "result of RemoveTerminatorArgs failed IR validation\n" << res.Failure();
+ }
+}
+
+} // namespace
+} // namespace tint::core::ir::transform
+
+TINT_IR_MODULE_FUZZER(tint::core::ir::transform::RemoveTerminatorArgsFuzzer);
diff --git a/src/tint/lang/core/ir/transform/remove_terminator_args_test.cc b/src/tint/lang/core/ir/transform/remove_terminator_args_test.cc
new file mode 100644
index 0000000..2fed34f
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/remove_terminator_args_test.cc
@@ -0,0 +1,911 @@
+// 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/remove_terminator_args.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/ir/transform/helper_test.h"
+
+namespace tint::core::ir::transform {
+namespace {
+
+using namespace tint::core::fluent_types; // NOLINT
+using namespace tint::core::number_suffixes; // NOLINT
+
+using IR_RemoveTerminatorArgsTest = TransformTest;
+
+TEST_F(IR_RemoveTerminatorArgsTest, NoModify_If) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* ifelse = b.If(true);
+ b.Append(ifelse->True(), [&] { //
+ b.ExitIf(ifelse);
+ });
+ b.Append(ifelse->False(), [&] { //
+ b.ExitIf(ifelse);
+ });
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ if true [t: $B2, f: $B3] { # if_1
+ $B2: { # true
+ exit_if # if_1
+ }
+ $B3: { # false
+ exit_if # if_1
+ }
+ }
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(RemoveTerminatorArgs);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_RemoveTerminatorArgsTest, NoModify_Switch) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* swtch = b.Switch(42_i);
+
+ auto* case_a = b.Case(swtch, Vector{b.Constant(1_i)});
+ b.Append(case_a, [&] { //
+ b.ExitSwitch(swtch);
+ });
+
+ auto* case_b = b.Case(swtch, Vector{b.Constant(2_i)});
+ b.Append(case_b, [&] { //
+ b.ExitSwitch(swtch);
+ });
+
+ auto* def_case = b.DefaultCase(swtch);
+ b.Append(def_case, [&] { //
+ b.ExitSwitch(swtch);
+ });
+
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ switch 42i [c: (1i, $B2), c: (2i, $B3), c: (default, $B4)] { # switch_1
+ $B2: { # case
+ exit_switch # switch_1
+ }
+ $B3: { # case
+ exit_switch # switch_1
+ }
+ $B4: { # case
+ exit_switch # switch_1
+ }
+ }
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(RemoveTerminatorArgs);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_RemoveTerminatorArgsTest, NoModify_Loop) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* loop = b.Loop();
+
+ b.Append(loop->Initializer(), [&] { //
+ b.NextIteration(loop);
+ });
+ b.Append(loop->Body(), [&] { //
+ auto* if_ = b.If(true);
+ b.Append(if_->True(), [&] { //
+ b.ExitLoop(loop);
+ });
+ b.Continue(loop);
+ });
+ b.Append(loop->Continuing(), [&] { //
+ b.BreakIf(loop, true);
+ });
+
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ loop [i: $B2, b: $B3, c: $B4] { # loop_1
+ $B2: { # initializer
+ next_iteration # -> $B3
+ }
+ $B3: { # body
+ if true [t: $B5] { # if_1
+ $B5: { # true
+ exit_loop # loop_1
+ }
+ }
+ continue # -> $B4
+ }
+ $B4: { # continuing
+ break_if true # -> [t: exit_loop loop_1, f: $B3]
+ }
+ }
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = src;
+
+ Run(RemoveTerminatorArgs);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_RemoveTerminatorArgsTest, IfResults) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* res_a = b.InstructionResult(ty.i32());
+ auto* res_b = b.InstructionResult(ty.u32());
+
+ auto* ifelse = b.If(true);
+ ifelse->SetResults(Vector{res_a, res_b});
+ b.Append(ifelse->True(), [&] { //
+ b.ExitIf(ifelse, 1_i, 42_u);
+ });
+ b.Append(ifelse->False(), [&] { //
+ b.ExitIf(ifelse, 42_i, 1_u);
+ });
+
+ // Use the results to make sure the uses get updated.
+ b.Add<i32>(res_a, 1_i);
+ b.Multiply<u32>(res_b, 2_u);
+
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ %2:i32, %3:u32 = if true [t: $B2, f: $B3] { # if_1
+ $B2: { # true
+ exit_if 1i, 42u # if_1
+ }
+ $B3: { # false
+ exit_if 42i, 1u # if_1
+ }
+ }
+ %4:i32 = add %2, 1i
+ %5:u32 = mul %3, 2u
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func():void {
+ $B1: {
+ %2:ptr<function, i32, read_write> = var
+ %3:ptr<function, u32, read_write> = var
+ if true [t: $B2, f: $B3] { # if_1
+ $B2: { # true
+ store %2, 1i
+ store %3, 42u
+ exit_if # if_1
+ }
+ $B3: { # false
+ store %2, 42i
+ store %3, 1u
+ exit_if # if_1
+ }
+ }
+ %4:u32 = load %3
+ %5:i32 = load %2
+ %6:i32 = add %5, 1i
+ %7:u32 = mul %4, 2u
+ ret
+ }
+}
+)";
+
+ Run(RemoveTerminatorArgs);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_RemoveTerminatorArgsTest, SwitchResults) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* res_a = b.InstructionResult(ty.i32());
+ auto* res_b = b.InstructionResult(ty.u32());
+
+ auto* swtch = b.Switch(42_i);
+ swtch->SetResults(Vector{res_a, res_b});
+
+ auto* case_a = b.Case(swtch, Vector{b.Constant(1_i)});
+ b.Append(case_a, [&] { //
+ b.ExitSwitch(swtch, 1_i, 2_u);
+ });
+
+ auto* case_b = b.Case(swtch, Vector{b.Constant(2_i)});
+ b.Append(case_b, [&] { //
+ b.ExitSwitch(swtch, 3_i, 4_u);
+ });
+
+ auto* def_case = b.DefaultCase(swtch);
+ b.Append(def_case, [&] { //
+ b.ExitSwitch(swtch, 5_i, 6_u);
+ });
+
+ // Use the results to make sure the uses get updated.
+ b.Add<i32>(res_a, 1_i);
+ b.Multiply<u32>(res_b, 2_u);
+
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ %2:i32, %3:u32 = switch 42i [c: (1i, $B2), c: (2i, $B3), c: (default, $B4)] { # switch_1
+ $B2: { # case
+ exit_switch 1i, 2u # switch_1
+ }
+ $B3: { # case
+ exit_switch 3i, 4u # switch_1
+ }
+ $B4: { # case
+ exit_switch 5i, 6u # switch_1
+ }
+ }
+ %4:i32 = add %2, 1i
+ %5:u32 = mul %3, 2u
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func():void {
+ $B1: {
+ %2:ptr<function, i32, read_write> = var
+ %3:ptr<function, u32, read_write> = var
+ switch 42i [c: (1i, $B2), c: (2i, $B3), c: (default, $B4)] { # switch_1
+ $B2: { # case
+ store %2, 1i
+ store %3, 2u
+ exit_switch # switch_1
+ }
+ $B3: { # case
+ store %2, 3i
+ store %3, 4u
+ exit_switch # switch_1
+ }
+ $B4: { # case
+ store %2, 5i
+ store %3, 6u
+ exit_switch # switch_1
+ }
+ }
+ %4:u32 = load %3
+ %5:i32 = load %2
+ %6:i32 = add %5, 1i
+ %7:u32 = mul %4, 2u
+ ret
+ }
+}
+)";
+
+ Run(RemoveTerminatorArgs);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_RemoveTerminatorArgsTest, Loop_Results) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* res_a = b.InstructionResult(ty.i32());
+ auto* res_b = b.InstructionResult(ty.u32());
+
+ auto* loop = b.Loop();
+ loop->SetResults(Vector{res_a, res_b});
+
+ b.Append(loop->Initializer(), [&] { //
+ b.NextIteration(loop);
+ });
+ b.Append(loop->Body(), [&] { //
+ auto* if_ = b.If(true);
+ b.Append(if_->True(), [&] { //
+ b.ExitLoop(loop, 1_i, 2_u);
+ });
+ b.Continue(loop);
+ });
+ b.Append(loop->Continuing(), [&] { //
+ b.BreakIf(loop, true, Empty, Vector{b.Constant(3_i), b.Constant(4_u)});
+ });
+
+ // Use the results to make sure the uses get updated.
+ b.Add<i32>(res_a, 1_i);
+ b.Multiply<u32>(res_b, 2_u);
+
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ %2:i32, %3:u32 = loop [i: $B2, b: $B3, c: $B4] { # loop_1
+ $B2: { # initializer
+ next_iteration # -> $B3
+ }
+ $B3: { # body
+ if true [t: $B5] { # if_1
+ $B5: { # true
+ exit_loop 1i, 2u # loop_1
+ }
+ }
+ continue # -> $B4
+ }
+ $B4: { # continuing
+ break_if true exit_loop: [ 3i, 4u ] # -> [t: exit_loop loop_1, f: $B3]
+ }
+ }
+ %4:i32 = add %2, 1i
+ %5:u32 = mul %3, 2u
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func():void {
+ $B1: {
+ %2:ptr<function, i32, read_write> = var
+ %3:ptr<function, u32, read_write> = var
+ loop [i: $B2, b: $B3, c: $B4] { # loop_1
+ $B2: { # initializer
+ next_iteration # -> $B3
+ }
+ $B3: { # body
+ if true [t: $B5] { # if_1
+ $B5: { # true
+ store %2, 1i
+ store %3, 2u
+ exit_loop # loop_1
+ }
+ }
+ continue # -> $B4
+ }
+ $B4: { # continuing
+ store %2, 3i
+ store %3, 4u
+ break_if true # -> [t: exit_loop loop_1, f: $B3]
+ }
+ }
+ %4:u32 = load %3
+ %5:i32 = load %2
+ %6:i32 = add %5, 1i
+ %7:u32 = mul %4, 2u
+ ret
+ }
+}
+)";
+
+ Run(RemoveTerminatorArgs);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_RemoveTerminatorArgsTest, Loop_BodyParams) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* param_a = b.BlockParam(ty.i32());
+ auto* param_b = b.BlockParam(ty.u32());
+
+ auto* loop = b.Loop();
+ loop->Body()->SetParams(Vector{param_a, param_b});
+
+ b.Append(loop->Initializer(), [&] { //
+ b.NextIteration(loop, 1_i, 2_u);
+ });
+ b.Append(loop->Body(), [&] { //
+ // Use the parameters to make sure the uses get updated.
+ b.Add<i32>(param_a, 1_i);
+ b.Multiply<u32>(param_b, 2_u);
+
+ auto* if_ = b.If(true);
+ b.Append(if_->True(), [&] { //
+ b.ExitLoop(loop);
+ });
+ b.Continue(loop);
+ });
+ b.Append(loop->Continuing(), [&] { //
+ b.BreakIf(loop, true, Vector{b.Constant(3_i), b.Constant(4_u)}, Empty);
+ });
+
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ loop [i: $B2, b: $B3, c: $B4] { # loop_1
+ $B2: { # initializer
+ next_iteration 1i, 2u # -> $B3
+ }
+ $B3 (%2:i32, %3:u32): { # body
+ %4:i32 = add %2, 1i
+ %5:u32 = mul %3, 2u
+ if true [t: $B5] { # if_1
+ $B5: { # true
+ exit_loop # loop_1
+ }
+ }
+ continue # -> $B4
+ }
+ $B4: { # continuing
+ break_if true next_iteration: [ 3i, 4u ] # -> [t: exit_loop loop_1, f: $B3]
+ }
+ }
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func():void {
+ $B1: {
+ loop [i: $B2, b: $B3, c: $B4] { # loop_1
+ $B2: { # initializer
+ %2:ptr<function, i32, read_write> = var
+ store %2, 1i
+ %3:ptr<function, u32, read_write> = var
+ store %3, 2u
+ next_iteration # -> $B3
+ }
+ $B3: { # body
+ %4:u32 = load %3
+ %5:i32 = load %2
+ %6:i32 = add %5, 1i
+ %7:u32 = mul %4, 2u
+ if true [t: $B5] { # if_1
+ $B5: { # true
+ exit_loop # loop_1
+ }
+ }
+ continue # -> $B4
+ }
+ $B4: { # continuing
+ store %2, 3i
+ store %3, 4u
+ break_if true # -> [t: exit_loop loop_1, f: $B3]
+ }
+ }
+ ret
+ }
+}
+)";
+
+ Run(RemoveTerminatorArgs);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_RemoveTerminatorArgsTest, Loop_ContinuingParams) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* param_a = b.BlockParam(ty.i32());
+ auto* param_b = b.BlockParam(ty.u32());
+
+ auto* loop = b.Loop();
+ loop->Continuing()->SetParams(Vector{param_a, param_b});
+
+ b.Append(loop->Initializer(), [&] { //
+ b.NextIteration(loop);
+ });
+ b.Append(loop->Body(), [&] { //
+ auto* if_ = b.If(true);
+ b.Append(if_->True(), [&] { //
+ b.ExitLoop(loop);
+ });
+ b.Continue(loop, 1_i, 2_u);
+ });
+ b.Append(loop->Continuing(), [&] {
+ // Use the parameters to make sure the uses get updated.
+ b.Add<i32>(param_a, 1_i);
+ b.Multiply<u32>(param_b, 2_u);
+
+ b.BreakIf(loop, true);
+ });
+
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ loop [i: $B2, b: $B3, c: $B4] { # loop_1
+ $B2: { # initializer
+ next_iteration # -> $B3
+ }
+ $B3: { # body
+ if true [t: $B5] { # if_1
+ $B5: { # true
+ exit_loop # loop_1
+ }
+ }
+ continue 1i, 2u # -> $B4
+ }
+ $B4 (%2:i32, %3:u32): { # continuing
+ %4:i32 = add %2, 1i
+ %5:u32 = mul %3, 2u
+ break_if true # -> [t: exit_loop loop_1, f: $B3]
+ }
+ }
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func():void {
+ $B1: {
+ loop [i: $B2, b: $B3, c: $B4] { # loop_1
+ $B2: { # initializer
+ next_iteration # -> $B3
+ }
+ $B3: { # body
+ %2:ptr<function, i32, read_write> = var
+ %3:ptr<function, u32, read_write> = var
+ if true [t: $B5] { # if_1
+ $B5: { # true
+ exit_loop # loop_1
+ }
+ }
+ store %2, 1i
+ store %3, 2u
+ continue # -> $B4
+ }
+ $B4: { # continuing
+ %4:u32 = load %3
+ %5:i32 = load %2
+ %6:i32 = add %5, 1i
+ %7:u32 = mul %4, 2u
+ break_if true # -> [t: exit_loop loop_1, f: $B3]
+ }
+ }
+ ret
+ }
+}
+)";
+
+ Run(RemoveTerminatorArgs);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_RemoveTerminatorArgsTest, Loop_BreakIfWithTwoArgLists) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* res_a = b.InstructionResult(ty.i32());
+ auto* res_b = b.InstructionResult(ty.u32());
+ auto* param_a = b.BlockParam(ty.f32());
+ auto* param_b = b.BlockParam(ty.i32());
+
+ auto* loop = b.Loop();
+ loop->SetResults(Vector{res_a, res_b});
+ loop->Body()->SetParams(Vector{param_a, param_b});
+
+ b.Append(loop->Initializer(), [&] { //
+ b.NextIteration(loop, 1_f, 2_i);
+ });
+ b.Append(loop->Body(), [&] {
+ // Use the parameters to make sure the uses get updated.
+ b.Subtract<f32>(param_a, 1_f);
+ b.Divide<i32>(param_b, 2_i);
+
+ auto* if_ = b.If(true);
+ b.Append(if_->True(), [&] { //
+ b.ExitLoop(loop, 3_i, 4_u);
+ });
+ b.Continue(loop);
+ });
+ b.Append(loop->Continuing(), [&] { //
+ b.BreakIf(loop, true, Vector{b.Constant(5_f), b.Constant(6_i)},
+ Vector{b.Constant(7_i), b.Constant(8_u)});
+ });
+
+ // Use the results to make sure the uses get updated.
+ b.Add<i32>(res_a, 1_i);
+ b.Multiply<u32>(res_b, 2_u);
+
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ %2:i32, %3:u32 = loop [i: $B2, b: $B3, c: $B4] { # loop_1
+ $B2: { # initializer
+ next_iteration 1.0f, 2i # -> $B3
+ }
+ $B3 (%4:f32, %5:i32): { # body
+ %6:f32 = sub %4, 1.0f
+ %7:i32 = div %5, 2i
+ if true [t: $B5] { # if_1
+ $B5: { # true
+ exit_loop 3i, 4u # loop_1
+ }
+ }
+ continue # -> $B4
+ }
+ $B4: { # continuing
+ break_if true next_iteration: [ 5.0f, 6i ] exit_loop: [ 7i, 8u ] # -> [t: exit_loop loop_1, f: $B3]
+ }
+ }
+ %8:i32 = add %2, 1i
+ %9:u32 = mul %3, 2u
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func():void {
+ $B1: {
+ %2:ptr<function, i32, read_write> = var
+ %3:ptr<function, u32, read_write> = var
+ loop [i: $B2, b: $B3, c: $B4] { # loop_1
+ $B2: { # initializer
+ %4:ptr<function, f32, read_write> = var
+ store %4, 1.0f
+ %5:ptr<function, i32, read_write> = var
+ store %5, 2i
+ next_iteration # -> $B3
+ }
+ $B3: { # body
+ %6:i32 = load %5
+ %7:f32 = load %4
+ %8:f32 = sub %7, 1.0f
+ %9:i32 = div %6, 2i
+ if true [t: $B5] { # if_1
+ $B5: { # true
+ store %2, 3i
+ store %3, 4u
+ exit_loop # loop_1
+ }
+ }
+ continue # -> $B4
+ }
+ $B4: { # continuing
+ store %2, 7i
+ store %3, 8u
+ store %4, 5.0f
+ store %5, 6i
+ break_if true # -> [t: exit_loop loop_1, f: $B3]
+ }
+ }
+ %10:u32 = load %3
+ %11:i32 = load %2
+ %12:i32 = add %11, 1i
+ %13:u32 = mul %10, 2u
+ ret
+ }
+}
+)";
+
+ Run(RemoveTerminatorArgs);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_RemoveTerminatorArgsTest, UndefResults) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* res_a = b.InstructionResult(ty.i32());
+ auto* res_b = b.InstructionResult(ty.u32());
+
+ auto* ifelse = b.If(true);
+ ifelse->SetResults(Vector{res_a, res_b});
+ b.Append(ifelse->True(), [&] { //
+ b.ExitIf(ifelse, 1_i, nullptr);
+ });
+ b.Append(ifelse->False(), [&] { //
+ b.ExitIf(ifelse, nullptr, 2_u);
+ });
+
+ // Use the results to make sure the uses get updated.
+ b.Add<i32>(res_a, 1_i);
+ b.Multiply<u32>(res_b, 2_u);
+
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ %2:i32, %3:u32 = if true [t: $B2, f: $B3] { # if_1
+ $B2: { # true
+ exit_if 1i, undef # if_1
+ }
+ $B3: { # false
+ exit_if undef, 2u # if_1
+ }
+ }
+ %4:i32 = add %2, 1i
+ %5:u32 = mul %3, 2u
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func():void {
+ $B1: {
+ %2:ptr<function, i32, read_write> = var
+ %3:ptr<function, u32, read_write> = var
+ if true [t: $B2, f: $B3] { # if_1
+ $B2: { # true
+ store %2, 1i
+ exit_if # if_1
+ }
+ $B3: { # false
+ store %3, 2u
+ exit_if # if_1
+ }
+ }
+ %4:u32 = load %3
+ %5:i32 = load %2
+ %6:i32 = add %5, 1i
+ %7:u32 = mul %4, 2u
+ ret
+ }
+}
+)";
+
+ Run(RemoveTerminatorArgs);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_RemoveTerminatorArgsTest, UndefBlockParams) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* param_a = b.BlockParam(ty.i32());
+ auto* param_b = b.BlockParam(ty.u32());
+
+ auto* loop = b.Loop();
+ loop->Body()->SetParams(Vector{param_a, param_b});
+
+ b.Append(loop->Initializer(), [&] { //
+ b.NextIteration(loop, 1_i, nullptr);
+ });
+ b.Append(loop->Body(), [&] { //
+ // Use the parameters to make sure the uses get updated.
+ b.Add<i32>(param_a, 1_i);
+ b.Multiply<u32>(param_b, 2_u);
+
+ auto* if_ = b.If(true);
+ b.Append(if_->True(), [&] { //
+ b.ExitLoop(loop);
+ });
+ b.Continue(loop);
+ });
+ b.Append(loop->Continuing(), [&] { //
+ b.BreakIf(loop, true, Vector{b.Constant(3_i), nullptr}, Empty);
+ });
+
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = func():void {
+ $B1: {
+ loop [i: $B2, b: $B3, c: $B4] { # loop_1
+ $B2: { # initializer
+ next_iteration 1i, undef # -> $B3
+ }
+ $B3 (%2:i32, %3:u32): { # body
+ %4:i32 = add %2, 1i
+ %5:u32 = mul %3, 2u
+ if true [t: $B5] { # if_1
+ $B5: { # true
+ exit_loop # loop_1
+ }
+ }
+ continue # -> $B4
+ }
+ $B4: { # continuing
+ break_if true next_iteration: [ 3i, undef ] # -> [t: exit_loop loop_1, f: $B3]
+ }
+ }
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func():void {
+ $B1: {
+ loop [i: $B2, b: $B3, c: $B4] { # loop_1
+ $B2: { # initializer
+ %2:ptr<function, i32, read_write> = var
+ store %2, 1i
+ %3:ptr<function, u32, read_write> = var
+ next_iteration # -> $B3
+ }
+ $B3: { # body
+ %4:u32 = load %3
+ %5:i32 = load %2
+ %6:i32 = add %5, 1i
+ %7:u32 = mul %4, 2u
+ if true [t: $B5] { # if_1
+ $B5: { # true
+ exit_loop # loop_1
+ }
+ }
+ continue # -> $B4
+ }
+ $B4: { # continuing
+ store %2, 3i
+ break_if true # -> [t: exit_loop loop_1, f: $B3]
+ }
+ }
+ ret
+ }
+}
+)";
+
+ Run(RemoveTerminatorArgs);
+
+ EXPECT_EQ(expect, str());
+}
+
+} // namespace
+} // namespace tint::core::ir::transform
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index f24b8eb..34906d4 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -1495,8 +1495,7 @@
if (auto* to = s->To()) {
auto* mv = to->Type()->As<core::type::MemoryView>();
if (!mv) {
- AddError(s, Store::kFromOperandOffset)
- << "store target operand is not a memory view";
+ AddError(s, Store::kToOperandOffset) << "store target operand is not a memory view";
return;
}
auto* value_type = from->Type();
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index 870d345..da74d0c 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -4510,9 +4510,9 @@
auto res = ir::Validate(mod);
ASSERT_NE(res, Success);
EXPECT_EQ(res.Failure().reason.Str(),
- R"(:4:15 error: store: store target operand is not a memory view
+ R"(:4:11 error: store: store target operand is not a memory view
store %l, 42u
- ^^^
+ ^^
:2:3 note: in block
$B1: {
diff --git a/src/tint/lang/glsl/writer/writer_ast_fuzz.cc b/src/tint/lang/glsl/writer/writer_ast_fuzz.cc
index 839e466..e555a75 100644
--- a/src/tint/lang/glsl/writer/writer_ast_fuzz.cc
+++ b/src/tint/lang/glsl/writer/writer_ast_fuzz.cc
@@ -43,7 +43,11 @@
// Excessive values can cause OOM / timeouts in the PadStructs transform.
static constexpr uint32_t kMaxOffset = 0x1000;
- if (options.first_instance_offset > kMaxOffset) {
+ if (options.first_instance_offset && options.first_instance_offset > kMaxOffset) {
+ return false;
+ }
+
+ if (options.first_vertex_offset && options.first_vertex_offset > kMaxOffset) {
return false;
}
diff --git a/src/tint/lang/msl/writer/raise/raise.cc b/src/tint/lang/msl/writer/raise/raise.cc
index ad8cbfe..d3b5007 100644
--- a/src/tint/lang/msl/writer/raise/raise.cc
+++ b/src/tint/lang/msl/writer/raise/raise.cc
@@ -37,6 +37,7 @@
#include "src/tint/lang/core/ir/transform/demote_to_helper.h"
#include "src/tint/lang/core/ir/transform/multiplanar_external_texture.h"
#include "src/tint/lang/core/ir/transform/preserve_padding.h"
+#include "src/tint/lang/core/ir/transform/remove_terminator_args.h"
#include "src/tint/lang/core/ir/transform/robustness.h"
#include "src/tint/lang/core/ir/transform/value_to_let.h"
#include "src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.h"
@@ -111,6 +112,7 @@
RUN_TRANSFORM(raise::ShaderIO, raise::ShaderIOConfig{options.emit_vertex_point_size});
RUN_TRANSFORM(raise::ModuleScopeVars);
+ RUN_TRANSFORM(core::ir::transform::RemoveTerminatorArgs);
RUN_TRANSFORM(core::ir::transform::ValueToLet);
RUN_TRANSFORM(raise::BuiltinPolyfill);
diff --git a/src/tint/lang/spirv/writer/raise/merge_return.cc b/src/tint/lang/spirv/writer/raise/merge_return.cc
index 350afa4..077660e 100644
--- a/src/tint/lang/spirv/writer/raise/merge_return.cc
+++ b/src/tint/lang/spirv/writer/raise/merge_return.cc
@@ -129,6 +129,7 @@
/// @param block the block to process
void ProcessBlock(core::ir::Block* block) {
core::ir::If* inner_if = nullptr;
+ Vector<core::ir::If*, 4> inner_if_stack;
for (auto* inst = *block->begin(); inst;) { // For each instruction in 'block'
// As we're modifying the block that we're iterating over, grab the pointer to the next
// instruction before (potentially) moving 'inst' to another block.
@@ -167,6 +168,7 @@
if (next && (next != fn_return || fn_return->Value()) &&
!tint::IsAnyOf<core::ir::Exit, core::ir::Unreachable>(next)) {
inner_if = CreateIfContinueExecution(ctrl);
+ inner_if_stack.Push(inner_if);
}
}
}
@@ -195,9 +197,10 @@
inner_if->True()->Append(b.ExitIf(inner_if));
}
- // Loop over the 'if' instructions, starting with the inner-most, and add any missing
- // terminating instructions to the blocks holding the 'if'.
- for (auto* i = inner_if; i; i = tint::As<core::ir::If>(i->Block()->Parent())) {
+ // Walk back down the stack of 'if' instructions that were created, and add any missing
+ // terminating instructions to the blocks holding them.
+ while (!inner_if_stack.IsEmpty()) {
+ auto* i = inner_if_stack.Pop();
if (!i->Block()->Terminator() && i->Block()->Parent()) {
// Append the exit instruction to the block holding the 'if'.
Vector<core::ir::InstructionResult*, 8> exit_args = i->Results();
diff --git a/src/tint/lang/spirv/writer/raise/merge_return_test.cc b/src/tint/lang/spirv/writer/raise/merge_return_test.cc
index 9cb2f0a..7b7c0f1 100644
--- a/src/tint/lang/spirv/writer/raise/merge_return_test.cc
+++ b/src/tint/lang/spirv/writer/raise/merge_return_test.cc
@@ -1413,6 +1413,306 @@
EXPECT_EQ(expect, str());
}
+TEST_F(SpirvWriter_MergeReturnTest, IfElse_NestedConsecutives) {
+ auto* value = b.FunctionParam(ty.i32());
+ auto* func = b.Function("foo", ty.i32());
+ func->SetParams({value});
+
+ b.Append(func->Block(), [&] {
+ auto* outer = b.If(b.Equal(ty.bool_(), value, 1_i));
+ b.Append(outer->True(), [&] {
+ auto* middle_first = b.If(b.Equal(ty.bool_(), value, 2_i));
+ b.Append(middle_first->True(), [&] { //
+ b.Return(func, 202_i);
+ });
+
+ auto* middle_second = b.If(b.Equal(ty.bool_(), value, 3_i));
+ b.Append(middle_second->True(), [&] {
+ auto* inner_first = b.If(b.Equal(ty.bool_(), value, 4_i));
+ b.Append(inner_first->True(), [&] { //
+ b.Return(func, 404_i);
+ });
+
+ auto* inner_second = b.If(b.Equal(ty.bool_(), value, 5_i));
+ b.Append(inner_second->True(), [&] { //
+ b.Return(func, 505_i);
+ });
+
+ b.ExitIf(middle_second);
+ });
+
+ b.ExitIf(outer);
+ });
+
+ b.Return(func, 606_i);
+ });
+
+ auto* src = R"(
+%foo = func(%2:i32):i32 {
+ $B1: {
+ %3:bool = eq %2, 1i
+ if %3 [t: $B2] { # if_1
+ $B2: { # true
+ %4:bool = eq %2, 2i
+ if %4 [t: $B3] { # if_2
+ $B3: { # true
+ ret 202i
+ }
+ }
+ %5:bool = eq %2, 3i
+ if %5 [t: $B4] { # if_3
+ $B4: { # true
+ %6:bool = eq %2, 4i
+ if %6 [t: $B5] { # if_4
+ $B5: { # true
+ ret 404i
+ }
+ }
+ %7:bool = eq %2, 5i
+ if %7 [t: $B6] { # if_5
+ $B6: { # true
+ ret 505i
+ }
+ }
+ exit_if # if_3
+ }
+ }
+ exit_if # if_1
+ }
+ }
+ ret 606i
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%2:i32):i32 {
+ $B1: {
+ %return_value:ptr<function, i32, read_write> = var
+ %continue_execution:ptr<function, bool, read_write> = var, true
+ %5:bool = eq %2, 1i
+ if %5 [t: $B2] { # if_1
+ $B2: { # true
+ %6:bool = eq %2, 2i
+ if %6 [t: $B3] { # if_2
+ $B3: { # true
+ store %continue_execution, false
+ store %return_value, 202i
+ exit_if # if_2
+ }
+ }
+ %7:bool = load %continue_execution
+ if %7 [t: $B4] { # if_3
+ $B4: { # true
+ %8:bool = eq %2, 3i
+ if %8 [t: $B5] { # if_4
+ $B5: { # true
+ %9:bool = eq %2, 4i
+ if %9 [t: $B6] { # if_5
+ $B6: { # true
+ store %continue_execution, false
+ store %return_value, 404i
+ exit_if # if_5
+ }
+ }
+ %10:bool = load %continue_execution
+ if %10 [t: $B7] { # if_6
+ $B7: { # true
+ %11:bool = eq %2, 5i
+ if %11 [t: $B8] { # if_7
+ $B8: { # true
+ store %continue_execution, false
+ store %return_value, 505i
+ exit_if # if_7
+ }
+ }
+ exit_if # if_6
+ }
+ }
+ exit_if # if_4
+ }
+ }
+ exit_if # if_3
+ }
+ }
+ exit_if # if_1
+ }
+ }
+ %12:bool = load %continue_execution
+ if %12 [t: $B9] { # if_8
+ $B9: { # true
+ store %return_value, 606i
+ exit_if # if_8
+ }
+ }
+ %13:i32 = load %return_value
+ ret %13
+ }
+}
+)";
+
+ Run(MergeReturn);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(SpirvWriter_MergeReturnTest, IfElse_NestedConsecutives_WithResults) {
+ auto* value = b.FunctionParam(ty.i32());
+ auto* func = b.Function("foo", ty.i32());
+ func->SetParams({value});
+
+ b.Append(func->Block(), [&] {
+ auto* outer_result = b.InstructionResult(ty.i32());
+ auto* outer = b.If(b.Equal(ty.bool_(), value, 1_i));
+ outer->SetResults(Vector{outer_result});
+ b.Append(outer->True(), [&] {
+ auto* middle_first = b.If(b.Equal(ty.bool_(), value, 2_i));
+ b.Append(middle_first->True(), [&] { //
+ b.Return(func, 202_i);
+ });
+
+ auto middle_result = b.InstructionResult(ty.i32());
+ auto* middle_second = b.If(b.Equal(ty.bool_(), value, 3_i));
+ middle_second->SetResults(Vector{middle_result});
+ b.Append(middle_second->True(), [&] {
+ auto* inner_first = b.If(b.Equal(ty.bool_(), value, 4_i));
+ b.Append(inner_first->True(), [&] { //
+ b.Return(func, 404_i);
+ });
+
+ auto inner_result = b.InstructionResult(ty.i32());
+ auto* inner_second = b.If(b.Equal(ty.bool_(), value, 5_i));
+ inner_second->SetResults(Vector{inner_result});
+ b.Append(inner_second->True(), [&] { //
+ b.ExitIf(inner_second, 505_i);
+ });
+
+ b.ExitIf(middle_second, inner_result);
+ });
+
+ b.ExitIf(outer, middle_result);
+ });
+
+ b.Return(func, outer_result);
+ });
+
+ auto* src = R"(
+%foo = func(%2:i32):i32 {
+ $B1: {
+ %3:bool = eq %2, 1i
+ %4:i32 = if %3 [t: $B2] { # if_1
+ $B2: { # true
+ %5:bool = eq %2, 2i
+ if %5 [t: $B3] { # if_2
+ $B3: { # true
+ ret 202i
+ }
+ }
+ %6:bool = eq %2, 3i
+ %7:i32 = if %6 [t: $B4] { # if_3
+ $B4: { # true
+ %8:bool = eq %2, 4i
+ if %8 [t: $B5] { # if_4
+ $B5: { # true
+ ret 404i
+ }
+ }
+ %9:bool = eq %2, 5i
+ %10:i32 = if %9 [t: $B6] { # if_5
+ $B6: { # true
+ exit_if 505i # if_5
+ }
+ # implicit false block: exit_if undef
+ }
+ exit_if %10 # if_3
+ }
+ # implicit false block: exit_if undef
+ }
+ exit_if %7 # if_1
+ }
+ # implicit false block: exit_if undef
+ }
+ ret %4
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%2:i32):i32 {
+ $B1: {
+ %return_value:ptr<function, i32, read_write> = var
+ %continue_execution:ptr<function, bool, read_write> = var, true
+ %5:bool = eq %2, 1i
+ %6:i32 = if %5 [t: $B2] { # if_1
+ $B2: { # true
+ %7:bool = eq %2, 2i
+ if %7 [t: $B3] { # if_2
+ $B3: { # true
+ store %continue_execution, false
+ store %return_value, 202i
+ exit_if # if_2
+ }
+ }
+ %8:bool = load %continue_execution
+ %9:i32 = if %8 [t: $B4] { # if_3
+ $B4: { # true
+ %10:bool = eq %2, 3i
+ %11:i32 = if %10 [t: $B5] { # if_4
+ $B5: { # true
+ %12:bool = eq %2, 4i
+ if %12 [t: $B6] { # if_5
+ $B6: { # true
+ store %continue_execution, false
+ store %return_value, 404i
+ exit_if # if_5
+ }
+ }
+ %13:bool = load %continue_execution
+ %14:i32 = if %13 [t: $B7] { # if_6
+ $B7: { # true
+ %15:bool = eq %2, 5i
+ %16:i32 = if %15 [t: $B8] { # if_7
+ $B8: { # true
+ exit_if 505i # if_7
+ }
+ # implicit false block: exit_if undef
+ }
+ exit_if %16 # if_6
+ }
+ # implicit false block: exit_if undef
+ }
+ exit_if %14 # if_4
+ }
+ # implicit false block: exit_if undef
+ }
+ exit_if %11 # if_3
+ }
+ # implicit false block: exit_if undef
+ }
+ exit_if %9 # if_1
+ }
+ # implicit false block: exit_if undef
+ }
+ %17:bool = load %continue_execution
+ if %17 [t: $B9] { # if_8
+ $B9: { # true
+ store %return_value, %6
+ exit_if # if_8
+ }
+ }
+ %18:i32 = load %return_value
+ ret %18
+ }
+}
+)";
+
+ Run(MergeReturn);
+
+ EXPECT_EQ(expect, str());
+}
+
TEST_F(SpirvWriter_MergeReturnTest, Loop_UnconditionalReturnInBody) {
auto* func = b.Function("foo", ty.i32());
diff --git a/src/tint/lang/wgsl/ast/BUILD.bazel b/src/tint/lang/wgsl/ast/BUILD.bazel
index be215b2..e038bf6 100644
--- a/src/tint/lang/wgsl/ast/BUILD.bazel
+++ b/src/tint/lang/wgsl/ast/BUILD.bazel
@@ -205,7 +205,6 @@
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/features",
diff --git a/src/tint/lang/wgsl/ast/BUILD.cmake b/src/tint/lang/wgsl/ast/BUILD.cmake
index 3d36157..6afc090 100644
--- a/src/tint/lang/wgsl/ast/BUILD.cmake
+++ b/src/tint/lang/wgsl/ast/BUILD.cmake
@@ -206,7 +206,6 @@
tint_target_add_dependencies(tint_lang_wgsl_ast lib
tint_api_common
tint_lang_core
- tint_lang_core_constant
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_features
diff --git a/src/tint/lang/wgsl/ast/BUILD.gn b/src/tint/lang/wgsl/ast/BUILD.gn
index 165f2a7..a1b43d7 100644
--- a/src/tint/lang/wgsl/ast/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/BUILD.gn
@@ -208,7 +208,6 @@
deps = [
"${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/features",
diff --git a/src/tint/lang/wgsl/ast/builder.h b/src/tint/lang/wgsl/ast/builder.h
index 03cc5b0..33fbe7a 100644
--- a/src/tint/lang/wgsl/ast/builder.h
+++ b/src/tint/lang/wgsl/ast/builder.h
@@ -28,34 +28,17 @@
#ifndef SRC_TINT_LANG_WGSL_AST_BUILDER_H_
#define SRC_TINT_LANG_WGSL_AST_BUILDER_H_
-#include <string>
-#include <unordered_set>
#include <utility>
#include "src/tint/api/common/override_id.h"
-#include "src/tint/lang/core/constant/manager.h"
#include "src/tint/lang/core/fluent_types.h"
#include "src/tint/lang/core/interpolation_sampling.h"
#include "src/tint/lang/core/interpolation_type.h"
#include "src/tint/lang/core/number.h"
-#include "src/tint/lang/core/type/array.h"
-#include "src/tint/lang/core/type/bool.h"
-#include "src/tint/lang/core/type/depth_texture.h"
-#include "src/tint/lang/core/type/external_texture.h"
-#include "src/tint/lang/core/type/f16.h"
-#include "src/tint/lang/core/type/f32.h"
-#include "src/tint/lang/core/type/i32.h"
-#include "src/tint/lang/core/type/matrix.h"
-#include "src/tint/lang/core/type/multisampled_texture.h"
-#include "src/tint/lang/core/type/pointer.h"
-#include "src/tint/lang/core/type/sampled_texture.h"
+#include "src/tint/lang/core/texel_format.h"
#include "src/tint/lang/core/type/sampler_kind.h"
-#include "src/tint/lang/core/type/storage_texture.h"
#include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/lang/core/type/u32.h"
-#include "src/tint/lang/core/type/vector.h"
-#include "src/tint/lang/core/type/void.h"
#include "src/tint/lang/wgsl/ast/alias.h"
#include "src/tint/lang/wgsl/ast/assignment_statement.h"
#include "src/tint/lang/wgsl/ast/binary_expression.h"
@@ -117,6 +100,8 @@
#include "src/tint/lang/wgsl/builtin_fn.h"
#include "src/tint/lang/wgsl/extension.h"
#include "src/tint/utils/id/generation_id.h"
+#include "src/tint/utils/memory/block_allocator.h"
+#include "src/tint/utils/symbol/symbol_table.h"
#include "src/tint/utils/text/string.h"
#ifdef CURRENTLY_IN_TINT_PUBLIC_HEADER
diff --git a/src/tint/lang/wgsl/diagnostic_rule.h b/src/tint/lang/wgsl/diagnostic_rule.h
index cf2d8f0..f84158f 100644
--- a/src/tint/lang/wgsl/diagnostic_rule.h
+++ b/src/tint/lang/wgsl/diagnostic_rule.h
@@ -38,7 +38,6 @@
#define SRC_TINT_LANG_WGSL_DIAGNOSTIC_RULE_H_
#include <cstdint>
-#include <string>
#include <variant>
#include "src/tint/utils/traits/traits.h"
diff --git a/src/tint/lang/wgsl/diagnostic_rule.h.tmpl b/src/tint/lang/wgsl/diagnostic_rule.h.tmpl
index 9948d1c..328f533 100644
--- a/src/tint/lang/wgsl/diagnostic_rule.h.tmpl
+++ b/src/tint/lang/wgsl/diagnostic_rule.h.tmpl
@@ -15,7 +15,6 @@
#define SRC_TINT_LANG_WGSL_DIAGNOSTIC_RULE_H_
#include <cstdint>
-#include <string>
#include <variant>
#include "src/tint/utils/traits/traits.h"
diff --git a/src/tint/lang/wgsl/ls/document.cc b/src/tint/lang/wgsl/ls/document.cc
index 2a60da4..8cc416b 100644
--- a/src/tint/lang/wgsl/ls/document.cc
+++ b/src/tint/lang/wgsl/ls/document.cc
@@ -51,8 +51,10 @@
langsvr::Result<langsvr::SuccessType> Server::Handle(
const lsp::TextDocumentDidOpenNotification& n) {
+ wgsl::reader::Options options;
+ options.allowed_features = wgsl::AllowedFeatures::Everything();
auto source = std::make_unique<Source::File>(n.text_document.uri, n.text_document.text);
- auto program = wgsl::reader::Parse(source.get());
+ auto program = wgsl::reader::Parse(source.get(), options);
auto file =
std::make_shared<File>(std::move(source), n.text_document.version, std::move(program));
files_.Add(n.text_document.uri, file);
@@ -82,8 +84,10 @@
utf8 = utf8.substr(0, utf8_start) + edit->text + utf8.substr(utf8_end);
}
}
+ wgsl::reader::Options options;
+ options.allowed_features = wgsl::AllowedFeatures::Everything();
auto source = std::make_unique<Source::File>(n.text_document.uri, utf8);
- auto program = wgsl::reader::Parse(source.get());
+ auto program = wgsl::reader::Parse(source.get(), options);
*file = std::make_shared<File>(std::move(source), n.text_document.version, std::move(program));
return PublishDiagnostics(**file);
}