Implement discard semantics
Implement new transform UnwindDiscardFunctions that replaces discard
statements with setting a module-level bool, adds a check and return for
this bool after every function call that may discard, and finally
invokes a single function that executes a discard from top-level
functions.
Regenerated tests and remove HLSL ones that used to fail FXC because it
had difficulty with discard.
Bug: tint:1478
Bug: chromium:1118
Change-Id: I09d680f59e2d5d0cad907bfbbdd426aae76d4bf3
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/84221
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 91bee00..1646c85 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -487,6 +487,8 @@
"transform/transform.h",
"transform/unshadow.cc",
"transform/unshadow.h",
+ "transform/unwind_discard_functions.cc",
+ "transform/unwind_discard_functions.h",
"transform/utils/hoist_to_decl_before.cc",
"transform/utils/hoist_to_decl_before.h",
"transform/var_for_dynamic_index.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 5e077e6..1f5e90c 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -365,6 +365,8 @@
transform/transform.h
transform/unshadow.cc
transform/unshadow.h
+ transform/unwind_discard_functions.cc
+ transform/unwind_discard_functions.h
transform/vectorize_scalar_matrix_constructors.cc
transform/vectorize_scalar_matrix_constructors.h
transform/var_for_dynamic_index.cc
@@ -1031,6 +1033,7 @@
transform/single_entry_point_test.cc
transform/test_helper.h
transform/unshadow_test.cc
+ transform/unwind_discard_functions_test.cc
transform/var_for_dynamic_index_test.cc
transform/vectorize_scalar_matrix_constructors_test.cc
transform/vertex_pulling_test.cc
diff --git a/src/tint/sem/if_statement.cc b/src/tint/sem/if_statement.cc
index d5f8fb3..38a7395 100644
--- a/src/tint/sem/if_statement.cc
+++ b/src/tint/sem/if_statement.cc
@@ -40,5 +40,9 @@
ElseStatement::~ElseStatement() = default;
+const ast::ElseStatement* ElseStatement::Declaration() const {
+ return static_cast<const ast::ElseStatement*>(Base::Declaration());
+}
+
} // namespace sem
} // namespace tint
diff --git a/src/tint/sem/if_statement.h b/src/tint/sem/if_statement.h
index 7dc2a11..c38a32a 100644
--- a/src/tint/sem/if_statement.h
+++ b/src/tint/sem/if_statement.h
@@ -73,6 +73,9 @@
/// Destructor
~ElseStatement() override;
+ /// @returns the AST node
+ const ast::ElseStatement* Declaration() const;
+
/// @returns the else-statement condition expression
const Expression* Condition() const { return condition_; }
diff --git a/src/tint/transform/glsl.cc b/src/tint/transform/glsl.cc
index c7352c4..a1cb69c 100644
--- a/src/tint/transform/glsl.cc
+++ b/src/tint/transform/glsl.cc
@@ -34,6 +34,7 @@
#include "src/tint/transform/simplify_pointers.h"
#include "src/tint/transform/single_entry_point.h"
#include "src/tint/transform/unshadow.h"
+#include "src/tint/transform/unwind_discard_functions.h"
#include "src/tint/transform/zero_init_workgroup_memory.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::Glsl);
@@ -84,6 +85,7 @@
}
manager.Add<CanonicalizeEntryPointIO>();
manager.Add<PromoteSideEffectsToDecl>();
+ manager.Add<UnwindDiscardFunctions>();
manager.Add<SimplifyPointers>();
manager.Add<RemovePhonies>();
diff --git a/src/tint/transform/test_helper.h b/src/tint/transform/test_helper.h
index 974cba0..8a36df1 100644
--- a/src/tint/transform/test_helper.h
+++ b/src/tint/transform/test_helper.h
@@ -118,7 +118,8 @@
template <typename TRANSFORM>
bool ShouldRun(Program&& program, const DataMap& data = {}) {
EXPECT_TRUE(program.IsValid()) << program.Diagnostics().str();
- return TRANSFORM().ShouldRun(&program, data);
+ const Transform& t = TRANSFORM();
+ return t.ShouldRun(&program, data);
}
/// @param in the input WGSL source
diff --git a/src/tint/transform/unwind_discard_functions.cc b/src/tint/transform/unwind_discard_functions.cc
new file mode 100644
index 0000000..80a47b1
--- /dev/null
+++ b/src/tint/transform/unwind_discard_functions.cc
@@ -0,0 +1,432 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/unwind_discard_functions.h"
+
+#include <memory>
+#include <string>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "src/tint/ast/discard_statement.h"
+#include "src/tint/ast/return_statement.h"
+#include "src/tint/ast/traverse_expressions.h"
+#include "src/tint/sem/block_statement.h"
+#include "src/tint/sem/call.h"
+#include "src/tint/sem/for_loop_statement.h"
+#include "src/tint/sem/function.h"
+#include "src/tint/sem/if_statement.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::transform::UnwindDiscardFunctions);
+
+namespace tint::transform {
+namespace {
+
+class State {
+ private:
+ CloneContext& ctx;
+ ProgramBuilder& b;
+ const sem::Info& sem;
+ Symbol module_discard_var_name; // Use ModuleDiscardVarName() to read
+ Symbol module_discard_func_name; // Use ModuleDiscardFuncName() to read
+
+ // For the input statement, returns the block and statement within that
+ // block to insert before/after.
+ std::pair<const sem::BlockStatement*, const ast::Statement*>
+ GetInsertionPoint(const ast::Statement* stmt) {
+ using RetType =
+ std::pair<const sem::BlockStatement*, const ast::Statement*>;
+
+ if (auto* sem_stmt = sem.Get(stmt)) {
+ auto* parent = sem_stmt->Parent();
+ return Switch(
+ parent,
+ [&](const sem::BlockStatement* block) -> RetType {
+ // Common case, just insert in the current block above the input
+ // statement.
+ return {block, stmt};
+ },
+ [&](const sem::ForLoopStatement* fl) -> RetType {
+ // `stmt` is either the for loop initializer or the continuing
+ // statement of a for-loop.
+ if (fl->Declaration()->initializer == stmt) {
+ // For loop init, insert above the for loop itself.
+ return {fl->Block(), fl->Declaration()};
+ }
+
+ TINT_ICE(Transform, b.Diagnostics())
+ << "cannot insert before or after continuing statement of a "
+ "for-loop";
+ return {};
+ },
+ [&](Default) -> RetType {
+ TINT_ICE(Transform, b.Diagnostics())
+ << "expected parent of statement to be either a block or for "
+ "loop";
+ return {};
+ });
+ }
+
+ return {};
+ }
+
+ // If `block`'s parent is of type TO, returns pointer to it.
+ template <typename TO>
+ const TO* ParentAs(const ast::BlockStatement* block) {
+ if (auto* sem_block = sem.Get(block)) {
+ return As<TO>(sem_block->Parent());
+ }
+ return nullptr;
+ }
+
+ // Returns true if `sem_expr` contains a call expression that may
+ // (transitively) execute a discard statement.
+ bool MayDiscard(const sem::Expression* sem_expr) {
+ return sem_expr && sem_expr->Behaviors().Contains(sem::Behavior::kDiscard);
+ }
+
+ // Lazily creates and returns the name of the module bool variable for whether
+ // to discard: "tint_discard".
+ Symbol ModuleDiscardVarName() {
+ if (!module_discard_var_name.IsValid()) {
+ module_discard_var_name = b.Symbols().New("tint_discard");
+ ctx.dst->Global(module_discard_var_name, b.ty.bool_(), b.Expr(false),
+ ast::StorageClass::kPrivate);
+ }
+ return module_discard_var_name;
+ }
+
+ // Lazily creates and returns the name of the function that contains a single
+ // discard statement: "tint_discard_func".
+ // We do this to avoid having multiple discard statements in a single program,
+ // which causes problems in certain backends (see crbug.com/1118).
+ Symbol ModuleDiscardFuncName() {
+ if (!module_discard_func_name.IsValid()) {
+ module_discard_func_name = b.Symbols().New("tint_discard_func");
+ b.Func(module_discard_func_name, {}, b.ty.void_(), {b.Discard()});
+ }
+ return module_discard_func_name;
+ }
+
+ // Creates "return <default return value>;" based on the return type of
+ // `stmt`'s owning function.
+ const ast::ReturnStatement* Return(const ast::Statement* stmt) {
+ const ast::Expression* ret_val = nullptr;
+ auto* ret_type = sem.Get(stmt)->Function()->Declaration()->return_type;
+ if (!ret_type->Is<ast::Void>()) {
+ ret_val = b.Construct(ctx.Clone(ret_type));
+ }
+ return b.Return(ret_val);
+ }
+
+ // Returns true if the function `stmt` is in is an entry point
+ bool IsInEntryPointFunc(const ast::Statement* stmt) {
+ return sem.Get(stmt)->Function()->Declaration()->IsEntryPoint();
+ }
+
+ // Creates "tint_discard_func();"
+ const ast::CallStatement* CallDiscardFunc() {
+ auto func_name = ModuleDiscardFuncName();
+ return b.CallStmt(b.Call(func_name));
+ }
+
+ // Creates and returns a new if-statement of the form:
+ //
+ // if (tint_discard) {
+ // return <default value>;
+ // }
+ //
+ // or if `stmt` is in a entry point function:
+ //
+ // if (tint_discard) {
+ // tint_discard_func();
+ // return <default value>;
+ // }
+ //
+ const ast::IfStatement* IfDiscardReturn(const ast::Statement* stmt) {
+ ast::StatementList stmts;
+
+ // For entry point functions, also emit the discard statement
+ if (IsInEntryPointFunc(stmt)) {
+ stmts.emplace_back(CallDiscardFunc());
+ }
+
+ stmts.emplace_back(Return(stmt));
+
+ auto var_name = ModuleDiscardVarName();
+ return b.If(var_name, b.Block(stmts));
+ }
+
+ // Hoists `sem_expr` to a let followed by an `IfDiscardReturn` before `stmt`.
+ // For example, if `stmt` is:
+ //
+ // return f();
+ //
+ // This function will transform this to:
+ //
+ // let t1 = f();
+ // if (tint_discard) {
+ // return;
+ // }
+ // return t1;
+ //
+ const ast::Statement* HoistAndInsertBefore(const ast::Statement* stmt,
+ const sem::Expression* sem_expr) {
+ auto* expr = sem_expr->Declaration();
+
+ auto ip = GetInsertionPoint(stmt);
+ auto var_name = b.Sym();
+ auto* decl = b.Decl(b.Var(var_name, nullptr, ctx.Clone(expr)));
+ ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, decl);
+
+ ctx.InsertBefore(ip.first->Declaration()->statements, ip.second,
+ IfDiscardReturn(stmt));
+
+ auto* var_expr = b.Expr(var_name);
+
+ // Special handling for CallStatement as we can only replace its expression
+ // with a CallExpression.
+ if (stmt->Is<ast::CallStatement>()) {
+ // We could replace the call statement with no statement, but we can't do
+ // that with transforms (yet), so just return a phony assignment.
+ return b.Assign(b.Phony(), var_expr);
+ }
+
+ ctx.Replace(expr, var_expr);
+ return ctx.CloneWithoutTransform(stmt);
+ }
+
+ // Returns true if `stmt` is a for-loop initializer statement.
+ bool IsForLoopInitStatement(const ast::Statement* stmt) {
+ if (auto* sem_stmt = sem.Get(stmt)) {
+ if (auto* sem_fl = As<sem::ForLoopStatement>(sem_stmt->Parent())) {
+ return sem_fl->Declaration()->initializer == stmt;
+ }
+ }
+ return false;
+ }
+
+ // Inserts an `IfDiscardReturn` after `stmt` if possible (i.e. `stmt` is not
+ // in a for-loop init), otherwise falls back to HoistAndInsertBefore, hoisting
+ // `sem_expr` to a let followed by an `IfDiscardReturn` before `stmt`.
+ //
+ // For example, if `stmt` is:
+ //
+ // let r = f();
+ //
+ // This function will transform this to:
+ //
+ // let r = f();
+ // if (tint_discard) {
+ // return;
+ // }
+ const ast::Statement* TryInsertAfter(const ast::Statement* stmt,
+ const sem::Expression* sem_expr) {
+ // If `stmt` is the init of a for-loop, hoist and insert before instead.
+ if (IsForLoopInitStatement(stmt)) {
+ return HoistAndInsertBefore(stmt, sem_expr);
+ }
+
+ auto ip = GetInsertionPoint(stmt);
+ ctx.InsertAfter(ip.first->Declaration()->statements, ip.second,
+ IfDiscardReturn(stmt));
+ return nullptr; // Don't replace current statement
+ }
+
+ // Replaces the input discard statement with either setting the module level
+ // discard bool ("tint_discard = true"), or calling the discard function
+ // ("tint_discard_func()"), followed by a default return statement.
+ //
+ // Replaces "discard;" with:
+ //
+ // tint_discard = true;
+ // return;
+ //
+ // Or if `stmt` is a entry point function, replaces with:
+ //
+ // tint_discard_func();
+ // return;
+ //
+ const ast::Statement* ReplaceDiscardStatement(
+ const ast::DiscardStatement* stmt) {
+ const ast::Statement* to_insert = nullptr;
+ if (IsInEntryPointFunc(stmt)) {
+ to_insert = CallDiscardFunc();
+ } else {
+ auto var_name = ModuleDiscardVarName();
+ to_insert = b.Assign(var_name, true);
+ }
+
+ auto ip = GetInsertionPoint(stmt);
+ ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, to_insert);
+ return Return(stmt);
+ }
+
+ // Handle statement
+ const ast::Statement* Statement(const ast::Statement* stmt) {
+ return Switch(
+ stmt,
+ [&](const ast::DiscardStatement* s) -> const ast::Statement* {
+ return ReplaceDiscardStatement(s);
+ },
+ [&](const ast::AssignmentStatement* s) -> const ast::Statement* {
+ auto* sem_lhs = sem.Get(s->lhs);
+ auto* sem_rhs = sem.Get(s->rhs);
+ if (MayDiscard(sem_lhs)) {
+ if (MayDiscard(sem_rhs)) {
+ TINT_ICE(Transform, b.Diagnostics())
+ << "Unexpected: both sides of assignment statement may "
+ "discard. Make sure transform::PromoteSideEffectsToDecl "
+ "was run first.";
+ }
+ return TryInsertAfter(s, sem_lhs);
+ } else if (MayDiscard(sem_rhs)) {
+ return TryInsertAfter(s, sem_rhs);
+ }
+ return nullptr;
+ },
+ [&](const ast::CallStatement* s) -> const ast::Statement* {
+ auto* sem_expr = sem.Get(s->expr);
+ if (!MayDiscard(sem_expr)) {
+ return nullptr;
+ }
+ return TryInsertAfter(s, sem_expr);
+ },
+ [&](const ast::ElseStatement* s) -> const ast::Statement* {
+ if (MayDiscard(sem.Get(s->condition))) {
+ TINT_ICE(Transform, b.Diagnostics())
+ << "Unexpected ElseIf condition that may discard. Make sure "
+ "transform::PromoteSideEffectsToDecl was run first.";
+ }
+ return nullptr;
+ },
+ [&](const ast::ForLoopStatement* s) -> const ast::Statement* {
+ if (MayDiscard(sem.Get(s->condition))) {
+ TINT_ICE(Transform, b.Diagnostics())
+ << "Unexpected ForLoopStatement condition that may discard. "
+ "Make sure transform::PromoteSideEffectsToDecl was run "
+ "first.";
+ }
+ return nullptr;
+ },
+ [&](const ast::IfStatement* s) -> const ast::Statement* {
+ auto* sem_expr = sem.Get(s->condition);
+ if (!MayDiscard(sem_expr)) {
+ return nullptr;
+ }
+ return HoistAndInsertBefore(s, sem_expr);
+ },
+ [&](const ast::ReturnStatement* s) -> const ast::Statement* {
+ auto* sem_expr = sem.Get(s->value);
+ if (!MayDiscard(sem_expr)) {
+ return nullptr;
+ }
+ return HoistAndInsertBefore(s, sem_expr);
+ },
+ [&](const ast::SwitchStatement* s) -> const ast::Statement* {
+ auto* sem_expr = sem.Get(s->condition);
+ if (!MayDiscard(sem_expr)) {
+ return nullptr;
+ }
+ return HoistAndInsertBefore(s, sem_expr);
+ },
+ [&](const ast::VariableDeclStatement* s) -> const ast::Statement* {
+ auto* var = s->variable;
+ if (!var->constructor) {
+ return nullptr;
+ }
+ auto* sem_expr = sem.Get(var->constructor);
+ if (!MayDiscard(sem_expr)) {
+ return nullptr;
+ }
+ return TryInsertAfter(s, sem_expr);
+ });
+ }
+
+ public:
+ /// Constructor
+ /// @param ctx_in the context
+ explicit State(CloneContext& ctx_in)
+ : ctx(ctx_in), b(*ctx_in.dst), sem(ctx_in.src->Sem()) {}
+
+ /// Runs the transform
+ void Run() {
+ ctx.ReplaceAll(
+ [&](const ast::BlockStatement* block) -> const ast::Statement* {
+ // If this block is for an else-if statement, process the else-if now
+ // before processing its block statements.
+ // NOTE: we can't replace else statements at this point - this would
+ // need to be done when replacing the parent if-statement. However, in
+ // this transform, we don't ever expect to need to do this as else-ifs
+ // are converted to else { if } by PromoteSideEffectsToDecl, so this
+ // is only for validation.
+ if (auto* sem_else = ParentAs<sem::ElseStatement>(block)) {
+ if (auto* new_stmt = Statement(sem_else->Declaration())) {
+ TINT_ASSERT(Transform, new_stmt == nullptr);
+ return nullptr;
+ }
+ }
+
+ // Iterate block statements and replace them as needed.
+ for (auto* stmt : block->statements) {
+ if (auto* new_stmt = Statement(stmt)) {
+ ctx.Replace(stmt, new_stmt);
+ }
+
+ // Handle for loops, as they are the only other AST node that
+ // contains statements outside of BlockStatements.
+ if (auto* fl = stmt->As<ast::ForLoopStatement>()) {
+ if (auto* new_stmt = Statement(fl->initializer)) {
+ ctx.Replace(fl->initializer, new_stmt);
+ }
+ if (auto* new_stmt = Statement(fl->continuing)) {
+ // NOTE: Should never reach here as we cannot discard in a
+ // continuing block.
+ ctx.Replace(fl->continuing, new_stmt);
+ }
+ }
+ }
+
+ return nullptr;
+ });
+
+ ctx.Clone();
+ }
+};
+
+} // namespace
+
+UnwindDiscardFunctions::UnwindDiscardFunctions() = default;
+UnwindDiscardFunctions::~UnwindDiscardFunctions() = default;
+
+void UnwindDiscardFunctions::Run(CloneContext& ctx,
+ const DataMap&,
+ DataMap&) const {
+ State state(ctx);
+ state.Run();
+}
+
+bool UnwindDiscardFunctions::ShouldRun(const Program* program,
+ const DataMap& /*data*/) const {
+ auto& sem = program->Sem();
+ for (auto* f : program->AST().Functions()) {
+ if (sem.Get(f)->Behaviors().Contains(sem::Behavior::kDiscard)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace tint::transform
diff --git a/src/tint/transform/unwind_discard_functions.h b/src/tint/transform/unwind_discard_functions.h
new file mode 100644
index 0000000..42bbecb
--- /dev/null
+++ b/src/tint/transform/unwind_discard_functions.h
@@ -0,0 +1,68 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_TRANSFORM_UNWIND_DISCARD_FUNCTIONS_H_
+#define SRC_TINT_TRANSFORM_UNWIND_DISCARD_FUNCTIONS_H_
+
+#include "src/tint/transform/transform.h"
+
+namespace tint::transform {
+
+/// This transform is responsible for implementing discard semantics as per the
+/// WGSL specification: https://gpuweb.github.io/gpuweb/wgsl/#discard-statement
+///
+/// Not all backend languages implement discard this way (e.g. HLSL), so this
+/// transform does the following:
+///
+/// * Replaces discard statements with setting a module-level boolean
+/// "tint_discard" to true and returning immediately.
+/// * Wherever calls are made to discarding functions (directly or
+/// transitively), it inserts a check afterwards for if "tint_discard" is true,
+/// to return immediately.
+/// * Finally, entry point functions that call discarding functions
+/// emit a call to "tint_discard_func()" that contains the sole discard
+/// statement.
+///
+/// @note Depends on the following transforms to have been run first:
+/// * PromoteSideEffectsToDecl
+class UnwindDiscardFunctions
+ : public Castable<UnwindDiscardFunctions, Transform> {
+ public:
+ /// Constructor
+ UnwindDiscardFunctions();
+
+ /// Destructor
+ ~UnwindDiscardFunctions() override;
+
+ protected:
+ /// Runs the transform using the CloneContext built for transforming a
+ /// program. Run() is responsible for calling Clone() on the CloneContext.
+ /// @param ctx the CloneContext primed with the input program and
+ /// ProgramBuilder
+ /// @param inputs optional extra transform-specific input data
+ /// @param outputs optional extra transform-specific output data
+ void Run(CloneContext& ctx,
+ const DataMap& inputs,
+ DataMap& outputs) const override;
+
+ /// @param program the program to inspect
+ /// @param data optional extra transform-specific input data
+ /// @returns true if this transform should be run for the given program
+ bool ShouldRun(const Program* program,
+ const DataMap& data = {}) const override;
+};
+
+} // namespace tint::transform
+
+#endif // SRC_TINT_TRANSFORM_UNWIND_DISCARD_FUNCTIONS_H_
diff --git a/src/tint/transform/unwind_discard_functions_test.cc b/src/tint/transform/unwind_discard_functions_test.cc
new file mode 100644
index 0000000..ae0a1f1
--- /dev/null
+++ b/src/tint/transform/unwind_discard_functions_test.cc
@@ -0,0 +1,1421 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/unwind_discard_functions.h"
+#include "src/tint/transform/promote_side_effects_to_decl.h"
+#include "src/tint/transform/test_helper.h"
+
+namespace tint {
+namespace transform {
+namespace {
+
+using UnwindDiscardFunctionsTest = TransformTest;
+
+TEST_F(UnwindDiscardFunctionsTest, EmptyModule) {
+ auto* src = "";
+ auto* expect = src;
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, ShouldRun_NoDiscardFunc) {
+ auto* src = R"(
+fn f() {
+}
+)";
+
+ EXPECT_FALSE(ShouldRun<UnwindDiscardFunctions>(src));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, SingleDiscardFunc_NoCall) {
+ auto* src = R"(
+fn f() {
+ discard;
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() {
+ tint_discard = true;
+ return;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, MultipleDiscardFuncs_NoCall) {
+ auto* src = R"(
+fn f() {
+ discard;
+ let marker1 = 0;
+}
+
+fn g() {
+ discard;
+ let marker1 = 0;
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() {
+ tint_discard = true;
+ return;
+ let marker1 = 0;
+}
+
+fn g() {
+ tint_discard = true;
+ return;
+ let marker1 = 0;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Call_VoidReturn) {
+ auto* src = R"(
+fn f() {
+ discard;
+ let marker1 = 0;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ f();
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() {
+ tint_discard = true;
+ return;
+ let marker1 = 0;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Call_NonVoidReturn) {
+ auto* src = R"(
+struct S {
+ x : i32,
+ y : i32,
+};
+
+fn f() -> S {
+ if (true) {
+ discard;
+ }
+ let marker1 = 0;
+ var s : S;
+ return s;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ f();
+ let marker2 = 0;
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+struct S {
+ x : i32,
+ y : i32,
+}
+
+var<private> tint_discard : bool = false;
+
+fn f() -> S {
+ if (true) {
+ tint_discard = true;
+ return S();
+ }
+ let marker1 = 0;
+ var s : S;
+ return s;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let marker2 = 0;
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Call_Nested) {
+ auto* src = R"(
+fn f() -> i32 {
+ let marker1 = 0;
+ if (true) {
+ discard;
+ }
+ let marker2 = 0;
+ return 0;
+}
+
+fn g() -> i32 {
+ let marker1 = 0;
+ f();
+ let marker2 = 0;
+ return 0;
+}
+
+fn h() -> i32{
+ let marker1 = 0;
+ g();
+ let marker2 = 0;
+ return 0;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ h();
+ let marker2 = 0;
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ let marker1 = 0;
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ let marker2 = 0;
+ return 0;
+}
+
+fn g() -> i32 {
+ let marker1 = 0;
+ f();
+ if (tint_discard) {
+ return i32();
+ }
+ let marker2 = 0;
+ return 0;
+}
+
+fn h() -> i32 {
+ let marker1 = 0;
+ g();
+ if (tint_discard) {
+ return i32();
+ }
+ let marker2 = 0;
+ return 0;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ h();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let marker2 = 0;
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Call_Multiple) {
+ auto* src = R"(
+fn f() {
+ discard;
+ let marker1 = 0;
+}
+
+fn g() {
+ discard;
+ let marker1 = 0;
+}
+
+fn h() {
+ discard;
+ let marker1 = 0;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ f();
+ let marker2 = 0;
+ g();
+ let marker3 = 0;
+ h();
+ let marker4 = 0;
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() {
+ tint_discard = true;
+ return;
+ let marker1 = 0;
+}
+
+fn g() {
+ tint_discard = true;
+ return;
+ let marker1 = 0;
+}
+
+fn h() {
+ tint_discard = true;
+ return;
+ let marker1 = 0;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let marker2 = 0;
+ g();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let marker3 = 0;
+ h();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let marker4 = 0;
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Call_DiscardFuncDeclaredBelow) {
+ auto* src = R"(
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ f();
+ let marker1 = 0;
+ return vec4<f32>();
+}
+
+fn f() {
+ discard;
+ let marker1 = 0;
+}
+)";
+ auto* expect = R"(
+fn tint_discard_func() {
+ discard;
+}
+
+var<private> tint_discard : bool = false;
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let marker1 = 0;
+ return vec4<f32>();
+}
+
+fn f() {
+ tint_discard = true;
+ return;
+ let marker1 = 0;
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, If) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 42;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ if (f() == 42) {
+ let marker1 = 0;
+ }
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 42;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let tint_symbol = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ if ((tint_symbol == 42)) {
+ let marker1 = 0;
+ }
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, ElseIf) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 42;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ if (true) {
+ let marker1 = 0;
+ } else if (f() == 42) {
+ let marker2 = 0;
+ } else if (true) {
+ let marker3 = 0;
+ }
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 42;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ if (true) {
+ let marker1 = 0;
+ } else {
+ let tint_symbol = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ if ((tint_symbol == 42)) {
+ let marker2 = 0;
+ } else if (true) {
+ let marker3 = 0;
+ }
+ }
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, ForLoop_Init_Assignment) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 42;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ var a = 0;
+ for (a = f(); ; ) {
+ let marker2 = 0;
+ break;
+ }
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 42;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ var a = 0;
+ var tint_symbol = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ for(a = tint_symbol; ; ) {
+ let marker2 = 0;
+ break;
+ }
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, ForLoop_Init_Call) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 42;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ for (f(); ; ) {
+ let marker2 = 0;
+ break;
+ }
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 42;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ var tint_symbol = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ for(_ = tint_symbol; ; ) {
+ let marker2 = 0;
+ break;
+ }
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, ForLoop_Init_VariableDecl) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 42;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ for (let i = f(); ; ) {
+ let marker2 = 0;
+ break;
+ }
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 42;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ var tint_symbol = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ for(let i = tint_symbol; ; ) {
+ let marker2 = 0;
+ break;
+ }
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, ForLoop_Cond) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 42;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ for (; f() == 42; ) {
+ let marker2 = 0;
+ break;
+ }
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 42;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ loop {
+ let tint_symbol = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ if (!((tint_symbol == 42))) {
+ break;
+ }
+ {
+ let marker2 = 0;
+ break;
+ }
+ }
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, ForLoop_Cont) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 42;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ for (; ; f()) {
+ let marker2 = 0;
+ break;
+ }
+ return vec4<f32>();
+}
+)";
+ auto* expect =
+ R"(test:12:12 error: cannot call a function that may discard inside a continuing block
+ for (; ; f()) {
+ ^
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Switch) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 42;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ switch (f()) {
+ case 0: {
+ let marker1 = 0;
+ }
+ case 1: {
+ let marker2 = 0;
+ }
+ case 42: {
+ let marker3 = 0;
+ }
+ default: {
+ let marker4 = 0;
+ }
+ }
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 42;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ var tint_symbol = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ switch(tint_symbol) {
+ case 0: {
+ let marker1 = 0;
+ }
+ case 1: {
+ let marker2 = 0;
+ }
+ case 42: {
+ let marker3 = 0;
+ }
+ default: {
+ let marker4 = 0;
+ }
+ }
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Return) {
+ auto* src = R"(
+struct S {
+ x : i32,
+ y : i32,
+};
+
+fn f() -> S {
+ if (true) {
+ discard;
+ }
+ var s : S;
+ return s;
+}
+
+fn g() -> S {
+ return f();
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ g();
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+struct S {
+ x : i32,
+ y : i32,
+}
+
+var<private> tint_discard : bool = false;
+
+fn f() -> S {
+ if (true) {
+ tint_discard = true;
+ return S();
+ }
+ var s : S;
+ return s;
+}
+
+fn g() -> S {
+ var tint_symbol = f();
+ if (tint_discard) {
+ return S();
+ }
+ return tint_symbol;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let marker1 = 0;
+ g();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, VariableDecl) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 42;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ var a = f();
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 42;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ var a = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Assignment_RightDiscard) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 42;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ var a : i32;
+ a = f();
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 42;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ var a : i32;
+ a = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Assignment_LeftDiscard) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 0;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ var b = array<i32, 10>();
+ b[f()] = 10;
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 0;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ var b = array<i32, 10>();
+ let tint_symbol = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ b[tint_symbol] = 10;
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Assignment_BothDiscard) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 0;
+}
+
+fn g() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 0;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ var b = array<i32, 10>();
+ b[f()] = g();
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 0;
+}
+
+fn g() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 0;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ var b = array<i32, 10>();
+ let tint_symbol = g();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let tint_symbol_1 = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ b[tint_symbol_1] = tint_symbol;
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Binary_Arith_MultipleDiscardFuncs) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 0;
+}
+
+fn g() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 0;
+}
+
+fn h() -> i32{
+ if (true) {
+ discard;
+ }
+ return 0;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ if ((f() + g() + h()) == 0) {
+ let marker1 = 0;
+ }
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 0;
+}
+
+fn g() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 0;
+}
+
+fn h() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 0;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let tint_symbol = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let tint_symbol_1 = g();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ let tint_symbol_2 = h();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ if ((((tint_symbol + tint_symbol_1) + tint_symbol_2) == 0)) {
+ let marker1 = 0;
+ }
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, Binary_Logical_MultipleDiscardFuncs) {
+ auto* src = R"(
+fn f() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 0;
+}
+
+fn g() -> i32 {
+ if (true) {
+ discard;
+ }
+ return 0;
+}
+
+fn h() -> i32{
+ if (true) {
+ discard;
+ }
+ return 0;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ if (f() == 1 && g() == 2 && h() == 3) {
+ let marker1 = 0;
+ }
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard : bool = false;
+
+fn f() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 0;
+}
+
+fn g() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 0;
+}
+
+fn h() -> i32 {
+ if (true) {
+ tint_discard = true;
+ return i32();
+ }
+ return 0;
+}
+
+fn tint_discard_func() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ let tint_symbol_2 = f();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ var tint_symbol_1 = (tint_symbol_2 == 1);
+ if (tint_symbol_1) {
+ let tint_symbol_3 = g();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ tint_symbol_1 = (tint_symbol_3 == 2);
+ }
+ var tint_symbol = tint_symbol_1;
+ if (tint_symbol) {
+ let tint_symbol_4 = h();
+ if (tint_discard) {
+ tint_discard_func();
+ return vec4<f32>();
+ }
+ tint_symbol = (tint_symbol_4 == 3);
+ }
+ if (tint_symbol) {
+ let marker1 = 0;
+ }
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnwindDiscardFunctionsTest, EnsureNoSymbolCollision) {
+ auto* src = R"(
+var<private> tint_discard_func : i32;
+var<private> tint_discard : i32;
+
+fn f() {
+ discard;
+ let marker1 = 0;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
+ f();
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+ auto* expect = R"(
+var<private> tint_discard_func : i32;
+
+var<private> tint_discard : i32;
+
+var<private> tint_discard_1 : bool = false;
+
+fn f() {
+ tint_discard_1 = true;
+ return;
+ let marker1 = 0;
+}
+
+fn tint_discard_func_1() {
+ discard;
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord_in : vec4<f32>) -> @location(0) vec4<f32> {
+ f();
+ if (tint_discard_1) {
+ tint_discard_func_1();
+ return vec4<f32>();
+ }
+ let marker1 = 0;
+ return vec4<f32>();
+}
+)";
+
+ DataMap data;
+ auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace
+} // namespace transform
+} // namespace tint
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 909fcff..bf35449 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -62,6 +62,7 @@
#include "src/tint/transform/remove_phonies.h"
#include "src/tint/transform/simplify_pointers.h"
#include "src/tint/transform/unshadow.h"
+#include "src/tint/transform/unwind_discard_functions.h"
#include "src/tint/transform/zero_init_workgroup_memory.h"
#include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h"
@@ -187,6 +188,7 @@
// only accessed directly via member accessors.
manager.Add<transform::NumWorkgroupsFromUniform>();
manager.Add<transform::PromoteSideEffectsToDecl>();
+ manager.Add<transform::UnwindDiscardFunctions>();
manager.Add<transform::SimplifyPointers>();
manager.Add<transform::RemovePhonies>();
// ArrayLengthFromUniform must come after InlinePointerLets and Simplify, as
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 78388dd..3e8d38b 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -68,6 +68,7 @@
#include "src/tint/transform/remove_phonies.h"
#include "src/tint/transform/simplify_pointers.h"
#include "src/tint/transform/unshadow.h"
+#include "src/tint/transform/unwind_discard_functions.h"
#include "src/tint/transform/vectorize_scalar_matrix_constructors.h"
#include "src/tint/transform/wrap_arrays_in_structs.h"
#include "src/tint/transform/zero_init_workgroup_memory.h"
@@ -174,6 +175,7 @@
}
manager.Add<transform::CanonicalizeEntryPointIO>();
manager.Add<transform::PromoteSideEffectsToDecl>();
+ manager.Add<transform::UnwindDiscardFunctions>();
manager.Add<transform::PromoteInitializersToConstVar>();
manager.Add<transform::VectorizeScalarMatrixConstructors>();
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index 3b3bdb7..1bf650f 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -52,6 +52,7 @@
#include "src/tint/transform/remove_unreachable_statements.h"
#include "src/tint/transform/simplify_pointers.h"
#include "src/tint/transform/unshadow.h"
+#include "src/tint/transform/unwind_discard_functions.h"
#include "src/tint/transform/var_for_dynamic_index.h"
#include "src/tint/transform/vectorize_scalar_matrix_constructors.h"
#include "src/tint/transform/zero_init_workgroup_memory.h"
@@ -278,6 +279,7 @@
}
manager.Add<transform::RemoveUnreachableStatements>();
manager.Add<transform::PromoteSideEffectsToDecl>();
+ manager.Add<transform::UnwindDiscardFunctions>();
manager.Add<transform::SimplifyPointers>(); // Required for arrayLength()
manager.Add<transform::FoldConstants>();
manager.Add<transform::VectorizeScalarMatrixConstructors>();
diff --git a/test/tint/BUILD.gn b/test/tint/BUILD.gn
index 834d948..7f6ec7e 100644
--- a/test/tint/BUILD.gn
+++ b/test/tint/BUILD.gn
@@ -338,6 +338,7 @@
"../../src/tint/transform/test_helper.h",
"../../src/tint/transform/transform_test.cc",
"../../src/tint/transform/unshadow_test.cc",
+ "../../src/tint/transform/unwind_discard_functions_test.cc",
"../../src/tint/transform/utils/hoist_to_decl_before_test.cc",
"../../src/tint/transform/var_for_dynamic_index_test.cc",
"../../src/tint/transform/vectorize_scalar_matrix_constructors_test.cc",
diff --git a/test/tint/bug/dawn/947.wgsl.expected.glsl b/test/tint/bug/dawn/947.wgsl.expected.glsl
index f3e2440..71b989e 100644
--- a/test/tint/bug/dawn/947.wgsl.expected.glsl
+++ b/test/tint/bug/dawn/947.wgsl.expected.glsl
@@ -52,19 +52,29 @@
vec4 position;
};
+bool tint_discard = false;
uniform highp sampler2D myTexture_mySampler;
vec4 fs_main(vec2 texcoord) {
vec2 clampedTexcoord = clamp(texcoord, vec2(0.0f, 0.0f), vec2(1.0f, 1.0f));
if (!(all(equal(clampedTexcoord, texcoord)))) {
- discard;
+ tint_discard = true;
+ return vec4(0.0f, 0.0f, 0.0f, 0.0f);
}
vec4 srcColor = texture(myTexture_mySampler, texcoord);
return srcColor;
}
+void tint_discard_func() {
+ discard;
+}
+
void main() {
vec4 inner_result = fs_main(texcoord_1);
+ if (tint_discard) {
+ tint_discard_func();
+ return;
+ }
value = inner_result;
return;
}
diff --git a/test/tint/bug/dawn/947.wgsl.expected.hlsl b/test/tint/bug/dawn/947.wgsl.expected.hlsl
index da0ff6a..7bcadcb 100644
--- a/test/tint/bug/dawn/947.wgsl.expected.hlsl
+++ b/test/tint/bug/dawn/947.wgsl.expected.hlsl
@@ -45,21 +45,29 @@
float4 value : SV_Target0;
};
+static bool tint_discard = false;
+
float4 fs_main_inner(float2 texcoord) {
- if (true) {
- float2 clampedTexcoord = clamp(texcoord, float2(0.0f, 0.0f), float2(1.0f, 1.0f));
- if (!(all((clampedTexcoord == texcoord)))) {
- discard;
- }
- float4 srcColor = myTexture.Sample(mySampler, texcoord);
- return srcColor;
+ float2 clampedTexcoord = clamp(texcoord, float2(0.0f, 0.0f), float2(1.0f, 1.0f));
+ if (!(all((clampedTexcoord == texcoord)))) {
+ tint_discard = true;
+ return float4(0.0f, 0.0f, 0.0f, 0.0f);
}
- float4 unused;
- return unused;
+ float4 srcColor = myTexture.Sample(mySampler, texcoord);
+ return srcColor;
+}
+
+void tint_discard_func() {
+ discard;
}
tint_symbol_5 fs_main(tint_symbol_4 tint_symbol_3) {
const float4 inner_result_1 = fs_main_inner(tint_symbol_3.texcoord);
+ if (tint_discard) {
+ tint_discard_func();
+ const tint_symbol_5 tint_symbol_8 = (tint_symbol_5)0;
+ return tint_symbol_8;
+ }
tint_symbol_5 wrapper_result_1 = (tint_symbol_5)0;
wrapper_result_1.value = inner_result_1;
return wrapper_result_1;
diff --git a/test/tint/bug/dawn/947.wgsl.expected.msl b/test/tint/bug/dawn/947.wgsl.expected.msl
index 22bfdd3..15efcd0 100644
--- a/test/tint/bug/dawn/947.wgsl.expected.msl
+++ b/test/tint/bug/dawn/947.wgsl.expected.msl
@@ -20,21 +20,21 @@
float2 arr[3];
};
-VertexOutputs vs_main_inner(uint VertexIndex, const constant Uniforms* const tint_symbol_4) {
+VertexOutputs vs_main_inner(uint VertexIndex, const constant Uniforms* const tint_symbol_5) {
tint_array_wrapper texcoord = {.arr={float2(-0.5f, 0.0f), float2(1.5f, 0.0f), float2(0.5f, 2.0f)}};
VertexOutputs output = {};
output.position = float4(((texcoord.arr[VertexIndex] * 2.0f) - float2(1.0f, 1.0f)), 0.0f, 1.0f);
- bool flipY = ((*(tint_symbol_4)).u_scale[1] < 0.0f);
+ bool flipY = ((*(tint_symbol_5)).u_scale[1] < 0.0f);
if (flipY) {
- output.texcoords = ((((texcoord.arr[VertexIndex] * (*(tint_symbol_4)).u_scale) + (*(tint_symbol_4)).u_offset) * float2(1.0f, -1.0f)) + float2(0.0f, 1.0f));
+ output.texcoords = ((((texcoord.arr[VertexIndex] * (*(tint_symbol_5)).u_scale) + (*(tint_symbol_5)).u_offset) * float2(1.0f, -1.0f)) + float2(0.0f, 1.0f));
} else {
- output.texcoords = ((((texcoord.arr[VertexIndex] * float2(1.0f, -1.0f)) + float2(0.0f, 1.0f)) * (*(tint_symbol_4)).u_scale) + (*(tint_symbol_4)).u_offset);
+ output.texcoords = ((((texcoord.arr[VertexIndex] * float2(1.0f, -1.0f)) + float2(0.0f, 1.0f)) * (*(tint_symbol_5)).u_scale) + (*(tint_symbol_5)).u_offset);
}
return output;
}
-vertex tint_symbol vs_main(const constant Uniforms* tint_symbol_5 [[buffer(0)]], uint VertexIndex [[vertex_id]]) {
- VertexOutputs const inner_result = vs_main_inner(VertexIndex, tint_symbol_5);
+vertex tint_symbol vs_main(const constant Uniforms* tint_symbol_6 [[buffer(0)]], uint VertexIndex [[vertex_id]]) {
+ VertexOutputs const inner_result = vs_main_inner(VertexIndex, tint_symbol_6);
tint_symbol wrapper_result = {};
wrapper_result.texcoords = inner_result.texcoords;
wrapper_result.position = inner_result.position;
@@ -49,17 +49,28 @@
float4 value [[color(0)]];
};
-float4 fs_main_inner(float2 texcoord, texture2d<float, access::sample> tint_symbol_6, sampler tint_symbol_7) {
+float4 fs_main_inner(float2 texcoord, thread bool* const tint_symbol_7, texture2d<float, access::sample> tint_symbol_8, sampler tint_symbol_9) {
float2 clampedTexcoord = clamp(texcoord, float2(0.0f, 0.0f), float2(1.0f, 1.0f));
if (!(all((clampedTexcoord == texcoord)))) {
- discard_fragment();
+ *(tint_symbol_7) = true;
+ return float4();
}
- float4 srcColor = tint_symbol_6.sample(tint_symbol_7, texcoord);
+ float4 srcColor = tint_symbol_8.sample(tint_symbol_9, texcoord);
return srcColor;
}
-fragment tint_symbol_3 fs_main(texture2d<float, access::sample> tint_symbol_8 [[texture(0)]], sampler tint_symbol_9 [[sampler(0)]], tint_symbol_2 tint_symbol_1 [[stage_in]]) {
- float4 const inner_result_1 = fs_main_inner(tint_symbol_1.texcoord, tint_symbol_8, tint_symbol_9);
+void tint_discard_func() {
+ discard_fragment();
+}
+
+fragment tint_symbol_3 fs_main(texture2d<float, access::sample> tint_symbol_11 [[texture(0)]], sampler tint_symbol_12 [[sampler(0)]], tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ thread bool tint_symbol_10 = false;
+ float4 const inner_result_1 = fs_main_inner(tint_symbol_1.texcoord, &(tint_symbol_10), tint_symbol_11, tint_symbol_12);
+ if (tint_symbol_10) {
+ tint_discard_func();
+ tint_symbol_3 const tint_symbol_4 = {};
+ return tint_symbol_4;
+ }
tint_symbol_3 wrapper_result_1 = {};
wrapper_result_1.value = inner_result_1;
return wrapper_result_1;
diff --git a/test/tint/bug/dawn/947.wgsl.expected.spvasm b/test/tint/bug/dawn/947.wgsl.expected.spvasm
index cfe88b2..df48a9a 100644
--- a/test/tint/bug/dawn/947.wgsl.expected.spvasm
+++ b/test/tint/bug/dawn/947.wgsl.expected.spvasm
@@ -1,10 +1,10 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
-; Bound: 137
+; Bound: 140
; Schema: 0
OpCapability Shader
- %116 = OpExtInstImport "GLSL.std.450"
+ %118 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %vs_main "vs_main" %VertexIndex_1 %texcoords_1 %position_1 %vertex_point_size
OpEntryPoint Fragment %fs_main "fs_main" %texcoord_1 %value
@@ -30,6 +30,7 @@
OpName %output "output"
OpName %flipY "flipY"
OpName %vs_main "vs_main"
+ OpName %tint_discard_func "tint_discard_func"
OpName %fs_main_inner "fs_main_inner"
OpName %texcoord_0 "texcoord"
OpName %clampedTexcoord "clampedTexcoord"
@@ -114,10 +115,10 @@
%89 = OpConstantComposite %v2float %float_0 %float_1
%void = OpTypeVoid
%103 = OpTypeFunction %void
- %111 = OpTypeFunction %v4float %v2float
- %117 = OpConstantComposite %v2float %float_0 %float_0
+ %113 = OpTypeFunction %v4float %v2float
+ %119 = OpConstantComposite %v2float %float_0 %float_0
%v2bool = OpTypeVector %bool 2
- %129 = OpTypeSampledImage %27
+ %132 = OpTypeSampledImage %27
%vs_main_inner = OpFunction %VertexOutputs None %28
%VertexIndex = OpFunctionParameter %uint
%32 = OpLabel
@@ -184,34 +185,39 @@
OpStore %vertex_point_size %float_1
OpReturn
OpFunctionEnd
-%fs_main_inner = OpFunction %v4float None %111
+%tint_discard_func = OpFunction %void None %103
+ %112 = OpLabel
+ OpKill
+ OpFunctionEnd
+%fs_main_inner = OpFunction %v4float None %113
%texcoord_0 = OpFunctionParameter %v2float
- %114 = OpLabel
+ %116 = OpLabel
%clampedTexcoord = OpVariable %_ptr_Function_v2float Function %8
%srcColor = OpVariable %_ptr_Function_v4float Function %12
- %115 = OpExtInst %v2float %116 NClamp %texcoord_0 %117 %58
- OpStore %clampedTexcoord %115
- %121 = OpLoad %v2float %clampedTexcoord
- %122 = OpFOrdEqual %v2bool %121 %texcoord_0
- %120 = OpAll %bool %122
- %119 = OpLogicalNot %bool %120
- OpSelectionMerge %124 None
- OpBranchConditional %119 %125 %124
- %125 = OpLabel
- OpKill
- %124 = OpLabel
- %127 = OpLoad %24 %mySampler
- %128 = OpLoad %27 %myTexture
- %130 = OpSampledImage %129 %128 %127
- %126 = OpImageSampleImplicitLod %v4float %130 %texcoord_0
- OpStore %srcColor %126
- %132 = OpLoad %v4float %srcColor
- OpReturnValue %132
+ %117 = OpExtInst %v2float %118 NClamp %texcoord_0 %119 %58
+ OpStore %clampedTexcoord %117
+ %123 = OpLoad %v2float %clampedTexcoord
+ %124 = OpFOrdEqual %v2bool %123 %texcoord_0
+ %122 = OpAll %bool %124
+ %121 = OpLogicalNot %bool %122
+ OpSelectionMerge %126 None
+ OpBranchConditional %121 %127 %126
+ %127 = OpLabel
+ %128 = OpFunctionCall %void %tint_discard_func
+ OpReturnValue %12
+ %126 = OpLabel
+ %130 = OpLoad %24 %mySampler
+ %131 = OpLoad %27 %myTexture
+ %133 = OpSampledImage %132 %131 %130
+ %129 = OpImageSampleImplicitLod %v4float %133 %texcoord_0
+ OpStore %srcColor %129
+ %135 = OpLoad %v4float %srcColor
+ OpReturnValue %135
OpFunctionEnd
%fs_main = OpFunction %void None %103
- %134 = OpLabel
- %136 = OpLoad %v2float %texcoord_1
- %135 = OpFunctionCall %v4float %fs_main_inner %136
- OpStore %value %135
+ %137 = OpLabel
+ %139 = OpLoad %v2float %texcoord_1
+ %138 = OpFunctionCall %v4float %fs_main_inner %139
+ OpStore %value %138
OpReturn
OpFunctionEnd
diff --git a/test/tint/bug/tint/1081.wgsl.expected.glsl b/test/tint/bug/tint/1081.wgsl.expected.glsl
index 3b4deae..5bef660 100644
--- a/test/tint/bug/tint/1081.wgsl.expected.glsl
+++ b/test/tint/bug/tint/1081.wgsl.expected.glsl
@@ -3,9 +3,11 @@
layout(location = 1) flat in ivec3 x_1;
layout(location = 2) out int value;
+bool tint_discard = false;
int f(int x) {
if ((x == 10)) {
- discard;
+ tint_discard = true;
+ return 0;
}
return x;
}
@@ -14,6 +16,9 @@
int y = x.x;
while (true) {
int r = f(y);
+ if (tint_discard) {
+ return 0;
+ }
if ((r == 0)) {
break;
}
@@ -21,8 +26,16 @@
return y;
}
+void tint_discard_func() {
+ discard;
+}
+
void main() {
int inner_result = tint_symbol(x_1);
+ if (tint_discard) {
+ tint_discard_func();
+ return;
+ }
value = inner_result;
return;
}
diff --git a/test/tint/bug/tint/1081.wgsl.expected.hlsl b/test/tint/bug/tint/1081.wgsl.expected.hlsl
index ad9174c..60ace97 100644
--- a/test/tint/bug/tint/1081.wgsl.expected.hlsl
+++ b/test/tint/bug/tint/1081.wgsl.expected.hlsl
@@ -1,12 +1,11 @@
+static bool tint_discard = false;
+
int f(int x) {
- if (true) {
- if ((x == 10)) {
- discard;
- }
- return x;
+ if ((x == 10)) {
+ tint_discard = true;
+ return 0;
}
- int unused;
- return unused;
+ return x;
}
struct tint_symbol_1 {
@@ -20,6 +19,9 @@
int y = x.x;
[loop] while (true) {
const int r = f(y);
+ if (tint_discard) {
+ return 0;
+ }
if ((r == 0)) {
break;
}
@@ -27,8 +29,17 @@
return y;
}
+void tint_discard_func() {
+ discard;
+}
+
tint_symbol_2 main(tint_symbol_1 tint_symbol) {
const int inner_result = main_inner(tint_symbol.x);
+ if (tint_discard) {
+ tint_discard_func();
+ const tint_symbol_2 tint_symbol_3 = (tint_symbol_2)0;
+ return tint_symbol_3;
+ }
tint_symbol_2 wrapper_result = (tint_symbol_2)0;
wrapper_result.value = inner_result;
return wrapper_result;
diff --git a/test/tint/bug/tint/1081.wgsl.expected.msl b/test/tint/bug/tint/1081.wgsl.expected.msl
index 34ebe0c..8304df1 100644
--- a/test/tint/bug/tint/1081.wgsl.expected.msl
+++ b/test/tint/bug/tint/1081.wgsl.expected.msl
@@ -1,9 +1,10 @@
#include <metal_stdlib>
using namespace metal;
-int f(int x) {
+int f(int x, thread bool* const tint_symbol_5) {
if ((x == 10)) {
- discard_fragment();
+ *(tint_symbol_5) = true;
+ return int();
}
return x;
}
@@ -16,10 +17,13 @@
int value [[color(2)]];
};
-int tint_symbol_inner(int3 x) {
+int tint_symbol_inner(int3 x, thread bool* const tint_symbol_6) {
int y = x[0];
while (true) {
- int const r = f(y);
+ int const r = f(y, tint_symbol_6);
+ if (*(tint_symbol_6)) {
+ return int();
+ }
if ((r == 0)) {
break;
}
@@ -27,8 +31,18 @@
return y;
}
+void tint_discard_func() {
+ discard_fragment();
+}
+
fragment tint_symbol_3 tint_symbol(tint_symbol_2 tint_symbol_1 [[stage_in]]) {
- int const inner_result = tint_symbol_inner(tint_symbol_1.x);
+ thread bool tint_symbol_7 = false;
+ int const inner_result = tint_symbol_inner(tint_symbol_1.x, &(tint_symbol_7));
+ if (tint_symbol_7) {
+ tint_discard_func();
+ tint_symbol_3 const tint_symbol_4 = {};
+ return tint_symbol_4;
+ }
tint_symbol_3 wrapper_result = {};
wrapper_result.value = inner_result;
return wrapper_result;
diff --git a/test/tint/bug/tint/1081.wgsl.expected.spvasm b/test/tint/bug/tint/1081.wgsl.expected.spvasm
index 2f5ee3f..53e025c 100644
--- a/test/tint/bug/tint/1081.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/1081.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
-; Bound: 41
+; Bound: 51
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
@@ -9,8 +9,10 @@
OpExecutionMode %main OriginUpperLeft
OpName %x_1 "x_1"
OpName %value "value"
+ OpName %tint_discard "tint_discard"
OpName %f "f"
OpName %x "x"
+ OpName %tint_discard_func "tint_discard_func"
OpName %main_inner "main_inner"
OpName %x_0 "x"
OpName %y "y"
@@ -25,55 +27,71 @@
%_ptr_Output_int = OpTypePointer Output %int
%7 = OpConstantNull %int
%value = OpVariable %_ptr_Output_int Output %7
- %8 = OpTypeFunction %int %int
- %int_10 = OpConstant %int 10
%bool = OpTypeBool
- %17 = OpTypeFunction %int %v3int
+ %false = OpConstantFalse %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discard = OpVariable %_ptr_Private_bool Private %false
+ %12 = OpTypeFunction %int %int
+ %int_10 = OpConstant %int 10
+ %true = OpConstantTrue %bool
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void
+ %25 = OpTypeFunction %int %v3int
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
- %void = OpTypeVoid
- %35 = OpTypeFunction %void
- %f = OpFunction %int None %8
+ %f = OpFunction %int None %12
%x = OpFunctionParameter %int
- %11 = OpLabel
- %13 = OpIEqual %bool %x %int_10
- OpSelectionMerge %15 None
- OpBranchConditional %13 %16 %15
- %16 = OpLabel
- OpKill
%15 = OpLabel
+ %17 = OpIEqual %bool %x %int_10
+ OpSelectionMerge %18 None
+ OpBranchConditional %17 %19 %18
+ %19 = OpLabel
+ OpStore %tint_discard %true
+ OpReturnValue %7
+ %18 = OpLabel
OpReturnValue %x
OpFunctionEnd
- %main_inner = OpFunction %int None %17
- %x_0 = OpFunctionParameter %v3int
- %20 = OpLabel
- %y = OpVariable %_ptr_Function_int Function %7
- %21 = OpCompositeExtract %int %x_0 0
- OpStore %y %21
- OpBranch %24
+%tint_discard_func = OpFunction %void None %21
%24 = OpLabel
- OpLoopMerge %25 %26 None
- OpBranch %27
- %27 = OpLabel
- %29 = OpLoad %int %y
- %28 = OpFunctionCall %int %f %29
- %31 = OpIEqual %bool %28 %int_0
- OpSelectionMerge %32 None
- OpBranchConditional %31 %33 %32
- %33 = OpLabel
- OpBranch %25
- %32 = OpLabel
- OpBranch %26
- %26 = OpLabel
- OpBranch %24
- %25 = OpLabel
- %34 = OpLoad %int %y
- OpReturnValue %34
+ OpKill
OpFunctionEnd
- %main = OpFunction %void None %35
- %38 = OpLabel
- %40 = OpLoad %v3int %x_1
- %39 = OpFunctionCall %int %main_inner %40
- OpStore %value %39
+ %main_inner = OpFunction %int None %25
+ %x_0 = OpFunctionParameter %v3int
+ %28 = OpLabel
+ %y = OpVariable %_ptr_Function_int Function %7
+ %29 = OpCompositeExtract %int %x_0 0
+ OpStore %y %29
+ OpBranch %32
+ %32 = OpLabel
+ OpLoopMerge %33 %34 None
+ OpBranch %35
+ %35 = OpLabel
+ %37 = OpLoad %int %y
+ %36 = OpFunctionCall %int %f %37
+ %38 = OpLoad %bool %tint_discard
+ OpSelectionMerge %39 None
+ OpBranchConditional %38 %40 %39
+ %40 = OpLabel
+ %41 = OpFunctionCall %void %tint_discard_func
+ OpReturnValue %7
+ %39 = OpLabel
+ %43 = OpIEqual %bool %36 %int_0
+ OpSelectionMerge %44 None
+ OpBranchConditional %43 %45 %44
+ %45 = OpLabel
+ OpBranch %33
+ %44 = OpLabel
+ OpBranch %34
+ %34 = OpLabel
+ OpBranch %32
+ %33 = OpLabel
+ %46 = OpLoad %int %y
+ OpReturnValue %46
+ OpFunctionEnd
+ %main = OpFunction %void None %21
+ %48 = OpLabel
+ %50 = OpLoad %v3int %x_1
+ %49 = OpFunctionCall %int %main_inner %50
+ OpStore %value %49
OpReturn
OpFunctionEnd
diff --git a/test/tint/bug/tint/1118.wgsl.expected.glsl b/test/tint/bug/tint/1118.wgsl.expected.glsl
index 7f61d30..a9bb098 100644
--- a/test/tint/bug/tint/1118.wgsl.expected.glsl
+++ b/test/tint/bug/tint/1118.wgsl.expected.glsl
@@ -39,6 +39,7 @@
} x_137;
vec4 glFragColor = vec4(0.0f, 0.0f, 0.0f, 0.0f);
+bool tint_discard = false;
void main_1() {
vec3 viewDirectionW = vec3(0.0f, 0.0f, 0.0f);
vec4 baseColor = vec4(0.0f, 0.0f, 0.0f, 0.0f);
@@ -57,10 +58,12 @@
vec3 finalSpecular = vec3(0.0f, 0.0f, 0.0f);
vec4 color = vec4(0.0f, 0.0f, 0.0f, 0.0f);
if ((fClipDistance3 > 0.0f)) {
- discard;
+ tint_discard = true;
+ return;
}
if ((fClipDistance4 > 0.0f)) {
- discard;
+ tint_discard = true;
+ return;
}
vec4 x_34 = x_29.vEyePosition;
vec3 x_38 = vec3(0.0f, 0.0f, 0.0f);
@@ -115,12 +118,24 @@
fClipDistance3 = fClipDistance3_param;
fClipDistance4 = fClipDistance4_param;
main_1();
- main_out tint_symbol_1 = main_out(glFragColor);
- return tint_symbol_1;
+ if (tint_discard) {
+ main_out tint_symbol_1 = main_out(vec4(0.0f, 0.0f, 0.0f, 0.0f));
+ return tint_symbol_1;
+ }
+ main_out tint_symbol_2 = main_out(glFragColor);
+ return tint_symbol_2;
+}
+
+void tint_discard_func() {
+ discard;
}
void main() {
main_out inner_result = tint_symbol(fClipDistance3_param_1, fClipDistance4_param_1);
+ if (tint_discard) {
+ tint_discard_func();
+ return;
+ }
glFragColor_1_1 = inner_result.glFragColor_1;
return;
}
diff --git a/test/tint/bug/tint/1118.wgsl.expected.hlsl b/test/tint/bug/tint/1118.wgsl.expected.hlsl
index 9d86c0e..117a578 100644
--- a/test/tint/bug/tint/1118.wgsl.expected.hlsl
+++ b/test/tint/bug/tint/1118.wgsl.expected.hlsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
static float fClipDistance3 = 0.0f;
static float fClipDistance4 = 0.0f;
cbuffer cbuffer_x_29 : register(b0, space0) {
@@ -12,6 +10,7 @@
uint4 x_137[1];
};
static float4 glFragColor = float4(0.0f, 0.0f, 0.0f, 0.0f);
+static bool tint_discard = false;
void main_1() {
float3 viewDirectionW = float3(0.0f, 0.0f, 0.0f);
@@ -31,10 +30,12 @@
float3 finalSpecular = float3(0.0f, 0.0f, 0.0f);
float4 color = float4(0.0f, 0.0f, 0.0f, 0.0f);
if ((fClipDistance3 > 0.0f)) {
- discard;
+ tint_discard = true;
+ return;
}
if ((fClipDistance4 > 0.0f)) {
- discard;
+ tint_discard = true;
+ return;
}
const float4 x_34 = asfloat(x_29[0]);
const float3 x_38 = float3(0.0f, 0.0f, 0.0f);
@@ -96,15 +97,26 @@
fClipDistance3 = fClipDistance3_param;
fClipDistance4 = fClipDistance4_param;
main_1();
- const main_out tint_symbol_8 = {glFragColor};
- return tint_symbol_8;
+ if (tint_discard) {
+ const main_out tint_symbol_8 = (main_out)0;
+ return tint_symbol_8;
+ }
+ const main_out tint_symbol_9 = {glFragColor};
+ return tint_symbol_9;
+}
+
+void tint_discard_func() {
+ discard;
}
tint_symbol_2 main(tint_symbol_1 tint_symbol) {
const main_out inner_result = main_inner(tint_symbol.fClipDistance3_param, tint_symbol.fClipDistance4_param);
+ if (tint_discard) {
+ tint_discard_func();
+ const tint_symbol_2 tint_symbol_10 = (tint_symbol_2)0;
+ return tint_symbol_10;
+ }
tint_symbol_2 wrapper_result = (tint_symbol_2)0;
wrapper_result.glFragColor_1 = inner_result.glFragColor_1;
return wrapper_result;
}
-Internal error: unread predicate
-
diff --git a/test/tint/bug/tint/1118.wgsl.expected.msl b/test/tint/bug/tint/1118.wgsl.expected.msl
index 6f56a9c..e1bcabf 100644
--- a/test/tint/bug/tint/1118.wgsl.expected.msl
+++ b/test/tint/bug/tint/1118.wgsl.expected.msl
@@ -28,7 +28,7 @@
/* 0x0000 */ float visibility;
};
-void main_1(thread float* const tint_symbol_5, thread float* const tint_symbol_6, const constant Scene* const tint_symbol_7, const constant Material* const tint_symbol_8, const constant Mesh* const tint_symbol_9, thread float4* const tint_symbol_10) {
+void main_1(thread float* const tint_symbol_7, thread bool* const tint_symbol_8, thread float* const tint_symbol_9, const constant Scene* const tint_symbol_10, const constant Material* const tint_symbol_11, const constant Mesh* const tint_symbol_12, thread float4* const tint_symbol_13) {
float3 viewDirectionW = 0.0f;
float4 baseColor = 0.0f;
float3 diffuseColor = 0.0f;
@@ -45,21 +45,23 @@
float3 finalDiffuse = 0.0f;
float3 finalSpecular = 0.0f;
float4 color = 0.0f;
- float const x_9 = *(tint_symbol_5);
+ float const x_9 = *(tint_symbol_7);
if ((x_9 > 0.0f)) {
- discard_fragment();
+ *(tint_symbol_8) = true;
+ return;
}
- float const x_17 = *(tint_symbol_6);
+ float const x_17 = *(tint_symbol_9);
if ((x_17 > 0.0f)) {
- discard_fragment();
+ *(tint_symbol_8) = true;
+ return;
}
- float4 const x_34 = (*(tint_symbol_7)).vEyePosition;
+ float4 const x_34 = (*(tint_symbol_10)).vEyePosition;
float3 const x_38 = float3(0.0f, 0.0f, 0.0f);
viewDirectionW = normalize((float3(x_34[0], x_34[1], x_34[2]) - x_38));
baseColor = float4(1.0f, 1.0f, 1.0f, 1.0f);
- float4 const x_52 = (*(tint_symbol_8)).vDiffuseColor;
+ float4 const x_52 = (*(tint_symbol_11)).vDiffuseColor;
diffuseColor = float3(x_52[0], x_52[1], x_52[2]);
- float const x_60 = (*(tint_symbol_8)).vDiffuseColor[3];
+ float const x_60 = (*(tint_symbol_11)).vDiffuseColor[3];
alpha = x_60;
float3 const x_62 = float3(0.0f, 0.0f, 0.0f);
float3 const x_64 = float3(0.0f, 0.0f, 0.0f);
@@ -76,12 +78,12 @@
shadow = 1.0f;
refractionColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
reflectionColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
- float3 const x_94 = (*(tint_symbol_8)).vEmissiveColor;
+ float3 const x_94 = (*(tint_symbol_11)).vEmissiveColor;
emissiveColor = x_94;
float3 const x_96 = diffuseBase;
float3 const x_97 = diffuseColor;
float3 const x_99 = emissiveColor;
- float3 const x_103 = (*(tint_symbol_8)).vAmbientColor;
+ float3 const x_103 = (*(tint_symbol_11)).vAmbientColor;
float4 const x_108 = baseColor;
finalDiffuse = (clamp((((x_96 * x_97) + x_99) + x_103), float3(0.0f, 0.0f, 0.0f), float3(1.0f, 1.0f, 1.0f)) * float3(x_108[0], x_108[1], x_108[2]));
finalSpecular = float3(0.0f, 0.0f, 0.0f);
@@ -97,11 +99,11 @@
float3 const x_132 = fmax(float3(x_129[0], x_129[1], x_129[2]), float3(0.0f, 0.0f, 0.0f));
float4 const x_133 = color;
color = float4(x_132[0], x_132[1], x_132[2], x_133[3]);
- float const x_140 = (*(tint_symbol_9)).visibility;
+ float const x_140 = (*(tint_symbol_12)).visibility;
float const x_142 = color[3];
color[3] = (x_142 * x_140);
float4 const x_147 = color;
- *(tint_symbol_10) = x_147;
+ *(tint_symbol_13) = x_147;
return;
}
@@ -118,19 +120,33 @@
float4 glFragColor_1 [[color(0)]];
};
-main_out tint_symbol_inner(float fClipDistance3_param, float fClipDistance4_param, thread float* const tint_symbol_11, thread float* const tint_symbol_12, const constant Scene* const tint_symbol_13, const constant Material* const tint_symbol_14, const constant Mesh* const tint_symbol_15, thread float4* const tint_symbol_16) {
- *(tint_symbol_11) = fClipDistance3_param;
- *(tint_symbol_12) = fClipDistance4_param;
- main_1(tint_symbol_11, tint_symbol_12, tint_symbol_13, tint_symbol_14, tint_symbol_15, tint_symbol_16);
- main_out const tint_symbol_4 = {.glFragColor_1=*(tint_symbol_16)};
- return tint_symbol_4;
+main_out tint_symbol_inner(float fClipDistance3_param, float fClipDistance4_param, thread float* const tint_symbol_14, thread float* const tint_symbol_15, thread bool* const tint_symbol_16, const constant Scene* const tint_symbol_17, const constant Material* const tint_symbol_18, const constant Mesh* const tint_symbol_19, thread float4* const tint_symbol_20) {
+ *(tint_symbol_14) = fClipDistance3_param;
+ *(tint_symbol_15) = fClipDistance4_param;
+ main_1(tint_symbol_14, tint_symbol_16, tint_symbol_15, tint_symbol_17, tint_symbol_18, tint_symbol_19, tint_symbol_20);
+ if (*(tint_symbol_16)) {
+ main_out const tint_symbol_4 = {};
+ return tint_symbol_4;
+ }
+ main_out const tint_symbol_5 = {.glFragColor_1=*(tint_symbol_20)};
+ return tint_symbol_5;
}
-fragment tint_symbol_3 tint_symbol(const constant Scene* tint_symbol_19 [[buffer(0)]], const constant Material* tint_symbol_20 [[buffer(1)]], const constant Mesh* tint_symbol_21 [[buffer(2)]], tint_symbol_2 tint_symbol_1 [[stage_in]]) {
- thread float tint_symbol_17 = 0.0f;
- thread float tint_symbol_18 = 0.0f;
- thread float4 tint_symbol_22 = 0.0f;
- main_out const inner_result = tint_symbol_inner(tint_symbol_1.fClipDistance3_param, tint_symbol_1.fClipDistance4_param, &(tint_symbol_17), &(tint_symbol_18), tint_symbol_19, tint_symbol_20, tint_symbol_21, &(tint_symbol_22));
+void tint_discard_func() {
+ discard_fragment();
+}
+
+fragment tint_symbol_3 tint_symbol(const constant Scene* tint_symbol_24 [[buffer(0)]], const constant Material* tint_symbol_25 [[buffer(1)]], const constant Mesh* tint_symbol_26 [[buffer(2)]], tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ thread float tint_symbol_21 = 0.0f;
+ thread float tint_symbol_22 = 0.0f;
+ thread bool tint_symbol_23 = false;
+ thread float4 tint_symbol_27 = 0.0f;
+ main_out const inner_result = tint_symbol_inner(tint_symbol_1.fClipDistance3_param, tint_symbol_1.fClipDistance4_param, &(tint_symbol_21), &(tint_symbol_22), &(tint_symbol_23), tint_symbol_24, tint_symbol_25, tint_symbol_26, &(tint_symbol_27));
+ if (tint_symbol_23) {
+ tint_discard_func();
+ tint_symbol_3 const tint_symbol_6 = {};
+ return tint_symbol_6;
+ }
tint_symbol_3 wrapper_result = {};
wrapper_result.glFragColor_1 = inner_result.glFragColor_1;
return wrapper_result;
diff --git a/test/tint/bug/tint/1118.wgsl.expected.spvasm b/test/tint/bug/tint/1118.wgsl.expected.spvasm
index 390f103..3023204 100644
--- a/test/tint/bug/tint/1118.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/1118.wgsl.expected.spvasm
@@ -1,10 +1,10 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
-; Bound: 187
+; Bound: 198
; Schema: 0
OpCapability Shader
- %69 = OpExtInstImport "GLSL.std.450"
+ %73 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fClipDistance3_param_1 %fClipDistance4_param_1 %glFragColor_1_1
OpExecutionMode %main OriginUpperLeft
@@ -27,6 +27,7 @@
OpMemberName %Mesh 0 "visibility"
OpName %x_137 "x_137"
OpName %glFragColor "glFragColor"
+ OpName %tint_discard "tint_discard"
OpName %main_1 "main_1"
OpName %viewDirectionW "viewDirectionW"
OpName %baseColor "baseColor"
@@ -44,6 +45,7 @@
OpName %finalDiffuse "finalDiffuse"
OpName %finalSpecular "finalSpecular"
OpName %color "color"
+ OpName %tint_discard_func "tint_discard_func"
OpName %main_out "main_out"
OpMemberName %main_out 0 "glFragColor_1"
OpName %main_inner "main_inner"
@@ -97,199 +99,217 @@
%x_137 = OpVariable %_ptr_Uniform_Mesh Uniform
%_ptr_Private_v4float = OpTypePointer Private %v4float
%glFragColor = OpVariable %_ptr_Private_v4float Private %8
+ %bool = OpTypeBool
+ %false = OpConstantFalse %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discard = OpVariable %_ptr_Private_bool Private %false
%void = OpTypeVoid
- %25 = OpTypeFunction %void
+ %29 = OpTypeFunction %void
%_ptr_Function_v3float = OpTypePointer Function %v3float
- %31 = OpConstantNull %v3float
+ %35 = OpConstantNull %v3float
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Function_float = OpTypePointer Function %float
%v2float = OpTypeVector %float 2
%_ptr_Function_v2float = OpTypePointer Function %v2float
- %41 = OpConstantNull %v2float
+ %45 = OpConstantNull %v2float
%float_0 = OpConstant %float 0
- %bool = OpTypeBool
+ %true = OpConstantTrue %bool
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
- %67 = OpConstantComposite %v3float %float_0 %float_0 %float_0
+ %71 = OpConstantComposite %v3float %float_0 %float_0 %float_0
%float_1 = OpConstant %float 1
- %76 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+ %80 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
%uint_3 = OpConstant %uint 3
%_ptr_Uniform_float = OpTypePointer Uniform %float
- %92 = OpConstantComposite %v2float %float_0 %float_0
- %93 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
- %110 = OpConstantComposite %v3float %float_1 %float_1 %float_1
- %111 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
+ %96 = OpConstantComposite %v2float %float_0 %float_0
+ %97 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+ %114 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+ %115 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
%uint_1 = OpConstant %uint 1
%main_out = OpTypeStruct %v4float
- %172 = OpTypeFunction %main_out %float %float
- %main_1 = OpFunction %void None %25
- %28 = OpLabel
-%viewDirectionW = OpVariable %_ptr_Function_v3float Function %31
+ %178 = OpTypeFunction %main_out %float %float
+ %189 = OpConstantNull %main_out
+ %main_1 = OpFunction %void None %29
+ %32 = OpLabel
+%viewDirectionW = OpVariable %_ptr_Function_v3float Function %35
%baseColor = OpVariable %_ptr_Function_v4float Function %8
-%diffuseColor = OpVariable %_ptr_Function_v3float Function %31
+%diffuseColor = OpVariable %_ptr_Function_v3float Function %35
%alpha = OpVariable %_ptr_Function_float Function %11
- %normalW = OpVariable %_ptr_Function_v3float Function %31
- %uvOffset = OpVariable %_ptr_Function_v2float Function %41
-%baseAmbientColor = OpVariable %_ptr_Function_v3float Function %31
+ %normalW = OpVariable %_ptr_Function_v3float Function %35
+ %uvOffset = OpVariable %_ptr_Function_v2float Function %45
+%baseAmbientColor = OpVariable %_ptr_Function_v3float Function %35
%glossiness = OpVariable %_ptr_Function_float Function %11
-%diffuseBase = OpVariable %_ptr_Function_v3float Function %31
+%diffuseBase = OpVariable %_ptr_Function_v3float Function %35
%shadow = OpVariable %_ptr_Function_float Function %11
%refractionColor = OpVariable %_ptr_Function_v4float Function %8
%reflectionColor = OpVariable %_ptr_Function_v4float Function %8
-%emissiveColor = OpVariable %_ptr_Function_v3float Function %31
-%finalDiffuse = OpVariable %_ptr_Function_v3float Function %31
-%finalSpecular = OpVariable %_ptr_Function_v3float Function %31
+%emissiveColor = OpVariable %_ptr_Function_v3float Function %35
+%finalDiffuse = OpVariable %_ptr_Function_v3float Function %35
+%finalSpecular = OpVariable %_ptr_Function_v3float Function %35
%color = OpVariable %_ptr_Function_v4float Function %8
- %52 = OpLoad %float %fClipDistance3
- %54 = OpFOrdGreaterThan %bool %52 %float_0
- OpSelectionMerge %56 None
- OpBranchConditional %54 %57 %56
- %57 = OpLabel
- OpKill
- %56 = OpLabel
- %58 = OpLoad %float %fClipDistance4
- %59 = OpFOrdGreaterThan %bool %58 %float_0
- OpSelectionMerge %60 None
- OpBranchConditional %59 %61 %60
- %61 = OpLabel
- OpKill
+ %56 = OpLoad %float %fClipDistance3
+ %58 = OpFOrdGreaterThan %bool %56 %float_0
+ OpSelectionMerge %59 None
+ OpBranchConditional %58 %60 %59
%60 = OpLabel
- %65 = OpAccessChain %_ptr_Uniform_v4float %x_29 %uint_0
- %66 = OpLoad %v4float %65
- %70 = OpCompositeExtract %float %66 0
- %71 = OpCompositeExtract %float %66 1
- %72 = OpCompositeExtract %float %66 2
- %73 = OpCompositeConstruct %v3float %70 %71 %72
- %74 = OpFSub %v3float %73 %67
- %68 = OpExtInst %v3float %69 Normalize %74
- OpStore %viewDirectionW %68
- OpStore %baseColor %76
- %77 = OpAccessChain %_ptr_Uniform_v4float %x_49 %uint_0
- %78 = OpLoad %v4float %77
- %79 = OpCompositeExtract %float %78 0
- %80 = OpCompositeExtract %float %78 1
- %81 = OpCompositeExtract %float %78 2
- %82 = OpCompositeConstruct %v3float %79 %80 %81
- OpStore %diffuseColor %82
- %85 = OpAccessChain %_ptr_Uniform_float %x_49 %uint_0 %uint_3
- %86 = OpLoad %float %85
- OpStore %alpha %86
- %90 = OpDPdx %v3float %67
- %91 = OpDPdy %v3float %67
- %89 = OpExtInst %v3float %69 Cross %90 %91
- %88 = OpFNegate %v3float %89
- %87 = OpExtInst %v3float %69 Normalize %88
- OpStore %normalW %87
- OpStore %uvOffset %92
- %94 = OpLoad %v4float %baseColor
- %95 = OpCompositeExtract %float %94 0
- %96 = OpCompositeExtract %float %94 1
- %97 = OpCompositeExtract %float %94 2
- %98 = OpCompositeConstruct %v3float %95 %96 %97
- %99 = OpCompositeExtract %float %93 0
- %100 = OpCompositeExtract %float %93 1
- %101 = OpCompositeExtract %float %93 2
+ OpStore %tint_discard %true
+ OpReturn
+ %59 = OpLabel
+ %62 = OpLoad %float %fClipDistance4
+ %63 = OpFOrdGreaterThan %bool %62 %float_0
+ OpSelectionMerge %64 None
+ OpBranchConditional %63 %65 %64
+ %65 = OpLabel
+ OpStore %tint_discard %true
+ OpReturn
+ %64 = OpLabel
+ %69 = OpAccessChain %_ptr_Uniform_v4float %x_29 %uint_0
+ %70 = OpLoad %v4float %69
+ %74 = OpCompositeExtract %float %70 0
+ %75 = OpCompositeExtract %float %70 1
+ %76 = OpCompositeExtract %float %70 2
+ %77 = OpCompositeConstruct %v3float %74 %75 %76
+ %78 = OpFSub %v3float %77 %71
+ %72 = OpExtInst %v3float %73 Normalize %78
+ OpStore %viewDirectionW %72
+ OpStore %baseColor %80
+ %81 = OpAccessChain %_ptr_Uniform_v4float %x_49 %uint_0
+ %82 = OpLoad %v4float %81
+ %83 = OpCompositeExtract %float %82 0
+ %84 = OpCompositeExtract %float %82 1
+ %85 = OpCompositeExtract %float %82 2
+ %86 = OpCompositeConstruct %v3float %83 %84 %85
+ OpStore %diffuseColor %86
+ %89 = OpAccessChain %_ptr_Uniform_float %x_49 %uint_0 %uint_3
+ %90 = OpLoad %float %89
+ OpStore %alpha %90
+ %94 = OpDPdx %v3float %71
+ %95 = OpDPdy %v3float %71
+ %93 = OpExtInst %v3float %73 Cross %94 %95
+ %92 = OpFNegate %v3float %93
+ %91 = OpExtInst %v3float %73 Normalize %92
+ OpStore %normalW %91
+ OpStore %uvOffset %96
+ %98 = OpLoad %v4float %baseColor
+ %99 = OpCompositeExtract %float %98 0
+ %100 = OpCompositeExtract %float %98 1
+ %101 = OpCompositeExtract %float %98 2
%102 = OpCompositeConstruct %v3float %99 %100 %101
- %103 = OpFMul %v3float %98 %102
- %104 = OpLoad %v4float %baseColor
- %105 = OpCompositeExtract %float %103 0
- %106 = OpCompositeExtract %float %103 1
- %107 = OpCompositeExtract %float %103 2
- %108 = OpCompositeExtract %float %104 3
- %109 = OpCompositeConstruct %v4float %105 %106 %107 %108
- OpStore %baseColor %109
- OpStore %baseAmbientColor %110
+ %103 = OpCompositeExtract %float %97 0
+ %104 = OpCompositeExtract %float %97 1
+ %105 = OpCompositeExtract %float %97 2
+ %106 = OpCompositeConstruct %v3float %103 %104 %105
+ %107 = OpFMul %v3float %102 %106
+ %108 = OpLoad %v4float %baseColor
+ %109 = OpCompositeExtract %float %107 0
+ %110 = OpCompositeExtract %float %107 1
+ %111 = OpCompositeExtract %float %107 2
+ %112 = OpCompositeExtract %float %108 3
+ %113 = OpCompositeConstruct %v4float %109 %110 %111 %112
+ OpStore %baseColor %113
+ OpStore %baseAmbientColor %114
OpStore %glossiness %float_0
- OpStore %diffuseBase %67
+ OpStore %diffuseBase %71
OpStore %shadow %float_1
- OpStore %refractionColor %111
- OpStore %reflectionColor %111
- %113 = OpAccessChain %_ptr_Uniform_v3float %x_49 %uint_3
- %114 = OpLoad %v3float %113
- OpStore %emissiveColor %114
- %115 = OpLoad %v3float %diffuseBase
- %116 = OpLoad %v3float %diffuseColor
- %117 = OpLoad %v3float %emissiveColor
- %119 = OpAccessChain %_ptr_Uniform_v3float %x_49 %uint_1
- %120 = OpLoad %v3float %119
- %121 = OpLoad %v4float %baseColor
- %123 = OpFMul %v3float %115 %116
- %124 = OpFAdd %v3float %123 %117
- %125 = OpFAdd %v3float %124 %120
- %122 = OpExtInst %v3float %69 NClamp %125 %67 %110
- %126 = OpCompositeExtract %float %121 0
- %127 = OpCompositeExtract %float %121 1
- %128 = OpCompositeExtract %float %121 2
- %129 = OpCompositeConstruct %v3float %126 %127 %128
- %130 = OpFMul %v3float %122 %129
- OpStore %finalDiffuse %130
- OpStore %finalSpecular %67
- %131 = OpLoad %v3float %finalDiffuse
- %132 = OpLoad %v3float %baseAmbientColor
- %133 = OpLoad %v3float %finalSpecular
- %134 = OpLoad %v4float %reflectionColor
- %135 = OpLoad %v4float %refractionColor
- %136 = OpFMul %v3float %131 %132
- %137 = OpFAdd %v3float %136 %133
- %138 = OpCompositeExtract %float %134 0
- %139 = OpCompositeExtract %float %134 1
- %140 = OpCompositeExtract %float %134 2
- %141 = OpCompositeConstruct %v3float %138 %139 %140
- %142 = OpFAdd %v3float %137 %141
- %143 = OpCompositeExtract %float %135 0
- %144 = OpCompositeExtract %float %135 1
- %145 = OpCompositeExtract %float %135 2
- %146 = OpCompositeConstruct %v3float %143 %144 %145
- %147 = OpFAdd %v3float %142 %146
- %148 = OpLoad %float %alpha
- %149 = OpCompositeExtract %float %147 0
- %150 = OpCompositeExtract %float %147 1
- %151 = OpCompositeExtract %float %147 2
- %152 = OpCompositeConstruct %v4float %149 %150 %151 %148
- OpStore %color %152
- %153 = OpLoad %v4float %color
- %155 = OpCompositeExtract %float %153 0
- %156 = OpCompositeExtract %float %153 1
- %157 = OpCompositeExtract %float %153 2
- %158 = OpCompositeConstruct %v3float %155 %156 %157
- %154 = OpExtInst %v3float %69 NMax %158 %67
- %159 = OpLoad %v4float %color
- %160 = OpCompositeExtract %float %154 0
- %161 = OpCompositeExtract %float %154 1
- %162 = OpCompositeExtract %float %154 2
- %163 = OpCompositeExtract %float %159 3
- %164 = OpCompositeConstruct %v4float %160 %161 %162 %163
- OpStore %color %164
- %165 = OpAccessChain %_ptr_Uniform_float %x_137 %uint_0
- %166 = OpLoad %float %165
- %167 = OpAccessChain %_ptr_Function_float %color %uint_3
- %168 = OpLoad %float %167
- %169 = OpAccessChain %_ptr_Function_float %color %uint_3
- %170 = OpFMul %float %168 %166
- OpStore %169 %170
- %171 = OpLoad %v4float %color
- OpStore %glFragColor %171
+ OpStore %refractionColor %115
+ OpStore %reflectionColor %115
+ %117 = OpAccessChain %_ptr_Uniform_v3float %x_49 %uint_3
+ %118 = OpLoad %v3float %117
+ OpStore %emissiveColor %118
+ %119 = OpLoad %v3float %diffuseBase
+ %120 = OpLoad %v3float %diffuseColor
+ %121 = OpLoad %v3float %emissiveColor
+ %123 = OpAccessChain %_ptr_Uniform_v3float %x_49 %uint_1
+ %124 = OpLoad %v3float %123
+ %125 = OpLoad %v4float %baseColor
+ %127 = OpFMul %v3float %119 %120
+ %128 = OpFAdd %v3float %127 %121
+ %129 = OpFAdd %v3float %128 %124
+ %126 = OpExtInst %v3float %73 NClamp %129 %71 %114
+ %130 = OpCompositeExtract %float %125 0
+ %131 = OpCompositeExtract %float %125 1
+ %132 = OpCompositeExtract %float %125 2
+ %133 = OpCompositeConstruct %v3float %130 %131 %132
+ %134 = OpFMul %v3float %126 %133
+ OpStore %finalDiffuse %134
+ OpStore %finalSpecular %71
+ %135 = OpLoad %v3float %finalDiffuse
+ %136 = OpLoad %v3float %baseAmbientColor
+ %137 = OpLoad %v3float %finalSpecular
+ %138 = OpLoad %v4float %reflectionColor
+ %139 = OpLoad %v4float %refractionColor
+ %140 = OpFMul %v3float %135 %136
+ %141 = OpFAdd %v3float %140 %137
+ %142 = OpCompositeExtract %float %138 0
+ %143 = OpCompositeExtract %float %138 1
+ %144 = OpCompositeExtract %float %138 2
+ %145 = OpCompositeConstruct %v3float %142 %143 %144
+ %146 = OpFAdd %v3float %141 %145
+ %147 = OpCompositeExtract %float %139 0
+ %148 = OpCompositeExtract %float %139 1
+ %149 = OpCompositeExtract %float %139 2
+ %150 = OpCompositeConstruct %v3float %147 %148 %149
+ %151 = OpFAdd %v3float %146 %150
+ %152 = OpLoad %float %alpha
+ %153 = OpCompositeExtract %float %151 0
+ %154 = OpCompositeExtract %float %151 1
+ %155 = OpCompositeExtract %float %151 2
+ %156 = OpCompositeConstruct %v4float %153 %154 %155 %152
+ OpStore %color %156
+ %157 = OpLoad %v4float %color
+ %159 = OpCompositeExtract %float %157 0
+ %160 = OpCompositeExtract %float %157 1
+ %161 = OpCompositeExtract %float %157 2
+ %162 = OpCompositeConstruct %v3float %159 %160 %161
+ %158 = OpExtInst %v3float %73 NMax %162 %71
+ %163 = OpLoad %v4float %color
+ %164 = OpCompositeExtract %float %158 0
+ %165 = OpCompositeExtract %float %158 1
+ %166 = OpCompositeExtract %float %158 2
+ %167 = OpCompositeExtract %float %163 3
+ %168 = OpCompositeConstruct %v4float %164 %165 %166 %167
+ OpStore %color %168
+ %169 = OpAccessChain %_ptr_Uniform_float %x_137 %uint_0
+ %170 = OpLoad %float %169
+ %171 = OpAccessChain %_ptr_Function_float %color %uint_3
+ %172 = OpLoad %float %171
+ %173 = OpAccessChain %_ptr_Function_float %color %uint_3
+ %174 = OpFMul %float %172 %170
+ OpStore %173 %174
+ %175 = OpLoad %v4float %color
+ OpStore %glFragColor %175
OpReturn
OpFunctionEnd
- %main_inner = OpFunction %main_out None %172
+%tint_discard_func = OpFunction %void None %29
+ %177 = OpLabel
+ OpKill
+ OpFunctionEnd
+ %main_inner = OpFunction %main_out None %178
%fClipDistance3_param = OpFunctionParameter %float
%fClipDistance4_param = OpFunctionParameter %float
- %177 = OpLabel
+ %183 = OpLabel
OpStore %fClipDistance3 %fClipDistance3_param
OpStore %fClipDistance4 %fClipDistance4_param
- %178 = OpFunctionCall %void %main_1
- %179 = OpLoad %v4float %glFragColor
- %180 = OpCompositeConstruct %main_out %179
- OpReturnValue %180
+ %184 = OpFunctionCall %void %main_1
+ %185 = OpLoad %bool %tint_discard
+ OpSelectionMerge %186 None
+ OpBranchConditional %185 %187 %186
+ %187 = OpLabel
+ %188 = OpFunctionCall %void %tint_discard_func
+ OpReturnValue %189
+ %186 = OpLabel
+ %190 = OpLoad %v4float %glFragColor
+ %191 = OpCompositeConstruct %main_out %190
+ OpReturnValue %191
OpFunctionEnd
- %main = OpFunction %void None %25
- %182 = OpLabel
- %184 = OpLoad %float %fClipDistance3_param_1
- %185 = OpLoad %float %fClipDistance4_param_1
- %183 = OpFunctionCall %main_out %main_inner %184 %185
- %186 = OpCompositeExtract %v4float %183 0
- OpStore %glFragColor_1_1 %186
+ %main = OpFunction %void None %29
+ %193 = OpLabel
+ %195 = OpLoad %float %fClipDistance3_param_1
+ %196 = OpLoad %float %fClipDistance4_param_1
+ %194 = OpFunctionCall %main_out %main_inner %195 %196
+ %197 = OpCompositeExtract %v4float %194 0
+ OpStore %glFragColor_1_1 %197
OpReturn
OpFunctionEnd
diff --git a/test/tint/bug/tint/1369.wgsl.expected.glsl b/test/tint/bug/tint/1369.wgsl.expected.glsl
index 4d0b9b7..dbecc85 100644
--- a/test/tint/bug/tint/1369.wgsl.expected.glsl
+++ b/test/tint/bug/tint/1369.wgsl.expected.glsl
@@ -9,17 +9,30 @@
#version 310 es
precision mediump float;
+bool tint_discard = false;
bool call_discard() {
- discard;
+ tint_discard = true;
+ return false;
return true;
}
void f() {
bool v = call_discard();
+ if (tint_discard) {
+ return;
+ }
bool also_unreachable = false;
}
+void tint_discard_func() {
+ discard;
+}
+
void main() {
f();
+ if (tint_discard) {
+ tint_discard_func();
+ return;
+ }
return;
}
diff --git a/test/tint/bug/tint/1369.wgsl.expected.hlsl b/test/tint/bug/tint/1369.wgsl.expected.hlsl
index dff55b3..d0fffc5 100644
--- a/test/tint/bug/tint/1369.wgsl.expected.hlsl
+++ b/test/tint/bug/tint/1369.wgsl.expected.hlsl
@@ -6,17 +6,24 @@
var also_unreachable : bool;
^^^^^^^^^^^^^^^^
+static bool tint_discard = false;
+
bool call_discard() {
- if (true) {
- discard;
- return true;
- }
- bool unused;
- return unused;
+ tint_discard = true;
+ return false;
+ return true;
+}
+
+void tint_discard_func() {
+ discard;
}
void f() {
bool v = call_discard();
+ if (tint_discard) {
+ tint_discard_func();
+ return;
+ }
bool also_unreachable = false;
return;
}
diff --git a/test/tint/bug/tint/1369.wgsl.expected.msl b/test/tint/bug/tint/1369.wgsl.expected.msl
index 8d1a7d7..e5ce396 100644
--- a/test/tint/bug/tint/1369.wgsl.expected.msl
+++ b/test/tint/bug/tint/1369.wgsl.expected.msl
@@ -9,13 +9,23 @@
#include <metal_stdlib>
using namespace metal;
-bool call_discard() {
- discard_fragment();
+bool call_discard(thread bool* const tint_symbol) {
+ *(tint_symbol) = true;
+ return bool();
return true;
}
+void tint_discard_func() {
+ discard_fragment();
+}
+
fragment void f() {
- bool v = call_discard();
+ thread bool tint_symbol_1 = false;
+ bool v = call_discard(&(tint_symbol_1));
+ if (tint_symbol_1) {
+ tint_discard_func();
+ return;
+ }
bool also_unreachable = false;
return;
}
diff --git a/test/tint/bug/tint/1369.wgsl.expected.spvasm b/test/tint/bug/tint/1369.wgsl.expected.spvasm
index a78ae04..e3ece9c 100644
--- a/test/tint/bug/tint/1369.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/1369.wgsl.expected.spvasm
@@ -9,29 +9,47 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
-; Bound: 13
+; Bound: 23
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %f "f"
OpExecutionMode %f OriginUpperLeft
+ OpName %tint_discard "tint_discard"
OpName %call_discard "call_discard"
+ OpName %tint_discard_func "tint_discard_func"
OpName %f "f"
OpName %v "v"
%bool = OpTypeBool
- %1 = OpTypeFunction %bool
+ %false = OpConstantFalse %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discard = OpVariable %_ptr_Private_bool Private %false
+ %5 = OpTypeFunction %bool
+ %true = OpConstantTrue %bool
+ %9 = OpConstantNull %bool
%void = OpTypeVoid
- %5 = OpTypeFunction %void
+ %10 = OpTypeFunction %void
%_ptr_Function_bool = OpTypePointer Function %bool
- %12 = OpConstantNull %bool
-%call_discard = OpFunction %bool None %1
- %4 = OpLabel
+%call_discard = OpFunction %bool None %5
+ %7 = OpLabel
+ OpStore %tint_discard %true
+ OpReturnValue %9
+ OpFunctionEnd
+%tint_discard_func = OpFunction %void None %10
+ %13 = OpLabel
OpKill
OpFunctionEnd
- %f = OpFunction %void None %5
- %8 = OpLabel
- %v = OpVariable %_ptr_Function_bool Function %12
- %9 = OpFunctionCall %bool %call_discard
- OpStore %v %9
+ %f = OpFunction %void None %10
+ %15 = OpLabel
+ %v = OpVariable %_ptr_Function_bool Function %9
+ %16 = OpFunctionCall %bool %call_discard
+ OpStore %v %16
+ %19 = OpLoad %bool %tint_discard
+ OpSelectionMerge %20 None
+ OpBranchConditional %19 %21 %20
+ %21 = OpLabel
+ %22 = OpFunctionCall %void %tint_discard_func
+ OpReturn
+ %20 = OpLabel
OpReturn
OpFunctionEnd
diff --git a/test/tint/unittest/reader/spirv/SpvParserCFGTest_EmitBody_Kill_InsideLoop.spvasm.expected.hlsl b/test/tint/unittest/reader/spirv/SpvParserCFGTest_EmitBody_Kill_InsideLoop.spvasm.expected.hlsl
deleted file mode 100644
index cc96aff..0000000
--- a/test/tint/unittest/reader/spirv/SpvParserCFGTest_EmitBody_Kill_InsideLoop.spvasm.expected.hlsl
+++ /dev/null
@@ -1,17 +0,0 @@
-SKIP: FAILED
-
-warning: code is unreachable
-static uint var_1 = 0u;
-
-void main_1() {
- [loop] while (true) {
- discard;
- }
- discard;
-}
-
-void main() {
- main_1();
- return;
-}
-
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/call-function-with-discard/0-opt.spvasm.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/call-function-with-discard/0-opt.spvasm.expected.hlsl
deleted file mode 100644
index 1db4c8c..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/call-function-with-discard/0-opt.spvasm.expected.hlsl
+++ /dev/null
@@ -1,50 +0,0 @@
-SKIP: FAILED
-
-cbuffer cbuffer_x_6 : register(b0, space0) {
- uint4 x_6[1];
-};
-static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-void func_() {
- const float x_28 = asfloat(x_6[0].x);
- if ((1.0f > x_28)) {
- discard;
- }
- return;
-}
-
-void main_1() {
- x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
- [loop] while (true) {
- func_();
- if (false) {
- } else {
- break;
- }
- }
- x_GLF_color = float4(1.0f, 0.0f, 0.0f, 1.0f);
- return;
-}
-
-struct main_out {
- float4 x_GLF_color_1;
-};
-struct tint_symbol {
- float4 x_GLF_color_1 : SV_Target0;
-};
-
-main_out main_inner() {
- main_1();
- const main_out tint_symbol_2 = {x_GLF_color};
- return tint_symbol_2;
-}
-
-tint_symbol main() {
- const main_out inner_result = main_inner();
- tint_symbol wrapper_result = (tint_symbol)0;
- wrapper_result.x_GLF_color_1 = inner_result.x_GLF_color_1;
- return wrapper_result;
-}
-C:\src\tint\test\Shader@0x0000016102DC2B30(16,10-21): warning X3557: loop only executes for 0 iteration(s), consider removing [loop]
-C:\src\tint\test\Shader@0x0000016102DC2B30(8,15-18): internal error: invalid access of unbound variable
-
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/call-function-with-discard/0-opt.wgsl.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/call-function-with-discard/0-opt.wgsl.expected.hlsl
deleted file mode 100644
index a528cf5..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/call-function-with-discard/0-opt.wgsl.expected.hlsl
+++ /dev/null
@@ -1,50 +0,0 @@
-SKIP: FAILED
-
-cbuffer cbuffer_x_6 : register(b0, space0) {
- uint4 x_6[1];
-};
-static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-void func_() {
- const float x_28 = asfloat(x_6[0].x);
- if ((1.0f > x_28)) {
- discard;
- }
- return;
-}
-
-void main_1() {
- x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
- [loop] while (true) {
- func_();
- if (false) {
- } else {
- break;
- }
- }
- x_GLF_color = float4(1.0f, 0.0f, 0.0f, 1.0f);
- return;
-}
-
-struct main_out {
- float4 x_GLF_color_1;
-};
-struct tint_symbol {
- float4 x_GLF_color_1 : SV_Target0;
-};
-
-main_out main_inner() {
- main_1();
- const main_out tint_symbol_2 = {x_GLF_color};
- return tint_symbol_2;
-}
-
-tint_symbol main() {
- const main_out inner_result = main_inner();
- tint_symbol wrapper_result = (tint_symbol)0;
- wrapper_result.x_GLF_color_1 = inner_result.x_GLF_color_1;
- return wrapper_result;
-}
-C:\src\tint\test\Shader@0x0000026A3937ED10(16,10-21): warning X3557: loop only executes for 0 iteration(s), consider removing [loop]
-C:\src\tint\test\Shader@0x0000026A3937ED10(8,15-18): internal error: invalid access of unbound variable
-
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.spvasm.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.spvasm.expected.hlsl
deleted file mode 100755
index 1626926..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.spvasm.expected.hlsl
+++ /dev/null
Binary files differ
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.wgsl.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.wgsl.expected.hlsl
deleted file mode 100755
index 711e15f..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.wgsl.expected.hlsl
+++ /dev/null
Binary files differ
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/unreachable-discard-statement-in-if/0-opt.spvasm.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/unreachable-discard-statement-in-if/0-opt.spvasm.expected.hlsl
deleted file mode 100644
index 1f1e152..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/unreachable-discard-statement-in-if/0-opt.spvasm.expected.hlsl
+++ /dev/null
@@ -1,64 +0,0 @@
-SKIP: FAILED
-
-cbuffer cbuffer_x_7 : register(b0, space0) {
- uint4 x_7[1];
-};
-static float4 gl_FragCoord = float4(0.0f, 0.0f, 0.0f, 0.0f);
-static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-float3 computePoint_() {
- if (true) {
- const float x_48 = asfloat(x_7[0].x);
- const float x_50 = asfloat(x_7[0].y);
- if ((x_48 > x_50)) {
- discard;
- }
- return float3(0.0f, 0.0f, 0.0f);
- }
- float3 unused;
- return unused;
-}
-
-void main_1() {
- bool x_34 = false;
- [loop] while (true) {
- const float3 x_36 = computePoint_();
- const float x_41 = gl_FragCoord.x;
- if ((x_41 < 0.0f)) {
- x_34 = true;
- break;
- }
- const float3 x_45 = computePoint_();
- x_GLF_color = float4(1.0f, 0.0f, 0.0f, 1.0f);
- x_34 = true;
- break;
- }
- return;
-}
-
-struct main_out {
- float4 x_GLF_color_1;
-};
-struct tint_symbol_1 {
- float4 gl_FragCoord_param : SV_Position;
-};
-struct tint_symbol_2 {
- float4 x_GLF_color_1 : SV_Target0;
-};
-
-main_out main_inner(float4 gl_FragCoord_param) {
- gl_FragCoord = gl_FragCoord_param;
- main_1();
- const main_out tint_symbol_4 = {x_GLF_color};
- return tint_symbol_4;
-}
-
-tint_symbol_2 main(tint_symbol_1 tint_symbol) {
- const main_out inner_result = main_inner(tint_symbol.gl_FragCoord_param);
- tint_symbol_2 wrapper_result = (tint_symbol_2)0;
- wrapper_result.x_GLF_color_1 = inner_result.x_GLF_color_1;
- return wrapper_result;
-}
-C:\src\tint\test\Shader@0x0000014F8C58FE70(22,10-21): warning X3557: loop only executes for 0 iteration(s), consider removing [loop]
-C:\src\tint\test\Shader@0x0000014F8C58FE70(11,10-13): internal error: invalid access of unbound variable
-
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/unreachable-discard-statement-in-if/0-opt.wgsl.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/unreachable-discard-statement-in-if/0-opt.wgsl.expected.hlsl
deleted file mode 100644
index 1bbf048..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/unreachable-discard-statement-in-if/0-opt.wgsl.expected.hlsl
+++ /dev/null
@@ -1,64 +0,0 @@
-SKIP: FAILED
-
-cbuffer cbuffer_x_7 : register(b0, space0) {
- uint4 x_7[1];
-};
-static float4 gl_FragCoord = float4(0.0f, 0.0f, 0.0f, 0.0f);
-static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-float3 computePoint_() {
- if (true) {
- const float x_48 = asfloat(x_7[0].x);
- const float x_50 = asfloat(x_7[0].y);
- if ((x_48 > x_50)) {
- discard;
- }
- return float3(0.0f, 0.0f, 0.0f);
- }
- float3 unused;
- return unused;
-}
-
-void main_1() {
- bool x_34 = false;
- [loop] while (true) {
- const float3 x_36 = computePoint_();
- const float x_41 = gl_FragCoord.x;
- if ((x_41 < 0.0f)) {
- x_34 = true;
- break;
- }
- const float3 x_45 = computePoint_();
- x_GLF_color = float4(1.0f, 0.0f, 0.0f, 1.0f);
- x_34 = true;
- break;
- }
- return;
-}
-
-struct main_out {
- float4 x_GLF_color_1;
-};
-struct tint_symbol_1 {
- float4 gl_FragCoord_param : SV_Position;
-};
-struct tint_symbol_2 {
- float4 x_GLF_color_1 : SV_Target0;
-};
-
-main_out main_inner(float4 gl_FragCoord_param) {
- gl_FragCoord = gl_FragCoord_param;
- main_1();
- const main_out tint_symbol_4 = {x_GLF_color};
- return tint_symbol_4;
-}
-
-tint_symbol_2 main(tint_symbol_1 tint_symbol) {
- const main_out inner_result = main_inner(tint_symbol.gl_FragCoord_param);
- tint_symbol_2 wrapper_result = (tint_symbol_2)0;
- wrapper_result.x_GLF_color_1 = inner_result.x_GLF_color_1;
- return wrapper_result;
-}
-C:\src\tint\test\Shader@0x0000017E3AA920C0(22,10-21): warning X3557: loop only executes for 0 iteration(s), consider removing [loop]
-C:\src\tint\test\Shader@0x0000017E3AA920C0(11,10-13): internal error: invalid access of unbound variable
-