tint: Use "demote-to-helper" semantics for discard

Discard statements no longer affect the behavior or uniformity
analysis. Update the resolver, validator, and several tests to reflect
this.

Some E2E tests were removed as they had loops that are now considered
to be infinite.

Use the DemoteToHelper transform to emulate the correct semantics on
platforms where discard is (or may) terminate the invocation in a
manner that would affect derivative operations.

We no longer need the UnwindDiscardFunctions transform for HLSL, which
already implements the correct semantics. However, we still run the
DemoteToHelper transform for the HLSL backend due to issues with FXC's
handling of discard statements (see crbug.com/tint/1118).

Fixed: tint:1723
Change-Id: Ib49ff187919ae81c4af8675e1b66acd57e2ff7d2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/109003
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index b51e531..fbbfe5a 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -554,8 +554,6 @@
     "transform/transform.h",
     "transform/unshadow.cc",
     "transform/unshadow.h",
-    "transform/unwind_discard_functions.cc",
-    "transform/unwind_discard_functions.h",
     "transform/utils/get_insertion_point.cc",
     "transform/utils/get_insertion_point.h",
     "transform/utils/hoist_to_decl_before.cc",
@@ -1253,7 +1251,6 @@
       "transform/test_helper.h",
       "transform/transform_test.cc",
       "transform/unshadow_test.cc",
-      "transform/unwind_discard_functions_test.cc",
       "transform/utils/get_insertion_point_test.cc",
       "transform/utils/hoist_to_decl_before_test.cc",
       "transform/var_for_dynamic_index_test.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index a42d58e..21da5e8 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -479,8 +479,6 @@
   transform/transform.h
   transform/unshadow.cc
   transform/unshadow.h
-  transform/unwind_discard_functions.cc
-  transform/unwind_discard_functions.h
   transform/utils/get_insertion_point.cc
   transform/utils/get_insertion_point.h
   transform/utils/hoist_to_decl_before.cc
@@ -1213,7 +1211,6 @@
       transform/substitute_override_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_matrix_conversions_test.cc
       transform/vectorize_scalar_matrix_initializers_test.cc
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker.cc b/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker.cc
index 66bbaf7..d77a762 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker.cc
@@ -29,7 +29,7 @@
 namespace tint::fuzzers::ast_fuzzer {
 
 JumpTracker::JumpTracker(const Program& program) {
-    // Consider every AST node, looking for break, return and discard statements.
+    // Consider every AST node, looking for break and return statements.
     for (auto* node : program.ASTNodes().Objects()) {
         auto* stmt = node->As<ast::Statement>();
         if (stmt == nullptr) {
@@ -63,14 +63,12 @@
                 }
                 candidate_statements.insert(current);
             }
-        } else if (stmt->As<ast::ReturnStatement>() || stmt->As<ast::DiscardStatement>()) {
-            // Walk up the AST from the return or discard statement, recording that every node
-            // encountered along the way contains a return/discard.
-            auto& target_set = stmt->As<ast::ReturnStatement>() ? contains_return_
-                                                                : contains_intraprocedural_discard_;
+        } else if (stmt->As<ast::ReturnStatement>()) {
+            // Walk up the AST from the return statement, recording that every node encountered
+            // along the way contains a return.
             const ast::Statement* current = stmt;
             while (true) {
-                target_set.insert(current);
+                contains_return_.insert(current);
                 auto* parent = program.Sem().Get(current)->Parent();
                 if (parent == nullptr) {
                     break;
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker.h b/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker.h
index 614ceb5..ec40ee8 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker.h
@@ -22,7 +22,7 @@
 
 namespace tint::fuzzers::ast_fuzzer {
 
-/// This class computes information on which statements contain loop breaks, returns and discards.
+/// This class computes information on which statements contain loop breaks and returns.
 /// It could be extended to handle other jumps, such as switch breaks and loop continues, should
 /// such information prove useful.
 class JumpTracker {
@@ -47,20 +47,9 @@
         return contains_return_.count(&statement) > 0;
     }
 
-    /// Indicates whether a statement contains a discard statement.
-    /// @param statement - the statement of interest.
-    /// @return true if and only if the statement is, or contains, a discard statement. This is
-    ///    determined in an intraprocedural fashion: the answer will be "false" if no discard occurs
-    ///    inside the statement, even if the statement calls a function that may lead to a discard
-    ///    being performed.
-    bool ContainsIntraproceduralDiscard(const ast::Statement& statement) const {
-        return contains_intraprocedural_discard_.count(&statement) > 0;
-    }
-
   private:
     std::unordered_set<const ast::Statement*> contains_break_for_innermost_loop_;
     std::unordered_set<const ast::Statement*> contains_return_;
-    std::unordered_set<const ast::Statement*> contains_intraprocedural_discard_;
 };
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker_test.cc
index f83e639..2482fee 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker_test.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/jump_tracker_test.cc
@@ -200,93 +200,6 @@
     }
 }
 
-TEST(JumpTrackerTest, Discards) {
-    std::string content = R"(
-fn main() {
-  var x : u32;
-  for (var i : i32 = 0; i < 100; i++) {
-    if (i == 40) {
-      {
-        discard;
-      }
-    }
-    for (var j : i32 = 0; j < 10; j++) {
-      loop {
-        if (i > j) {
-          discard;
-        }
-        continuing {
-          i++;
-          j-=2;
-        }
-      }
-      switch (j) {
-        case 0: {
-          if (i == j) {
-            break;
-          }
-          i = i + 1;
-          continue;
-        }
-        default: {
-          discard;
-        }
-      }
-    }
-  }
-}
-  )";
-    Source::File file("test.wgsl", content);
-    auto program = reader::wgsl::Parse(&file);
-    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
-
-    JumpTracker jump_tracker(program);
-
-    const auto* function_body = program.AST().Functions()[0]->body;
-    const auto* outer_loop = function_body->statements[1]->As<ast::ForLoopStatement>();
-    const auto* outer_loop_body = outer_loop->body;
-    const auto* first_if = outer_loop_body->statements[0]->As<ast::IfStatement>();
-    const auto* first_if_body = first_if->body;
-    const auto* block_in_first_if = first_if_body->statements[0]->As<ast::BlockStatement>();
-    const auto* discard_in_first_if = block_in_first_if->statements[0]->As<ast::DiscardStatement>();
-    const auto* inner_for_loop = outer_loop_body->statements[1]->As<ast::ForLoopStatement>();
-    const auto* inner_for_loop_body = inner_for_loop->body;
-    const auto* innermost_loop = inner_for_loop_body->statements[0]->As<ast::LoopStatement>();
-    const auto* innermost_loop_body = innermost_loop->body;
-    const auto* innermost_loop_if = innermost_loop_body->statements[0]->As<ast::IfStatement>();
-    const auto* innermost_loop_if_body = innermost_loop_if->body;
-    const auto* discard_in_innermost_loop =
-        innermost_loop_if_body->statements[0]->As<ast::DiscardStatement>();
-    const auto* switch_statement = inner_for_loop_body->statements[1]->As<ast::SwitchStatement>();
-    const auto* default_statement = switch_statement->body[1];
-    const auto* default_statement_body = default_statement->body;
-    const auto* discard_in_default_statement =
-        default_statement_body->statements[0]->As<ast::DiscardStatement>();
-
-    std::unordered_set<const ast::Statement*> containing_discard = {
-        function_body,          outer_loop,
-        outer_loop_body,        first_if,
-        first_if_body,          block_in_first_if,
-        discard_in_first_if,    inner_for_loop,
-        inner_for_loop_body,    innermost_loop,
-        innermost_loop_body,    innermost_loop_if,
-        innermost_loop_if_body, discard_in_innermost_loop,
-        switch_statement,       default_statement,
-        default_statement_body, discard_in_default_statement};
-
-    for (auto* node : program.ASTNodes().Objects()) {
-        auto* stmt = node->As<ast::Statement>();
-        if (stmt == nullptr) {
-            continue;
-        }
-        if (containing_discard.count(stmt) > 0) {
-            ASSERT_TRUE(jump_tracker.ContainsIntraproceduralDiscard(*stmt));
-        } else {
-            ASSERT_FALSE(jump_tracker.ContainsIntraproceduralDiscard(*stmt));
-        }
-    }
-}
-
 TEST(JumpTrackerTest, WhileLoop) {
     std::string content = R"(
 fn main() {
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement.cc
index 1ec3ca4..89ab66b 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement.cc
@@ -135,10 +135,9 @@
         return false;
     }
 
-    if (jump_tracker.ContainsReturn(statement_node) ||
-        jump_tracker.ContainsIntraproceduralDiscard(statement_node)) {
-        // This is conservative. It would be possible to delete a return/discard statement as long
-        // as there is still a return/discard on every control flow path.
+    if (jump_tracker.ContainsReturn(statement_node)) {
+        // This is conservative. It would be possible to delete a return statement as long as there
+        // is still a return on every control flow path.
         return false;
     }
 
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc
index 275a19e..a2ab29c 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc
@@ -606,48 +606,6 @@
     CheckStatementDeletionNotAllowed(original, statement_finder);
 }
 
-TEST(DeleteStatementTest, DoNotRemoveDiscard) {
-    auto original = R"(
-fn main() {
-  discard;
-})";
-    auto statement_finder = [](const Program& program) -> const ast::Statement* {
-        return program.AST().Functions()[0]->body->statements[0]->As<ast::DiscardStatement>();
-    };
-    CheckStatementDeletionNotAllowed(original, statement_finder);
-}
-
-TEST(DeleteStatementTest, DoNotRemoveStatementContainingDiscard) {
-    auto original = R"(
-fn foo() -> i32 {
-  if (true) {
-    discard;
-  } else {
-    discard;
-  }
-})";
-    auto statement_finder = [](const Program& program) -> const ast::Statement* {
-        return program.AST().Functions()[0]->body->statements[0]->As<ast::IfStatement>();
-    };
-    CheckStatementDeletionNotAllowed(original, statement_finder);
-}
-
-TEST(DeleteStatementTest, DoNotRemoveLoopBody) {
-    auto original = R"(
-fn foo() {
-  discard;
-}
-fn main() {
-  loop {
-    foo();
-  }
-})";
-    auto statement_finder = [](const Program& program) -> const ast::Statement* {
-        return program.AST().Functions()[1]->body->statements[0]->As<ast::LoopStatement>()->body;
-    };
-    CheckStatementDeletionNotAllowed(original, statement_finder);
-}
-
 TEST(DeleteStatementTest, DoNotRemoveForLoopBody) {
     auto original = R"(
 fn main() {
diff --git a/src/tint/resolver/function_validation_test.cc b/src/tint/resolver/function_validation_test.cc
index 49d37a1..a4ff9d8 100644
--- a/src/tint/resolver/function_validation_test.cc
+++ b/src/tint/resolver/function_validation_test.cc
@@ -161,7 +161,7 @@
     EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
 }
 
-TEST_F(ResolverFunctionValidationTest, UnreachableCode_discard) {
+TEST_F(ResolverFunctionValidationTest, UnreachableCode_discard_nowarning) {
     // fn func() -> {
     //  var a : i32;
     //  discard;
@@ -175,38 +175,17 @@
     Func("func", utils::Empty, ty.void_(), utils::Vector{decl_a, discard, assign_a});
 
     ASSERT_TRUE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
     EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
     EXPECT_TRUE(Sem().Get(discard)->IsReachable());
-    EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
-}
-
-TEST_F(ResolverFunctionValidationTest, UnreachableCode_discard_InBlocks) {
-    // fn func() -> {
-    //  var a : i32;
-    //  {{{discard;}}}
-    //  a = 2i;
-    //}
-
-    auto* decl_a = Decl(Var("a", ty.i32()));
-    auto* discard = Discard();
-    auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
-
-    Func("func", utils::Empty, ty.void_(),
-         utils::Vector{decl_a, Block(Block(Block(discard))), assign_a});
-
-    ASSERT_TRUE(r()->Resolve());
-    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
-    EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
-    EXPECT_TRUE(Sem().Get(discard)->IsReachable());
-    EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
+    EXPECT_TRUE(Sem().Get(assign_a)->IsReachable());
 }
 
 TEST_F(ResolverFunctionValidationTest, DiscardCalledDirectlyFromVertexEntryPoint) {
-    // @vertex() fn func() -> @position(0) vec4<f32> { discard; }
+    // @vertex() fn func() -> @position(0) vec4<f32> { discard; return; }
     Func(Source{{1, 2}}, "func", utils::Empty, ty.vec4<f32>(),
          utils::Vector{
              Discard(Source{{12, 34}}),
+             Return(Construct(ty.vec4<f32>())),
          },
          utils::Vector{Stage(ast::PipelineStage::kVertex)},
          utils::Vector{Builtin(ast::BuiltinValue::kPosition)});
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index daec00a..d30d671 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -3295,10 +3295,8 @@
     auto* sem =
         builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
     return StatementScope(stmt, sem, [&] {
-        sem->Behaviors() = sem::Behavior::kDiscard;
         current_function_->SetDiscardStatement(sem);
-
-        return validator_.DiscardStatement(sem, current_statement_);
+        return true;
     });
 }
 
diff --git a/src/tint/resolver/resolver_behavior_test.cc b/src/tint/resolver/resolver_behavior_test.cc
index 150512a..01b7890 100644
--- a/src/tint/resolver/resolver_behavior_test.cc
+++ b/src/tint/resolver/resolver_behavior_test.cc
@@ -30,10 +30,11 @@
 class ResolverBehaviorTest : public ResolverTest {
   protected:
     void SetUp() override {
-        // Create a function called 'DiscardOrNext' which returns an i32, and has
-        // the behavior of {Discard, Return}, which when called, will have the
-        // behavior {Discard, Next}.
-        Func("DiscardOrNext", utils::Empty, ty.i32(),
+        // Create a function called 'Next' which returns an i32, and has the behavior of {Return},
+        // which when called, will have the behavior {Next}.
+        // It contains a discard statement, which should not affect the behavior analysis or any
+        // related validation.
+        Func("Next", utils::Empty, ty.i32(),
              utils::Vector{
                  If(true, Block(Discard())),
                  Return(1_i),
@@ -42,7 +43,7 @@
 };
 
 TEST_F(ResolverBehaviorTest, ExprBinaryOp_LHS) {
-    auto* stmt = Decl(Var("lhs", ty.i32(), Add(Call("DiscardOrNext"), 1_i)));
+    auto* stmt = Decl(Var("lhs", ty.i32(), Add(Call("Next"), 1_i)));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -50,11 +51,11 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, ExprBinaryOp_RHS) {
-    auto* stmt = Decl(Var("lhs", ty.i32(), Add(1_i, Call("DiscardOrNext"))));
+    auto* stmt = Decl(Var("lhs", ty.i32(), Add(1_i, Call("Next"))));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -62,11 +63,11 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, ExprBitcastOp) {
-    auto* stmt = Decl(Var("lhs", ty.u32(), Bitcast<u32>(Call("DiscardOrNext"))));
+    auto* stmt = Decl(Var("lhs", ty.u32(), Bitcast<u32>(Call("Next"))));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -74,7 +75,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, ExprIndex_Arr) {
@@ -92,11 +93,11 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, ExprIndex_Idx) {
-    auto* stmt = Decl(Var("lhs", ty.i32(), IndexAccessor("arr", Call("DiscardOrNext"))));
+    auto* stmt = Decl(Var("lhs", ty.i32(), IndexAccessor("arr", Call("Next"))));
 
     Func("F", utils::Empty, ty.void_(),
          utils::Vector{
@@ -108,13 +109,12 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, ExprUnaryOp) {
-    auto* stmt =
-        Decl(Var("lhs", ty.i32(),
-                 create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Call("DiscardOrNext"))));
+    auto* stmt = Decl(Var("lhs", ty.i32(),
+                          create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Call("Next"))));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -122,7 +122,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtAssign) {
@@ -138,7 +138,7 @@
 }
 
 TEST_F(ResolverBehaviorTest, StmtAssign_LHSDiscardOrNext) {
-    auto* stmt = Assign(IndexAccessor("lhs", Call("DiscardOrNext")), 1_i);
+    auto* stmt = Assign(IndexAccessor("lhs", Call("Next")), 1_i);
 
     Func("F", utils::Empty, ty.void_(),
          utils::Vector{
@@ -150,11 +150,11 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtAssign_RHSDiscardOrNext) {
-    auto* stmt = Assign("lhs", Call("DiscardOrNext"));
+    auto* stmt = Assign("lhs", Call("Next"));
 
     Func("F", utils::Empty, ty.void_(),
          utils::Vector{
@@ -166,7 +166,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtBlockEmpty) {
@@ -180,7 +180,7 @@
 }
 
 TEST_F(ResolverBehaviorTest, StmtBlockSingleStmt) {
-    auto* stmt = Block(Discard());
+    auto* stmt = Block(Return());
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -188,7 +188,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kReturn);
 }
 
 TEST_F(ResolverBehaviorTest, StmtCallReturn) {
@@ -212,12 +212,11 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtCallFuncMayDiscard) {
-    auto* stmt =
-        For(Decl(Var("v", ty.i32(), Call("DiscardOrNext"))), nullptr, nullptr, Block(Break()));
+    auto* stmt = For(Decl(Var("v", ty.i32(), Call("Next"))), nullptr, nullptr, Block(Break()));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -225,7 +224,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtBreak) {
@@ -258,7 +257,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopEmpty_NoExit) {
@@ -288,7 +287,7 @@
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopDiscard) {
-    auto* stmt = For(nullptr, nullptr, nullptr, Block(Discard()));
+    auto* stmt = For(nullptr, nullptr, nullptr, Block(Discard(), Break()));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -296,7 +295,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopReturn) {
@@ -310,8 +309,7 @@
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopBreak_InitCallFuncMayDiscard) {
-    auto* stmt =
-        For(Decl(Var("v", ty.i32(), Call("DiscardOrNext"))), nullptr, nullptr, Block(Break()));
+    auto* stmt = For(Decl(Var("v", ty.i32(), Call("Next"))), nullptr, nullptr, Block(Break()));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -319,11 +317,11 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopEmpty_InitCallFuncMayDiscard) {
-    auto* stmt = For(Decl(Var("v", ty.i32(), Call("DiscardOrNext"))), nullptr, nullptr, Block());
+    auto* stmt = For(Decl(Var("v", ty.i32(), Call("Next"))), nullptr, nullptr, Block(Break()));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -331,7 +329,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopEmpty_CondTrue) {
@@ -345,7 +343,7 @@
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopEmpty_CondCallFuncMayDiscard) {
-    auto* stmt = For(nullptr, Equal(Call("DiscardOrNext"), 1_i), nullptr, Block());
+    auto* stmt = For(nullptr, Equal(Call("Next"), 1_i), nullptr, Block());
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -353,7 +351,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtWhileBreak) {
@@ -375,7 +373,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtWhileReturn) {
@@ -399,7 +397,7 @@
 }
 
 TEST_F(ResolverBehaviorTest, StmtWhileEmpty_CondCallFuncMayDiscard) {
-    auto* stmt = While(Equal(Call("DiscardOrNext"), 1_i), Block());
+    auto* stmt = While(Equal(Call("Next"), 1_i), Block());
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -407,7 +405,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtIfTrue_ThenEmptyBlock) {
@@ -429,7 +427,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtIfTrue_ThenEmptyBlock_ElseDiscard) {
@@ -441,7 +439,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtIfTrue_ThenDiscard_ElseDiscard) {
@@ -453,11 +451,11 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtIfCallFuncMayDiscard_ThenEmptyBlock) {
-    auto* stmt = If(Equal(Call("DiscardOrNext"), 1_i), Block());
+    auto* stmt = If(Equal(Call("Next"), 1_i), Block());
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -465,12 +463,12 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtIfTrue_ThenEmptyBlock_ElseCallFuncMayDiscard) {
     auto* stmt = If(true, Block(),  //
-                    Else(If(Equal(Call("DiscardOrNext"), 1_i), Block())));
+                    Else(If(Equal(Call("Next"), 1_i), Block())));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -478,7 +476,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtLetDecl) {
@@ -492,7 +490,7 @@
 }
 
 TEST_F(ResolverBehaviorTest, StmtLetDecl_RHSDiscardOrNext) {
-    auto* stmt = Decl(Let("lhs", ty.i32(), Call("DiscardOrNext")));
+    auto* stmt = Decl(Let("lhs", ty.i32(), Call("Next")));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -500,7 +498,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtLoopEmpty_NoExit) {
@@ -530,7 +528,7 @@
 }
 
 TEST_F(ResolverBehaviorTest, StmtLoopDiscard) {
-    auto* stmt = Loop(Block(Discard()));
+    auto* stmt = Loop(Block(Discard(), Break()));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -538,7 +536,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtLoopReturn) {
@@ -590,14 +588,14 @@
 }
 
 TEST_F(ResolverBehaviorTest, StmtReturn_DiscardOrNext) {
-    auto* stmt = Return(Call("DiscardOrNext"));
+    auto* stmt = Return(Call("Next"));
 
     Func("F", utils::Empty, ty.i32(), utils::Vector{stmt});
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kReturn, sem::Behavior::kDiscard));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kReturn));
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondTrue_DefaultEmpty) {
@@ -629,7 +627,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_DefaultReturn) {
@@ -661,7 +659,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext, sem::Behavior::kDiscard));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_Case0Empty_DefaultReturn) {
@@ -683,7 +681,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_Case0Discard_DefaultDiscard) {
@@ -696,7 +694,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_Case0Discard_DefaultReturn) {
@@ -709,7 +707,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kReturn));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kReturn, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_Case0Discard_Case1Return_DefaultEmpty) {
@@ -724,12 +722,11 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext,
-                                               sem::Behavior::kReturn));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext, sem::Behavior::kReturn));
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondCallFuncMayDiscard_DefaultEmpty) {
-    auto* stmt = Switch(Call("DiscardOrNext"), DefaultCase(Block()));
+    auto* stmt = Switch(Call("Next"), DefaultCase(Block()));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -737,7 +734,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtVarDecl) {
@@ -751,7 +748,7 @@
 }
 
 TEST_F(ResolverBehaviorTest, StmtVarDecl_RHSDiscardOrNext) {
-    auto* stmt = Decl(Var("lhs", ty.i32(), Call("DiscardOrNext")));
+    auto* stmt = Decl(Var("lhs", ty.i32(), Call("Next")));
 
     Func("F", utils::Empty, ty.void_(), utils::Vector{stmt},
          utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -759,7 +756,7 @@
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
     auto* sem = Sem().Get(stmt);
-    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 }  // namespace
diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc
index fbaeff9..c7fd1f6 100644
--- a/src/tint/resolver/uniformity_test.cc
+++ b/src/tint/resolver/uniformity_test.cc
@@ -736,7 +736,6 @@
     kBreak,
     kContinue,
     kReturn,
-    kDiscard,
 };
 enum Condition {
     kNone,
@@ -754,8 +753,6 @@
             return "continue";
         case kReturn:
             return "return";
-        case kDiscard:
-            return "discard";
     }
     return "";
 }
@@ -790,7 +787,7 @@
 
 INSTANTIATE_TEST_SUITE_P(UniformityAnalysisTest,
                          LoopTest,
-                         ::testing::Combine(::testing::Range<int>(0, kDiscard + 1),
+                         ::testing::Combine(::testing::Range<int>(0, kReturn + 1),
                                             ::testing::Range<int>(0, kNonUniform + 1)),
                          [](const ::testing::TestParamInfo<LoopTestParams>& p) {
                              ControlFlowInterrupt interrupt =
@@ -1025,7 +1022,7 @@
 
 INSTANTIATE_TEST_SUITE_P(UniformityAnalysisTest,
                          LoopDeadCodeTest,
-                         ::testing::Range<int>(0, kDiscard + 1),
+                         ::testing::Range<int>(0, kReturn + 1),
                          [](const ::testing::TestParamInfo<LoopDeadCodeTest::ParamType>& p) {
                              return ToStr(static_cast<ControlFlowInterrupt>(p.param));
                          });
@@ -2890,36 +2887,6 @@
 )");
 }
 
-TEST_F(UniformityAnalysisTest, IfElse_NonUniformDiscard_NoReconverge) {
-    // If statements should not reconverge after non-uniform discards.
-    std::string src = R"(
-@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
-
-fn foo() {
-  if (non_uniform == 42) {
-    discard;
-  } else {
-  }
-  workgroupBarrier();
-}
-)";
-
-    RunTest(src, false);
-    EXPECT_EQ(error_,
-              R"(test:9:3 warning: 'workgroupBarrier' must only be called from uniform control flow
-  workgroupBarrier();
-  ^^^^^^^^^^^^^^^^
-
-test:5:3 note: control flow depends on non-uniform value
-  if (non_uniform == 42) {
-  ^^
-
-test:5:7 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
-  if (non_uniform == 42) {
-      ^^^^^^^^^^^
-)");
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 /// Switch statement tests.
 ////////////////////////////////////////////////////////////////////////////////
@@ -6749,6 +6716,22 @@
 /// Miscellaneous statement and expression tests.
 ////////////////////////////////////////////////////////////////////////////////
 
+TEST_F(UniformityAnalysisTest, NonUniformDiscard) {
+    // Non-uniform discard statements should not cause uniformity issues.
+    std::string src = R"(
+@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
+
+fn foo() {
+  if (non_uniform == 42) {
+    discard;
+  }
+  _ = dpdx(1.0);
+}
+)";
+
+    RunTest(src, true);
+}
+
 TEST_F(UniformityAnalysisTest, FunctionReconvergesOnExit) {
     // Call a function that has returns during non-uniform control flow, and test that the analysis
     // reconverges when returning to the caller.
@@ -6775,29 +6758,6 @@
     RunTest(src, true);
 }
 
-TEST_F(UniformityAnalysisTest, FunctionRequiresUniformFlowAndCausesNonUniformFlow) {
-    // Test that a function that requires uniform flow and then causes non-uniform flow can be
-    // called without error.
-    std::string src = R"(
-@group(0) @binding(0) var<storage, read_write> non_uniform_global : i32;
-
-fn foo() {
-  _ = dpdx(0.5);
-
-  if (non_uniform_global == 0) {
-    discard;
-  }
-}
-
-@fragment
-fn main() {
-  foo();
-}
-)";
-
-    RunTest(src, true);
-}
-
 TEST_F(UniformityAnalysisTest, TypeInitializer) {
     std::string src = R"(
 @group(0) @binding(0) var<storage, read_write> non_uniform_global : i32;
@@ -7031,22 +6991,6 @@
     RunTest(src, true);
 }
 
-TEST_F(UniformityAnalysisTest, DeadCode_AfterDiscard) {
-    // Dead code after a discard statement shouldn't cause uniformity errors.
-    std::string src = R"(
-@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
-
-fn foo() {
-  discard;
-  if (non_uniform == 42) {
-    workgroupBarrier();
-  }
-}
-)";
-
-    RunTest(src, true);
-}
-
 TEST_F(UniformityAnalysisTest, ArrayLength) {
     std::string src = R"(
 @group(0) @binding(0) var<storage, read_write> arr : array<f32>;
diff --git a/src/tint/resolver/validation_test.cc b/src/tint/resolver/validation_test.cc
index 34ddd90..c3893af 100644
--- a/src/tint/resolver/validation_test.cc
+++ b/src/tint/resolver/validation_test.cc
@@ -766,69 +766,17 @@
     // loop  {
     //   continuing {
     //     discard;
+    //     breakif true;
     //   }
     // }
 
-    WrapInFunction(Loop(  // loop
-        Block(),          //   loop block
-        Block(            //   loop continuing block
-            Discard(Source{{12, 34}}))));
+    Func("my_func", utils::Empty, ty.void_(),
+         utils::Vector{Loop(  // loop
+             Block(),         //   loop block
+             Block(           //   loop continuing block
+                 Discard(Source{{12, 34}}), BreakIf(true)))});
 
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              R"(12:34 error: continuing blocks must not contain a discard statement)");
-}
-
-TEST_F(ResolverTest, Stmt_Loop_DiscardInContinuing_Indirect) {
-    // loop {
-    //   if (false) { break; }
-    //   continuing {
-    //     loop { discard; }
-    //   }
-    // }
-
-    WrapInFunction(Loop(                   // outer loop
-        Block(If(false, Block(Break()))),  //   outer loop block
-        Block(Source{{56, 78}},            //   outer loop continuing block
-              Loop(                        //     inner loop
-                  Block(                   //       inner loop block
-                      Discard(Source{{12, 34}}))))));
-
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              R"(12:34 error: continuing blocks must not contain a discard statement
-56:78 note: see continuing block here)");
-}
-
-TEST_F(ResolverTest, Stmt_Loop_DiscardInContinuing_Indirect_ViaCall) {
-    // fn MayDiscard() { if (true) { discard; } }
-    // fn F() { MayDiscard(); }
-    // loop {
-    //   continuing {
-    //     loop { F(); }
-    //   }
-    // }
-
-    Func("MayDiscard", utils::Empty, ty.void_(),
-         utils::Vector{
-             If(true, Block(Discard())),
-         });
-    Func("SomeFunc", utils::Empty, ty.void_(),
-         utils::Vector{
-             CallStmt(Call("MayDiscard")),
-         });
-
-    WrapInFunction(Loop(         // outer loop
-        Block(),                 //   outer loop block
-        Block(Source{{56, 78}},  //   outer loop continuing block
-              Loop(              //     inner loop
-                  Block(         //       inner loop block
-                      CallStmt(Call(Source{{12, 34}}, "SomeFunc")))))));
-
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot call a function that may discard inside a continuing block
-56:78 note: see continuing block here)");
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTest, Stmt_Loop_ContinueInContinuing_Direct) {
@@ -973,55 +921,11 @@
     //   break;
     // }
 
-    WrapInFunction(For(nullptr, nullptr, Discard(Source{{12, 34}}),  //
-                       Block(Break())));
+    Func("my_func", utils::Empty, ty.void_(),
+         utils::Vector{For(nullptr, nullptr, Discard(Source{{12, 34}}),  //
+                           Block(Break()))});
 
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              R"(12:34 error: continuing blocks must not contain a discard statement)");
-}
-
-TEST_F(ResolverTest, Stmt_ForLoop_DiscardInContinuing_Indirect) {
-    // for(;; loop { discard }) {
-    //   break;
-    // }
-
-    WrapInFunction(For(nullptr, nullptr,
-                       Loop(Source{{56, 78}},                   //
-                            Block(Discard(Source{{12, 34}}))),  //
-                       Block(Break())));
-
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              R"(12:34 error: continuing blocks must not contain a discard statement
-56:78 note: see continuing block here)");
-}
-
-TEST_F(ResolverTest, Stmt_ForLoop_DiscardInContinuing_Indirect_ViaCall) {
-    // fn MayDiscard() { if (true) { discard; } }
-    // fn F() { MayDiscard(); }
-    // for(;; loop { F() }) {
-    //   break;
-    // }
-
-    Func("MayDiscard", utils::Empty, ty.void_(),
-         utils::Vector{
-             If(true, Block(Discard())),
-         });
-    Func("F", utils::Empty, ty.void_(),
-         utils::Vector{
-             CallStmt(Call("MayDiscard")),
-         });
-
-    WrapInFunction(For(nullptr, nullptr,
-                       Loop(Source{{56, 78}},                               //
-                            Block(CallStmt(Call(Source{{12, 34}}, "F")))),  //
-                       Block(Break())));
-
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              R"(12:34 error: cannot call a function that may discard inside a continuing block
-56:78 note: see continuing block here)");
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTest, Stmt_ForLoop_ContinueInContinuing_Direct) {
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
index f285b5f..5b38e68 100644
--- a/src/tint/resolver/validator.cc
+++ b/src/tint/resolver/validator.cc
@@ -1076,12 +1076,8 @@
     }
 
     // https://www.w3.org/TR/WGSL/#behaviors-rules
-    // a function behavior is always one of {}, {Next}, {Discard}, or
-    // {Next, Discard}.
-    if (func->Behaviors() != sem::Behaviors{} &&  // NOLINT: bad warning
-        func->Behaviors() != sem::Behavior::kNext && func->Behaviors() != sem::Behavior::kDiscard &&
-        func->Behaviors() != sem::Behaviors{sem::Behavior::kNext,  //
-                                            sem::Behavior::kDiscard}) {
+    // a function behavior is always one of {}, or {Next}.
+    if (func->Behaviors() != sem::Behaviors{} && func->Behaviors() != sem::Behavior::kNext) {
         auto name = symbols_.NameFor(decl->symbol);
         TINT_ICE(Resolver, diagnostics_)
             << "function '" << name << "' behaviors are: " << func->Behaviors();
@@ -1544,19 +1540,6 @@
     return true;
 }
 
-bool Validator::DiscardStatement(const sem::Statement* stmt,
-                                 sem::Statement* current_statement) const {
-    if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ false, current_statement)) {
-        AddError("continuing blocks must not contain a discard statement",
-                 stmt->Declaration()->source);
-        if (continuing != stmt->Declaration() && continuing != stmt->Parent()->Declaration()) {
-            AddNote("see continuing block here", continuing->source);
-        }
-        return false;
-    }
-    return true;
-}
-
 bool Validator::FallthroughStatement(const sem::Statement* stmt) const {
     if (auto* block = As<sem::BlockStatement>(stmt->Parent())) {
         if (auto* c = As<sem::CaseStatement>(block->Parent())) {
@@ -1843,18 +1826,6 @@
         }
     }
 
-    if (call->Behaviors().Contains(sem::Behavior::kDiscard)) {
-        if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ false, current_statement)) {
-            AddError("cannot call a function that may discard inside a continuing block",
-                     call->Declaration()->source);
-            if (continuing != call->Stmt()->Declaration() &&
-                continuing != call->Stmt()->Parent()->Declaration()) {
-                AddNote("see continuing block here", continuing->source);
-            }
-            return false;
-        }
-    }
-
     return true;
 }
 
diff --git a/src/tint/resolver/validator.h b/src/tint/resolver/validator.h
index efc3842..082147b 100644
--- a/src/tint/resolver/validator.h
+++ b/src/tint/resolver/validator.h
@@ -199,12 +199,6 @@
     /// @returns true on success, false otherwise
     bool Call(const sem::Call* call, sem::Statement* current_statement) const;
 
-    /// Validates a discard statement
-    /// @param stmt the statement to validate
-    /// @param current_statement the current statement being resolved
-    /// @returns true on success, false otherwise
-    bool DiscardStatement(const sem::Statement* stmt, sem::Statement* current_statement) const;
-
     /// Validates an entry point
     /// @param func the entry point function to validate
     /// @param stage the pipeline stage for the entry point
diff --git a/src/tint/sem/behavior.cc b/src/tint/sem/behavior.cc
index 617794f..4746104 100644
--- a/src/tint/sem/behavior.cc
+++ b/src/tint/sem/behavior.cc
@@ -20,8 +20,6 @@
     switch (behavior) {
         case Behavior::kReturn:
             return out << "Return";
-        case Behavior::kDiscard:
-            return out << "Discard";
         case Behavior::kBreak:
             return out << "Break";
         case Behavior::kContinue:
diff --git a/src/tint/sem/behavior.h b/src/tint/sem/behavior.h
index 4acb8d5..2557252 100644
--- a/src/tint/sem/behavior.h
+++ b/src/tint/sem/behavior.h
@@ -23,7 +23,6 @@
 /// @see https://www.w3.org/TR/WGSL/#behaviors
 enum class Behavior {
     kReturn,
-    kDiscard,
     kBreak,
     kContinue,
     kFallthrough,
diff --git a/src/tint/transform/demote_to_helper.h b/src/tint/transform/demote_to_helper.h
index 8968e78..ba87feb 100644
--- a/src/tint/transform/demote_to_helper.h
+++ b/src/tint/transform/demote_to_helper.h
@@ -25,6 +25,10 @@
 /// program to ensure that discarding the fragment does not affect uniformity with respect to
 /// derivative operations. We do this by setting a global flag and masking all writes to storage
 /// buffers and textures.
+///
+/// @note Depends on the following transforms to have been run first:
+/// * PromoteSideEffectsToDecl
+/// * ExpandCompoundAssignment
 class DemoteToHelper final : public Castable<DemoteToHelper, Transform> {
   public:
     /// Constructor
diff --git a/src/tint/transform/for_loop_to_loop_test.cc b/src/tint/transform/for_loop_to_loop_test.cc
index 172e1fc..fa34f56 100644
--- a/src/tint/transform/for_loop_to_loop_test.cc
+++ b/src/tint/transform/for_loop_to_loop_test.cc
@@ -76,7 +76,7 @@
     auto* src = R"(
 fn f() {
   for (;;) {
-    discard;
+    return;
   }
 }
 )";
@@ -84,7 +84,7 @@
     auto* expect = R"(
 fn f() {
   loop {
-    discard;
+    return;
   }
 }
 )";
diff --git a/src/tint/transform/remove_unreachable_statements_test.cc b/src/tint/transform/remove_unreachable_statements_test.cc
index 4b0a265..3e8c2b6 100644
--- a/src/tint/transform/remove_unreachable_statements_test.cc
+++ b/src/tint/transform/remove_unreachable_statements_test.cc
@@ -113,187 +113,23 @@
     EXPECT_EQ(expect, str(got));
 }
 
+// Discard has "demote-to-helper" semantics, and so code following a discard statement is not
+// considered unreachable.
 TEST_F(RemoveUnreachableStatementsTest, Discard) {
     auto* src = R"(
 fn f() {
   discard;
-  var remove_me = 1;
-  if (true) {
-    var remove_me_too = 1;
-  }
-}
-)";
-
-    auto* expect = R"(
-fn f() {
-  discard;
-}
-)";
-
-    auto got = Run<RemoveUnreachableStatements>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RemoveUnreachableStatementsTest, NestedDiscard) {
-    auto* src = R"(
-fn f() {
-  {
-    {
-      discard;
-    }
-  }
-  var remove_me = 1;
-  if (true) {
-    var remove_me_too = 1;
-  }
-}
-)";
-
-    auto* expect = R"(
-fn f() {
-  {
-    {
-      discard;
-    }
-  }
-}
-)";
-
-    auto got = Run<RemoveUnreachableStatements>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RemoveUnreachableStatementsTest, CallToFuncWithDiscard) {
-    auto* src = R"(
-fn DISCARD() {
-  discard;
-}
-
-fn f() {
-  DISCARD();
-  var remove_me = 1;
-  if (true) {
-    var remove_me_too = 1;
-  }
-}
-)";
-
-    auto* expect = R"(
-fn DISCARD() {
-  discard;
-}
-
-fn f() {
-  DISCARD();
-}
-)";
-
-    auto got = Run<RemoveUnreachableStatements>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RemoveUnreachableStatementsTest, CallToFuncWithIfDiscard) {
-    auto* src = R"(
-fn DISCARD() {
-  if (true) {
-    discard;
-  }
-}
-
-fn f() {
-  DISCARD();
   var preserve_me = 1;
-  if (true) {
-    var preserve_me_too = 1;
-  }
-}
-)";
-
-    auto* expect = src;
-
-    auto got = Run<RemoveUnreachableStatements>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RemoveUnreachableStatementsTest, IfDiscardElseDiscard) {
-    auto* src = R"(
-fn f() {
-  if (true) {
-    discard;
-  } else {
-    discard;
-  }
-  var remove_me = 1;
-  if (true) {
-    var remove_me_too = 1;
-  }
 }
 )";
 
     auto* expect = R"(
 fn f() {
-  if (true) {
-    discard;
-  } else {
-    discard;
-  }
-}
-)";
-
-    auto got = Run<RemoveUnreachableStatements>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RemoveUnreachableStatementsTest, IfDiscardElseReturn) {
-    auto* src = R"(
-fn f() {
-  if (true) {
-    discard;
-  } else {
-    return;
-  }
-  var remove_me = 1;
-  if (true) {
-    var remove_me_too = 1;
-  }
-}
-)";
-
-    auto* expect = R"(
-fn f() {
-  if (true) {
-    discard;
-  } else {
-    return;
-  }
-}
-)";
-
-    auto got = Run<RemoveUnreachableStatements>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RemoveUnreachableStatementsTest, IfDiscard) {
-    auto* src = R"(
-fn f() {
-  if (true) {
-    discard;
-  }
+  discard;
   var preserve_me = 1;
-  if (true) {
-    var preserve_me_too = 1;
-  }
 }
 )";
 
-    auto* expect = src;
-
     auto got = Run<RemoveUnreachableStatements>(src);
 
     EXPECT_EQ(expect, str(got));
@@ -319,27 +155,6 @@
     EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(RemoveUnreachableStatementsTest, IfElseDiscard) {
-    auto* src = R"(
-fn f() {
-  if (true) {
-  } else {
-    discard;
-  }
-  var preserve_me = 1;
-  if (true) {
-    var preserve_me_too = 1;
-  }
-}
-)";
-
-    auto* expect = src;
-
-    auto got = Run<RemoveUnreachableStatements>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
 TEST_F(RemoveUnreachableStatementsTest, IfElseReturn) {
     auto* src = R"(
 fn f() {
@@ -361,42 +176,6 @@
     EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(RemoveUnreachableStatementsTest, LoopWithDiscard) {
-    auto* src = R"(
-fn f() {
-  loop {
-    var a = 1;
-    discard;
-
-    continuing {
-      var b = 2;
-    }
-  }
-  var remove_me = 1;
-  if (true) {
-    var remove_me_too = 1;
-  }
-}
-)";
-
-    auto* expect = R"(
-fn f() {
-  loop {
-    var a = 1;
-    discard;
-
-    continuing {
-      var b = 2;
-    }
-  }
-}
-)";
-
-    auto got = Run<RemoveUnreachableStatements>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
 TEST_F(RemoveUnreachableStatementsTest, LoopWithConditionalBreak) {
     auto* src = R"(
 fn f() {
@@ -449,97 +228,6 @@
     EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(RemoveUnreachableStatementsTest, SwitchDefaultDiscard) {
-    auto* src = R"(
-fn f() {
-  switch(1) {
-    default: {
-      discard;
-    }
-  }
-  var remove_me = 1;
-  if (true) {
-    var remove_me_too = 1;
-  }
-}
-)";
-
-    auto* expect = R"(
-fn f() {
-  switch(1) {
-    default: {
-      discard;
-    }
-  }
-}
-)";
-
-    auto got = Run<RemoveUnreachableStatements>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RemoveUnreachableStatementsTest, SwitchCaseReturnDefaultDiscard) {
-    auto* src = R"(
-fn f() {
-  switch(1) {
-    case 0: {
-      return;
-    }
-    default: {
-      discard;
-    }
-  }
-  var remove_me = 1;
-  if (true) {
-    var remove_me_too = 1;
-  }
-}
-)";
-
-    auto* expect = R"(
-fn f() {
-  switch(1) {
-    case 0: {
-      return;
-    }
-    default: {
-      discard;
-    }
-  }
-}
-)";
-
-    auto got = Run<RemoveUnreachableStatements>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(RemoveUnreachableStatementsTest, SwitchCaseBreakDefaultDiscard) {
-    auto* src = R"(
-fn f() {
-  switch(1) {
-    case 0: {
-      break;
-    }
-    default: {
-      discard;
-    }
-  }
-  var preserve_me = 1;
-  if (true) {
-    var preserve_me_too = 1;
-  }
-}
-)";
-
-    auto* expect = src;
-
-    auto got = Run<RemoveUnreachableStatements>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
 TEST_F(RemoveUnreachableStatementsTest, SwitchCaseReturnDefaultBreak) {
     auto* src = R"(
 fn f() {
diff --git a/src/tint/transform/unwind_discard_functions.cc b/src/tint/transform/unwind_discard_functions.cc
deleted file mode 100644
index 068fe35..0000000
--- a/src/tint/transform/unwind_discard_functions.cc
+++ /dev/null
@@ -1,374 +0,0 @@
-// 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"
-#include "src/tint/transform/utils/get_insertion_point.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::transform::UnwindDiscardFunctions);
-
-namespace tint::transform {
-namespace {
-
-bool ShouldRun(const Program* program) {
-    auto& sem = program->Sem();
-    for (auto* f : program->AST().Functions()) {
-        if (sem.Get(f)->Behaviors().Contains(sem::Behavior::kDiscard)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-}  // namespace
-
-/// PIMPL state for the transform
-struct UnwindDiscardFunctions::State {
-    /// 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* {
-            // 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;
-        });
-    }
-
-  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
-
-    // 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->GlobalVar(module_discard_var_name, b.ty.bool_(), b.Expr(false),
-                               ast::AddressSpace::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, tint::utils::Empty, b.ty.void_(),
-                   tint::utils::Vector{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) {
-        tint::utils::Vector<const ast::Statement*, 2> stmts;
-
-        // For entry point functions, also emit the discard statement
-        if (IsInEntryPointFunc(stmt)) {
-            stmts.Push(CallDiscardFunc());
-        }
-
-        stmts.Push(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 = utils::GetInsertionPoint(ctx, stmt);
-        auto var_name = b.Sym();
-        auto* decl = b.Decl(b.Var(var_name, 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 = tint::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 = utils::GetInsertionPoint(ctx, 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 = utils::GetInsertionPoint(ctx, 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::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::WhileStatement* s) -> const ast::Statement* {
-                if (MayDiscard(sem.Get(s->condition))) {
-                    TINT_ICE(Transform, b.Diagnostics())
-                        << "Unexpected WhileStatement 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->initializer) {
-                    return nullptr;
-                }
-                auto* sem_expr = sem.Get(var->initializer);
-                if (!MayDiscard(sem_expr)) {
-                    return nullptr;
-                }
-                return TryInsertAfter(s, sem_expr);
-            });
-    }
-};
-
-UnwindDiscardFunctions::UnwindDiscardFunctions() = default;
-UnwindDiscardFunctions::~UnwindDiscardFunctions() = default;
-
-Transform::ApplyResult UnwindDiscardFunctions::Apply(const Program* src,
-                                                     const DataMap&,
-                                                     DataMap&) const {
-    if (!ShouldRun(src)) {
-        return SkipTransform;
-    }
-
-    ProgramBuilder b;
-    CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
-
-    State state(ctx);
-    state.Run();
-
-    ctx.Clone();
-    return Program(std::move(b));
-}
-
-}  // namespace tint::transform
diff --git a/src/tint/transform/unwind_discard_functions.h b/src/tint/transform/unwind_discard_functions.h
deleted file mode 100644
index 7614c27..0000000
--- a/src/tint/transform/unwind_discard_functions.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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 final : public Castable<UnwindDiscardFunctions, Transform> {
-  public:
-    /// Constructor
-    UnwindDiscardFunctions();
-
-    /// Destructor
-    ~UnwindDiscardFunctions() override;
-
-    /// @copydoc Transform::Apply
-    ApplyResult Apply(const Program* program,
-                      const DataMap& inputs,
-                      DataMap& outputs) const override;
-
-  private:
-    struct State;
-};
-
-}  // 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
deleted file mode 100644
index 7d1fa27..0000000
--- a/src/tint/transform/unwind_discard_functions_test.cc
+++ /dev/null
@@ -1,1480 +0,0 @@
-// 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::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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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"(
-@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;
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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, While_Cond) {
-    auto* src = R"(
-fn f() -> i32 {
-  if (true) {
-    discard;
-  }
-  return 42;
-}
-
-@fragment
-fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
-  let marker1 = 0;
-  while (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;
-}
-
-@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, Switch) {
-    auto* src = R"(
-fn f() -> i32 {
-  if (true) {
-    discard;
-  }
-  return 42;
-}
-
-@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;
-}
-
-@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();
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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;
-}
-
-@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 tint::transform
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 50cdbcf..29136cb 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -54,6 +54,7 @@
 #include "src/tint/transform/canonicalize_entry_point_io.h"
 #include "src/tint/transform/combine_samplers.h"
 #include "src/tint/transform/decompose_memory_access.h"
+#include "src/tint/transform/demote_to_helper.h"
 #include "src/tint/transform/disable_uniformity_analysis.h"
 #include "src/tint/transform/expand_compound_assignment.h"
 #include "src/tint/transform/manager.h"
@@ -66,7 +67,6 @@
 #include "src/tint/transform/single_entry_point.h"
 #include "src/tint/transform/std140.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"
@@ -217,7 +217,9 @@
     manager.Add<transform::ExpandCompoundAssignment>();
     manager.Add<transform::PromoteSideEffectsToDecl>();
     manager.Add<transform::PadStructs>();
-    manager.Add<transform::UnwindDiscardFunctions>();
+
+    // DemoteToHelper must come after PromoteSideEffectsToDecl and ExpandCompoundAssignment.
+    manager.Add<transform::DemoteToHelper>();
 
     manager.Add<transform::RemovePhonies>();
 
diff --git a/src/tint/writer/glsl/generator_impl_loop_test.cc b/src/tint/writer/glsl/generator_impl_loop_test.cc
index 7aa94be..639107b 100644
--- a/src/tint/writer/glsl/generator_impl_loop_test.cc
+++ b/src/tint/writer/glsl/generator_impl_loop_test.cc
@@ -23,7 +23,7 @@
 using GlslGeneratorImplTest_Loop = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_Loop) {
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block();
     auto* l = Loop(body, continuing);
 
@@ -36,7 +36,7 @@
 
     ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
-    discard;
+    break;
   }
 )");
 }
@@ -44,7 +44,7 @@
 TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopWithContinuing) {
     Func("a_statement", {}, ty.void_(), {});
 
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")));
     auto* l = Loop(body, continuing);
 
@@ -57,7 +57,7 @@
 
     ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
-    discard;
+    break;
     {
       a_statement();
     }
@@ -68,7 +68,7 @@
 TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopWithContinuing_BreakIf) {
     Func("a_statement", {}, ty.void_(), {});
 
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")), BreakIf(true));
     auto* l = Loop(body, continuing);
 
@@ -81,7 +81,7 @@
 
     ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
-    discard;
+    break;
     {
       a_statement();
       if (true) { break; }
@@ -96,7 +96,7 @@
     GlobalVar("lhs", ty.f32(), ast::AddressSpace::kPrivate);
     GlobalVar("rhs", ty.f32(), ast::AddressSpace::kPrivate);
 
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")));
     auto* inner = Loop(body, continuing);
 
@@ -105,7 +105,7 @@
     auto* lhs = Expr("lhs");
     auto* rhs = Expr("rhs");
 
-    continuing = Block(Assign(lhs, rhs));
+    continuing = Block(Assign(lhs, rhs), BreakIf(true));
 
     auto* outer = Loop(body, continuing);
 
@@ -119,13 +119,14 @@
     ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
     while (true) {
-      discard;
+      break;
       {
         a_statement();
       }
     }
     {
       lhs = rhs;
+      if (true) { break; }
     }
   }
 )");
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 92e0cc5..a7c3f00 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -54,6 +54,7 @@
 #include "src/tint/transform/calculate_array_length.h"
 #include "src/tint/transform/canonicalize_entry_point_io.h"
 #include "src/tint/transform/decompose_memory_access.h"
+#include "src/tint/transform/demote_to_helper.h"
 #include "src/tint/transform/disable_uniformity_analysis.h"
 #include "src/tint/transform/expand_compound_assignment.h"
 #include "src/tint/transform/localize_struct_array_assignment.h"
@@ -65,7 +66,6 @@
 #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_initializers.h"
 #include "src/tint/transform/zero_init_workgroup_memory.h"
 #include "src/tint/utils/defer.h"
@@ -213,10 +213,15 @@
     manager.Add<transform::NumWorkgroupsFromUniform>();
     manager.Add<transform::ExpandCompoundAssignment>();
     manager.Add<transform::PromoteSideEffectsToDecl>();
-    manager.Add<transform::UnwindDiscardFunctions>();
     manager.Add<transform::VectorizeScalarMatrixInitializers>();
     manager.Add<transform::SimplifyPointers>();
     manager.Add<transform::RemovePhonies>();
+
+    // DemoteToHelper must come after CanonicalizeEntryPointIO, PromoteSideEffectsToDecl, and
+    // ExpandCompoundAssignment.
+    // TODO(crbug.com/tint/1752): This is only necessary when FXC is being used.
+    manager.Add<transform::DemoteToHelper>();
+
     // ArrayLengthFromUniform must come after InlinePointerLets and Simplify, as
     // it assumes that the form of the array length argument is &var.array.
     manager.Add<transform::ArrayLengthFromUniform>();
diff --git a/src/tint/writer/hlsl/generator_impl_loop_test.cc b/src/tint/writer/hlsl/generator_impl_loop_test.cc
index 3d8219b..9d2a4de 100644
--- a/src/tint/writer/hlsl/generator_impl_loop_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_loop_test.cc
@@ -23,7 +23,7 @@
 using HlslGeneratorImplTest_Loop = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_Loop) {
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block();
     auto* l = Loop(body, continuing);
 
@@ -36,7 +36,7 @@
 
     ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
-    discard;
+    break;
   }
 )");
 }
@@ -44,7 +44,7 @@
 TEST_F(HlslGeneratorImplTest_Loop, Emit_LoopWithContinuing) {
     Func("a_statement", {}, ty.void_(), {});
 
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")));
     auto* l = Loop(body, continuing);
 
@@ -57,7 +57,7 @@
 
     ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
-    discard;
+    break;
     {
       a_statement();
     }
@@ -68,7 +68,7 @@
 TEST_F(HlslGeneratorImplTest_Loop, Emit_LoopWithContinuing_BreakIf) {
     Func("a_statement", {}, ty.void_(), {});
 
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")), BreakIf(true));
     auto* l = Loop(body, continuing);
 
@@ -81,7 +81,7 @@
 
     ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
-    discard;
+    break;
     {
       a_statement();
       if (true) { break; }
@@ -96,7 +96,7 @@
     GlobalVar("lhs", ty.f32(), ast::AddressSpace::kPrivate);
     GlobalVar("rhs", ty.f32(), ast::AddressSpace::kPrivate);
 
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")));
     auto* inner = Loop(body, continuing);
 
@@ -105,7 +105,7 @@
     auto* lhs = Expr("lhs");
     auto* rhs = Expr("rhs");
 
-    continuing = Block(Assign(lhs, rhs));
+    continuing = Block(Assign(lhs, rhs), BreakIf(true));
 
     auto* outer = Loop(body, continuing);
 
@@ -119,13 +119,14 @@
     ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
     while (true) {
-      discard;
+      break;
       {
         a_statement();
       }
     }
     {
       lhs = rhs;
+      if (true) { break; }
     }
   }
 )");
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 65b5275..88578df 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -62,6 +62,7 @@
 #include "src/tint/transform/array_length_from_uniform.h"
 #include "src/tint/transform/builtin_polyfill.h"
 #include "src/tint/transform/canonicalize_entry_point_io.h"
+#include "src/tint/transform/demote_to_helper.h"
 #include "src/tint/transform/disable_uniformity_analysis.h"
 #include "src/tint/transform/expand_compound_assignment.h"
 #include "src/tint/transform/manager.h"
@@ -72,7 +73,6 @@
 #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_initializers.h"
 #include "src/tint/transform/zero_init_workgroup_memory.h"
 #include "src/tint/utils/defer.h"
@@ -226,9 +226,12 @@
     manager.Add<transform::CanonicalizeEntryPointIO>();
     manager.Add<transform::ExpandCompoundAssignment>();
     manager.Add<transform::PromoteSideEffectsToDecl>();
-    manager.Add<transform::UnwindDiscardFunctions>();
     manager.Add<transform::PromoteInitializersToLet>();
 
+    // DemoteToHelper must come after PromoteSideEffectsToDecl and ExpandCompoundAssignment.
+    // TODO(crbug.com/tint/1752): This is only necessary for Metal versions older than 2.3.
+    manager.Add<transform::DemoteToHelper>();
+
     manager.Add<transform::VectorizeScalarMatrixInitializers>();
     manager.Add<transform::RemovePhonies>();
     manager.Add<transform::SimplifyPointers>();
diff --git a/src/tint/writer/msl/generator_impl_loop_test.cc b/src/tint/writer/msl/generator_impl_loop_test.cc
index 1dd5430..89009e0 100644
--- a/src/tint/writer/msl/generator_impl_loop_test.cc
+++ b/src/tint/writer/msl/generator_impl_loop_test.cc
@@ -23,7 +23,7 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Loop) {
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block();
     auto* l = Loop(body, continuing);
 
@@ -36,7 +36,7 @@
 
     ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
-    discard_fragment();
+    break;
   }
 )");
 }
@@ -44,7 +44,7 @@
 TEST_F(MslGeneratorImplTest, Emit_LoopWithContinuing) {
     Func("a_statement", {}, ty.void_(), utils::Empty);
 
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")));
     auto* l = Loop(body, continuing);
 
@@ -57,7 +57,7 @@
 
     ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
-    discard_fragment();
+    break;
     {
       a_statement();
     }
@@ -68,7 +68,7 @@
 TEST_F(MslGeneratorImplTest, Emit_LoopWithContinuing_BreakIf) {
     Func("a_statement", {}, ty.void_(), {});
 
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")), BreakIf(true));
     auto* l = Loop(body, continuing);
 
@@ -81,7 +81,7 @@
 
     ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
-    discard_fragment();
+    break;
     {
       a_statement();
       if (true) { break; }
@@ -96,13 +96,13 @@
     GlobalVar("lhs", ty.f32(), ast::AddressSpace::kPrivate);
     GlobalVar("rhs", ty.f32(), ast::AddressSpace::kPrivate);
 
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")));
     auto* inner = Loop(body, continuing);
 
     body = Block(inner);
 
-    continuing = Block(Assign("lhs", "rhs"));
+    continuing = Block(Assign("lhs", "rhs"), BreakIf(true));
 
     auto* outer = Loop(body, continuing);
 
@@ -116,13 +116,14 @@
     ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  while (true) {
     while (true) {
-      discard_fragment();
+      break;
       {
         a_statement();
       }
     }
     {
       lhs = rhs;
+      if (true) { break; }
     }
   }
 )");
diff --git a/src/tint/writer/spirv/generator_impl.cc b/src/tint/writer/spirv/generator_impl.cc
index aa5d449..30dd186 100644
--- a/src/tint/writer/spirv/generator_impl.cc
+++ b/src/tint/writer/spirv/generator_impl.cc
@@ -21,6 +21,7 @@
 #include "src/tint/transform/add_empty_entry_point.h"
 #include "src/tint/transform/builtin_polyfill.h"
 #include "src/tint/transform/canonicalize_entry_point_io.h"
+#include "src/tint/transform/demote_to_helper.h"
 #include "src/tint/transform/disable_uniformity_analysis.h"
 #include "src/tint/transform/expand_compound_assignment.h"
 #include "src/tint/transform/for_loop_to_loop.h"
@@ -32,7 +33,6 @@
 #include "src/tint/transform/simplify_pointers.h"
 #include "src/tint/transform/std140.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_matrix_conversions.h"
 #include "src/tint/transform/vectorize_scalar_matrix_initializers.h"
@@ -82,7 +82,6 @@
     manager.Add<transform::RemoveUnreachableStatements>();
     manager.Add<transform::ExpandCompoundAssignment>();
     manager.Add<transform::PromoteSideEffectsToDecl>();
-    manager.Add<transform::UnwindDiscardFunctions>();
     manager.Add<transform::SimplifyPointers>();  // Required for arrayLength()
     manager.Add<transform::RemovePhonies>();
     manager.Add<transform::VectorizeScalarMatrixInitializers>();
@@ -93,6 +92,11 @@
     manager.Add<transform::AddEmptyEntryPoint>();
     manager.Add<transform::AddBlockAttribute>();
 
+    // DemoteToHelper must come after CanonicalizeEntryPointIO, PromoteSideEffectsToDecl, and
+    // ExpandCompoundAssignment.
+    // TODO(crbug.com/tint/1752): Use SPV_EXT_demote_to_helper_invocation if available.
+    manager.Add<transform::DemoteToHelper>();
+
     // Std140 must come after PromoteSideEffectsToDecl.
     // Std140 must come before VarForDynamicIndex and ForLoopToLoop.
     manager.Add<transform::Std140>();
diff --git a/src/tint/writer/wgsl/generator_impl_loop_test.cc b/src/tint/writer/wgsl/generator_impl_loop_test.cc
index 48510bb..ac3f808 100644
--- a/src/tint/writer/wgsl/generator_impl_loop_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_loop_test.cc
@@ -22,7 +22,7 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Loop) {
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block();
     auto* l = Loop(body, continuing);
 
@@ -35,7 +35,7 @@
 
     ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  loop {
-    discard;
+    break;
   }
 )");
 }
@@ -43,7 +43,7 @@
 TEST_F(WgslGeneratorImplTest, Emit_LoopWithContinuing) {
     Func("a_statement", {}, ty.void_(), {});
 
-    auto* body = Block(create<ast::DiscardStatement>());
+    auto* body = Block(Break());
     auto* continuing = Block(CallStmt(Call("a_statement")));
     auto* l = Loop(body, continuing);
 
@@ -56,7 +56,7 @@
 
     ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
     EXPECT_EQ(gen.result(), R"(  loop {
-    discard;
+    break;
 
     continuing {
       a_statement();
diff --git a/test/tint/bug/dawn/947.wgsl.expected.dxc.hlsl b/test/tint/bug/dawn/947.wgsl.expected.dxc.hlsl
index 7557169..262a1ca 100644
--- a/test/tint/bug/dawn/947.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/dawn/947.wgsl.expected.dxc.hlsl
@@ -1,3 +1,5 @@
+static bool tint_discarded = false;
+
 cbuffer cbuffer_uniforms : register(b0, space0) {
   uint4 uniforms[1];
 };
@@ -45,30 +47,21 @@
   float4 value : SV_Target0;
 };
 
-static bool tint_discard = false;
-
 float4 fs_main_inner(float2 texcoord) {
   float2 clampedTexcoord = clamp(texcoord, (0.0f).xx, (1.0f).xx);
   if (!(all((clampedTexcoord == texcoord)))) {
-    tint_discard = true;
-    return (0.0f).xxxx;
+    tint_discarded = true;
   }
   float4 srcColor = (0.0f).xxxx;
   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;
+  if (tint_discarded) {
+    discard;
+  }
   return wrapper_result_1;
 }
diff --git a/test/tint/bug/dawn/947.wgsl.expected.fxc.hlsl b/test/tint/bug/dawn/947.wgsl.expected.fxc.hlsl
index 7557169..262a1ca 100644
--- a/test/tint/bug/dawn/947.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/dawn/947.wgsl.expected.fxc.hlsl
@@ -1,3 +1,5 @@
+static bool tint_discarded = false;
+
 cbuffer cbuffer_uniforms : register(b0, space0) {
   uint4 uniforms[1];
 };
@@ -45,30 +47,21 @@
   float4 value : SV_Target0;
 };
 
-static bool tint_discard = false;
-
 float4 fs_main_inner(float2 texcoord) {
   float2 clampedTexcoord = clamp(texcoord, (0.0f).xx, (1.0f).xx);
   if (!(all((clampedTexcoord == texcoord)))) {
-    tint_discard = true;
-    return (0.0f).xxxx;
+    tint_discarded = true;
   }
   float4 srcColor = (0.0f).xxxx;
   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;
+  if (tint_discarded) {
+    discard;
+  }
   return wrapper_result_1;
 }
diff --git a/test/tint/bug/dawn/947.wgsl.expected.glsl b/test/tint/bug/dawn/947.wgsl.expected.glsl
index 307e7c3..ead3e6b 100644
--- a/test/tint/bug/dawn/947.wgsl.expected.glsl
+++ b/test/tint/bug/dawn/947.wgsl.expected.glsl
@@ -40,6 +40,7 @@
 #version 310 es
 precision mediump float;
 
+bool tint_discarded = false;
 layout(location = 0) in vec2 texcoord_1;
 layout(location = 0) out vec4 value;
 struct Uniforms {
@@ -52,27 +53,20 @@
   vec4 position;
 };
 
-bool tint_discard = false;
 vec4 fs_main(vec2 texcoord) {
   vec2 clampedTexcoord = clamp(texcoord, vec2(0.0f), vec2(1.0f));
   if (!(all(equal(clampedTexcoord, texcoord)))) {
-    tint_discard = true;
-    return vec4(0.0f);
+    tint_discarded = true;
   }
   vec4 srcColor = vec4(0.0f);
   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;
+  if (tint_discarded) {
+    discard;
+  }
   return;
 }
diff --git a/test/tint/bug/dawn/947.wgsl.expected.msl b/test/tint/bug/dawn/947.wgsl.expected.msl
index df5dab0..02084ce 100644
--- a/test/tint/bug/dawn/947.wgsl.expected.msl
+++ b/test/tint/bug/dawn/947.wgsl.expected.msl
@@ -29,21 +29,21 @@
   float4 position [[position]];
 };
 
-VertexOutputs vs_main_inner(uint VertexIndex, const constant Uniforms* const tint_symbol_5) {
+VertexOutputs vs_main_inner(uint VertexIndex, const constant Uniforms* const tint_symbol_4) {
   tint_array<float2, 3> texcoord = tint_array<float2, 3>{float2(-0.5f, 0.0f), float2(1.5f, 0.0f), float2(0.5f, 2.0f)};
   VertexOutputs output = {};
   output.position = float4(((texcoord[VertexIndex] * 2.0f) - float2(1.0f)), 0.0f, 1.0f);
-  bool flipY = ((*(tint_symbol_5)).u_scale[1] < 0.0f);
+  bool flipY = ((*(tint_symbol_4)).u_scale[1] < 0.0f);
   if (flipY) {
-    output.texcoords = ((((texcoord[VertexIndex] * (*(tint_symbol_5)).u_scale) + (*(tint_symbol_5)).u_offset) * float2(1.0f, -1.0f)) + float2(0.0f, 1.0f));
+    output.texcoords = ((((texcoord[VertexIndex] * (*(tint_symbol_4)).u_scale) + (*(tint_symbol_4)).u_offset) * float2(1.0f, -1.0f)) + float2(0.0f, 1.0f));
   } else {
-    output.texcoords = ((((texcoord[VertexIndex] * float2(1.0f, -1.0f)) + float2(0.0f, 1.0f)) * (*(tint_symbol_5)).u_scale) + (*(tint_symbol_5)).u_offset);
+    output.texcoords = ((((texcoord[VertexIndex] * float2(1.0f, -1.0f)) + float2(0.0f, 1.0f)) * (*(tint_symbol_4)).u_scale) + (*(tint_symbol_4)).u_offset);
   }
   return output;
 }
 
-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);
+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);
   tint_symbol wrapper_result = {};
   wrapper_result.texcoords = inner_result.texcoords;
   wrapper_result.position = inner_result.position;
@@ -58,30 +58,23 @@
   float4 value [[color(0)]];
 };
 
-float4 fs_main_inner(float2 texcoord, thread bool* const tint_symbol_7) {
+float4 fs_main_inner(float2 texcoord, thread bool* const tint_symbol_6) {
   float2 clampedTexcoord = clamp(texcoord, float2(0.0f), float2(1.0f));
   if (!(all((clampedTexcoord == texcoord)))) {
-    *(tint_symbol_7) = true;
-    return float4(0.0f);
+    *(tint_symbol_6) = true;
   }
   float4 srcColor = float4(0.0f);
   return srcColor;
 }
 
-void tint_discard_func() {
-  discard_fragment();
-}
-
 fragment tint_symbol_3 fs_main(tint_symbol_2 tint_symbol_1 [[stage_in]]) {
-  thread bool tint_symbol_8 = false;
-  float4 const inner_result_1 = fs_main_inner(tint_symbol_1.texcoord, &(tint_symbol_8));
-  if (tint_symbol_8) {
-    tint_discard_func();
-    tint_symbol_3 const tint_symbol_4 = tint_symbol_3{};
-    return tint_symbol_4;
-  }
+  thread bool tint_symbol_7 = false;
+  float4 const inner_result_1 = fs_main_inner(tint_symbol_1.texcoord, &(tint_symbol_7));
   tint_symbol_3 wrapper_result_1 = {};
   wrapper_result_1.value = inner_result_1;
+  if (tint_symbol_7) {
+    discard_fragment();
+  }
   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 10da7fe..c60d142 100644
--- a/test/tint/bug/dawn/947.wgsl.expected.spvasm
+++ b/test/tint/bug/dawn/947.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 134
+; Bound: 137
 ; Schema: 0
                OpCapability Shader
         %118 = OpExtInstImport "GLSL.std.450"
@@ -9,6 +9,7 @@
                OpEntryPoint Vertex %vs_main "vs_main" %VertexIndex_1 %texcoords_1 %position_1 %vertex_point_size
                OpEntryPoint Fragment %fs_main "fs_main" %texcoord_1 %value
                OpExecutionMode %fs_main OriginUpperLeft
+               OpName %tint_discarded "tint_discarded"
                OpName %VertexIndex_1 "VertexIndex_1"
                OpName %texcoords_1 "texcoords_1"
                OpName %position_1 "position_1"
@@ -32,7 +33,6 @@
                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"
@@ -58,144 +58,143 @@
                OpMemberDecorate %VertexOutputs 0 Offset 0
                OpMemberDecorate %VertexOutputs 1 Offset 16
                OpDecorate %_arr_v2float_uint_3 ArrayStride 8
+       %bool = OpTypeBool
+          %2 = OpConstantNull %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discarded = OpVariable %_ptr_Private_bool Private %2
        %uint = OpTypeInt 32 0
 %_ptr_Input_uint = OpTypePointer Input %uint
 %VertexIndex_1 = OpVariable %_ptr_Input_uint Input
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
 %_ptr_Output_v2float = OpTypePointer Output %v2float
-          %8 = OpConstantNull %v2float
-%texcoords_1 = OpVariable %_ptr_Output_v2float Output %8
+         %12 = OpConstantNull %v2float
+%texcoords_1 = OpVariable %_ptr_Output_v2float Output %12
     %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
-         %12 = OpConstantNull %v4float
- %position_1 = OpVariable %_ptr_Output_v4float Output %12
+         %16 = OpConstantNull %v4float
+ %position_1 = OpVariable %_ptr_Output_v4float Output %16
 %_ptr_Output_float = OpTypePointer Output %float
-         %15 = OpConstantNull %float
-%vertex_point_size = OpVariable %_ptr_Output_float Output %15
+         %19 = OpConstantNull %float
+%vertex_point_size = OpVariable %_ptr_Output_float Output %19
 %_ptr_Input_v2float = OpTypePointer Input %v2float
  %texcoord_1 = OpVariable %_ptr_Input_v2float Input
-      %value = OpVariable %_ptr_Output_v4float Output %12
+      %value = OpVariable %_ptr_Output_v4float Output %16
    %Uniforms = OpTypeStruct %v2float %v2float
 %uniforms_block = OpTypeStruct %Uniforms
 %_ptr_Uniform_uniforms_block = OpTypePointer Uniform %uniforms_block
    %uniforms = OpVariable %_ptr_Uniform_uniforms_block Uniform
-         %25 = OpTypeSampler
-%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25
-  %mySampler = OpVariable %_ptr_UniformConstant_25 UniformConstant
-         %28 = OpTypeImage %float 2D 0 0 0 1 Unknown
-%_ptr_UniformConstant_28 = OpTypePointer UniformConstant %28
-  %myTexture = OpVariable %_ptr_UniformConstant_28 UniformConstant
+         %29 = OpTypeSampler
+%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29
+  %mySampler = OpVariable %_ptr_UniformConstant_29 UniformConstant
+         %32 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_32 = OpTypePointer UniformConstant %32
+  %myTexture = OpVariable %_ptr_UniformConstant_32 UniformConstant
 %VertexOutputs = OpTypeStruct %v2float %v4float
-         %29 = OpTypeFunction %VertexOutputs %uint
+         %33 = OpTypeFunction %VertexOutputs %uint
      %uint_3 = OpConstant %uint 3
 %_arr_v2float_uint_3 = OpTypeArray %v2float %uint_3
  %float_n0_5 = OpConstant %float -0.5
-         %37 = OpConstantComposite %v2float %float_n0_5 %15
+         %41 = OpConstantComposite %v2float %float_n0_5 %19
   %float_1_5 = OpConstant %float 1.5
-         %39 = OpConstantComposite %v2float %float_1_5 %15
+         %43 = OpConstantComposite %v2float %float_1_5 %19
   %float_0_5 = OpConstant %float 0.5
     %float_2 = OpConstant %float 2
-         %42 = OpConstantComposite %v2float %float_0_5 %float_2
-         %43 = OpConstantComposite %_arr_v2float_uint_3 %37 %39 %42
+         %46 = OpConstantComposite %v2float %float_0_5 %float_2
+         %47 = OpConstantComposite %_arr_v2float_uint_3 %41 %43 %46
 %_ptr_Function__arr_v2float_uint_3 = OpTypePointer Function %_arr_v2float_uint_3
-         %46 = OpConstantNull %_arr_v2float_uint_3
+         %50 = OpConstantNull %_arr_v2float_uint_3
 %_ptr_Function_VertexOutputs = OpTypePointer Function %VertexOutputs
-         %49 = OpConstantNull %VertexOutputs
+         %53 = OpConstantNull %VertexOutputs
      %uint_1 = OpConstant %uint 1
 %_ptr_Function_v4float = OpTypePointer Function %v4float
 %_ptr_Function_v2float = OpTypePointer Function %v2float
     %float_1 = OpConstant %float 1
-         %58 = OpConstantComposite %v2float %float_1 %float_1
+         %62 = OpConstantComposite %v2float %float_1 %float_1
      %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-       %bool = OpTypeBool
 %_ptr_Function_bool = OpTypePointer Function %bool
-         %71 = OpConstantNull %bool
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
    %float_n1 = OpConstant %float -1
-         %87 = OpConstantComposite %v2float %float_1 %float_n1
-         %89 = OpConstantComposite %v2float %15 %float_1
+         %89 = OpConstantComposite %v2float %float_1 %float_n1
+         %91 = OpConstantComposite %v2float %19 %float_1
        %void = OpTypeVoid
-        %103 = OpTypeFunction %void
+        %105 = OpTypeFunction %void
         %113 = OpTypeFunction %v4float %v2float
      %v2bool = OpTypeVector %bool 2
-%vs_main_inner = OpFunction %VertexOutputs None %29
+       %true = OpConstantTrue %bool
+%vs_main_inner = OpFunction %VertexOutputs None %33
 %VertexIndex = OpFunctionParameter %uint
-         %33 = OpLabel
-   %texcoord = OpVariable %_ptr_Function__arr_v2float_uint_3 Function %46
-     %output = OpVariable %_ptr_Function_VertexOutputs Function %49
-      %flipY = OpVariable %_ptr_Function_bool Function %71
-               OpStore %texcoord %43
-         %52 = OpAccessChain %_ptr_Function_v4float %output %uint_1
-         %54 = OpAccessChain %_ptr_Function_v2float %texcoord %VertexIndex
-         %55 = OpLoad %v2float %54
-         %56 = OpVectorTimesScalar %v2float %55 %float_2
-         %59 = OpFSub %v2float %56 %58
-         %60 = OpCompositeExtract %float %59 0
-         %61 = OpCompositeExtract %float %59 1
-         %62 = OpCompositeConstruct %v4float %60 %61 %15 %float_1
-               OpStore %52 %62
-         %65 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_0 %uint_1
-         %66 = OpLoad %float %65
-         %67 = OpFOrdLessThan %bool %66 %15
-               OpStore %flipY %67
-         %72 = OpLoad %bool %flipY
-               OpSelectionMerge %73 None
-               OpBranchConditional %72 %74 %75
-         %74 = OpLabel
-         %76 = OpAccessChain %_ptr_Function_v2float %output %uint_0
-         %77 = OpAccessChain %_ptr_Function_v2float %texcoord %VertexIndex
-         %78 = OpLoad %v2float %77
-         %80 = OpAccessChain %_ptr_Uniform_v2float %uniforms %uint_0 %uint_0
-         %81 = OpLoad %v2float %80
-         %82 = OpFMul %v2float %78 %81
-         %83 = OpAccessChain %_ptr_Uniform_v2float %uniforms %uint_0 %uint_1
-         %84 = OpLoad %v2float %83
-         %85 = OpFAdd %v2float %82 %84
-         %88 = OpFMul %v2float %85 %87
-         %90 = OpFAdd %v2float %88 %89
-               OpStore %76 %90
-               OpBranch %73
+         %37 = OpLabel
+   %texcoord = OpVariable %_ptr_Function__arr_v2float_uint_3 Function %50
+     %output = OpVariable %_ptr_Function_VertexOutputs Function %53
+      %flipY = OpVariable %_ptr_Function_bool Function %2
+               OpStore %texcoord %47
+         %56 = OpAccessChain %_ptr_Function_v4float %output %uint_1
+         %58 = OpAccessChain %_ptr_Function_v2float %texcoord %VertexIndex
+         %59 = OpLoad %v2float %58
+         %60 = OpVectorTimesScalar %v2float %59 %float_2
+         %63 = OpFSub %v2float %60 %62
+         %64 = OpCompositeExtract %float %63 0
+         %65 = OpCompositeExtract %float %63 1
+         %66 = OpCompositeConstruct %v4float %64 %65 %19 %float_1
+               OpStore %56 %66
+         %69 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_0 %uint_1
+         %70 = OpLoad %float %69
+         %71 = OpFOrdLessThan %bool %70 %19
+               OpStore %flipY %71
+         %74 = OpLoad %bool %flipY
+               OpSelectionMerge %75 None
+               OpBranchConditional %74 %76 %77
+         %76 = OpLabel
+         %78 = OpAccessChain %_ptr_Function_v2float %output %uint_0
+         %79 = OpAccessChain %_ptr_Function_v2float %texcoord %VertexIndex
+         %80 = OpLoad %v2float %79
+         %82 = OpAccessChain %_ptr_Uniform_v2float %uniforms %uint_0 %uint_0
+         %83 = OpLoad %v2float %82
+         %84 = OpFMul %v2float %80 %83
+         %85 = OpAccessChain %_ptr_Uniform_v2float %uniforms %uint_0 %uint_1
+         %86 = OpLoad %v2float %85
+         %87 = OpFAdd %v2float %84 %86
+         %90 = OpFMul %v2float %87 %89
+         %92 = OpFAdd %v2float %90 %91
+               OpStore %78 %92
+               OpBranch %75
+         %77 = OpLabel
+         %93 = OpAccessChain %_ptr_Function_v2float %output %uint_0
+         %94 = OpAccessChain %_ptr_Function_v2float %texcoord %VertexIndex
+         %95 = OpLoad %v2float %94
+         %96 = OpFMul %v2float %95 %89
+         %97 = OpFAdd %v2float %96 %91
+         %98 = OpAccessChain %_ptr_Uniform_v2float %uniforms %uint_0 %uint_0
+         %99 = OpLoad %v2float %98
+        %100 = OpFMul %v2float %97 %99
+        %101 = OpAccessChain %_ptr_Uniform_v2float %uniforms %uint_0 %uint_1
+        %102 = OpLoad %v2float %101
+        %103 = OpFAdd %v2float %100 %102
+               OpStore %93 %103
+               OpBranch %75
          %75 = OpLabel
-         %91 = OpAccessChain %_ptr_Function_v2float %output %uint_0
-         %92 = OpAccessChain %_ptr_Function_v2float %texcoord %VertexIndex
-         %93 = OpLoad %v2float %92
-         %94 = OpFMul %v2float %93 %87
-         %95 = OpFAdd %v2float %94 %89
-         %96 = OpAccessChain %_ptr_Uniform_v2float %uniforms %uint_0 %uint_0
-         %97 = OpLoad %v2float %96
-         %98 = OpFMul %v2float %95 %97
-         %99 = OpAccessChain %_ptr_Uniform_v2float %uniforms %uint_0 %uint_1
-        %100 = OpLoad %v2float %99
-        %101 = OpFAdd %v2float %98 %100
-               OpStore %91 %101
-               OpBranch %73
-         %73 = OpLabel
-        %102 = OpLoad %VertexOutputs %output
-               OpReturnValue %102
+        %104 = OpLoad %VertexOutputs %output
+               OpReturnValue %104
                OpFunctionEnd
-    %vs_main = OpFunction %void None %103
-        %106 = OpLabel
-        %108 = OpLoad %uint %VertexIndex_1
-        %107 = OpFunctionCall %VertexOutputs %vs_main_inner %108
-        %109 = OpCompositeExtract %v2float %107 0
-               OpStore %texcoords_1 %109
-        %110 = OpCompositeExtract %v4float %107 1
-               OpStore %position_1 %110
+    %vs_main = OpFunction %void None %105
+        %108 = OpLabel
+        %110 = OpLoad %uint %VertexIndex_1
+        %109 = OpFunctionCall %VertexOutputs %vs_main_inner %110
+        %111 = OpCompositeExtract %v2float %109 0
+               OpStore %texcoords_1 %111
+        %112 = OpCompositeExtract %v4float %109 1
+               OpStore %position_1 %112
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
-%tint_discard_func = OpFunction %void None %103
-        %112 = OpLabel
-               OpKill
-               OpFunctionEnd
 %fs_main_inner = OpFunction %v4float None %113
  %texcoord_0 = OpFunctionParameter %v2float
         %116 = OpLabel
-%clampedTexcoord = OpVariable %_ptr_Function_v2float Function %8
-   %srcColor = OpVariable %_ptr_Function_v4float Function %12
-        %117 = OpExtInst %v2float %118 NClamp %texcoord_0 %8 %58
+%clampedTexcoord = OpVariable %_ptr_Function_v2float Function %12
+   %srcColor = OpVariable %_ptr_Function_v4float Function %16
+        %117 = OpExtInst %v2float %118 NClamp %texcoord_0 %12 %62
                OpStore %clampedTexcoord %117
         %122 = OpLoad %v2float %clampedTexcoord
         %123 = OpFOrdEqual %v2bool %122 %texcoord_0
@@ -204,17 +203,23 @@
                OpSelectionMerge %125 None
                OpBranchConditional %120 %126 %125
         %126 = OpLabel
-        %127 = OpFunctionCall %void %tint_discard_func
-               OpReturnValue %12
+               OpStore %tint_discarded %true
+               OpBranch %125
         %125 = OpLabel
-               OpStore %srcColor %12
+               OpStore %srcColor %16
         %129 = OpLoad %v4float %srcColor
                OpReturnValue %129
                OpFunctionEnd
-    %fs_main = OpFunction %void None %103
+    %fs_main = OpFunction %void None %105
         %131 = OpLabel
         %133 = OpLoad %v2float %texcoord_1
         %132 = OpFunctionCall %v4float %fs_main_inner %133
                OpStore %value %132
+        %134 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %135 None
+               OpBranchConditional %134 %136 %135
+        %136 = OpLabel
+               OpKill
+        %135 = OpLabel
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/1081.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/1081.wgsl.expected.dxc.hlsl
index 55f7d15..0f7e2c2 100644
--- a/test/tint/bug/tint/1081.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/1081.wgsl.expected.dxc.hlsl
@@ -1,9 +1,8 @@
-static bool tint_discard = false;
+static bool tint_discarded = false;
 
 int f(int x) {
   if ((x == 10)) {
-    tint_discard = true;
-    return 0;
+    tint_discarded = true;
   }
   return x;
 }
@@ -19,9 +18,6 @@
   int y = x.x;
   while (true) {
     const int r = f(y);
-    if (tint_discard) {
-      return 0;
-    }
     if ((r == 0)) {
       break;
     }
@@ -29,18 +25,12 @@
   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;
+  if (tint_discarded) {
+    discard;
+  }
   return wrapper_result;
 }
diff --git a/test/tint/bug/tint/1081.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/1081.wgsl.expected.fxc.hlsl
index 55f7d15..0f7e2c2 100644
--- a/test/tint/bug/tint/1081.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/1081.wgsl.expected.fxc.hlsl
@@ -1,9 +1,8 @@
-static bool tint_discard = false;
+static bool tint_discarded = false;
 
 int f(int x) {
   if ((x == 10)) {
-    tint_discard = true;
-    return 0;
+    tint_discarded = true;
   }
   return x;
 }
@@ -19,9 +18,6 @@
   int y = x.x;
   while (true) {
     const int r = f(y);
-    if (tint_discard) {
-      return 0;
-    }
     if ((r == 0)) {
       break;
     }
@@ -29,18 +25,12 @@
   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;
+  if (tint_discarded) {
+    discard;
+  }
   return wrapper_result;
 }
diff --git a/test/tint/bug/tint/1081.wgsl.expected.glsl b/test/tint/bug/tint/1081.wgsl.expected.glsl
index 5bef660..cd44545 100644
--- a/test/tint/bug/tint/1081.wgsl.expected.glsl
+++ b/test/tint/bug/tint/1081.wgsl.expected.glsl
@@ -1,13 +1,12 @@
 #version 310 es
 precision mediump float;
 
+bool tint_discarded = false;
 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)) {
-    tint_discard = true;
-    return 0;
+    tint_discarded = true;
   }
   return x;
 }
@@ -16,9 +15,6 @@
   int y = x.x;
   while (true) {
     int r = f(y);
-    if (tint_discard) {
-      return 0;
-    }
     if ((r == 0)) {
       break;
     }
@@ -26,16 +22,11 @@
   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;
+  if (tint_discarded) {
+    discard;
+  }
   return;
 }
diff --git a/test/tint/bug/tint/1081.wgsl.expected.msl b/test/tint/bug/tint/1081.wgsl.expected.msl
index d60e032..1194ebf 100644
--- a/test/tint/bug/tint/1081.wgsl.expected.msl
+++ b/test/tint/bug/tint/1081.wgsl.expected.msl
@@ -1,10 +1,9 @@
 #include <metal_stdlib>
 
 using namespace metal;
-int f(int x, thread bool* const tint_symbol_5) {
+int f(int x, thread bool* const tint_symbol_4) {
   if ((x == 10)) {
-    *(tint_symbol_5) = true;
-    return 0;
+    *(tint_symbol_4) = true;
   }
   return x;
 }
@@ -17,13 +16,10 @@
   int value [[color(2)]];
 };
 
-int tint_symbol_inner(int3 x, thread bool* const tint_symbol_6) {
+int tint_symbol_inner(int3 x, thread bool* const tint_symbol_5) {
   int y = x[0];
   while (true) {
-    int const r = f(y, tint_symbol_6);
-    if (*(tint_symbol_6)) {
-      return 0;
-    }
+    int const r = f(y, tint_symbol_5);
     if ((r == 0)) {
       break;
     }
@@ -31,20 +27,14 @@
   return y;
 }
 
-void tint_discard_func() {
-  discard_fragment();
-}
-
 fragment tint_symbol_3 tint_symbol(tint_symbol_2 tint_symbol_1 [[stage_in]]) {
-  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 = tint_symbol_3{};
-    return tint_symbol_4;
-  }
+  thread bool tint_symbol_6 = false;
+  int const inner_result = tint_symbol_inner(tint_symbol_1.x, &(tint_symbol_6));
   tint_symbol_3 wrapper_result = {};
   wrapper_result.value = inner_result;
+  if (tint_symbol_6) {
+    discard_fragment();
+  }
   return wrapper_result;
 }
 
diff --git a/test/tint/bug/tint/1081.wgsl.expected.spvasm b/test/tint/bug/tint/1081.wgsl.expected.spvasm
index 16ea294..62aac7b 100644
--- a/test/tint/bug/tint/1081.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/1081.wgsl.expected.spvasm
@@ -1,20 +1,17 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 58
+; Bound: 47
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint Fragment %main "main" %x_1 %value
                OpExecutionMode %main OriginUpperLeft
+               OpName %tint_discarded "tint_discarded"
                OpName %x_1 "x_1"
                OpName %value "value"
-               OpName %tint_discard "tint_discard"
                OpName %f "f"
                OpName %x "x"
-               OpName %tint_return_flag "tint_return_flag"
-               OpName %tint_return_value "tint_return_value"
-               OpName %tint_discard_func "tint_discard_func"
                OpName %main_inner "main_inner"
                OpName %x_0 "x"
                OpName %y "y"
@@ -22,92 +19,72 @@
                OpDecorate %x_1 Location 1
                OpDecorate %x_1 Flat
                OpDecorate %value Location 2
+       %bool = OpTypeBool
+          %2 = OpConstantNull %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discarded = OpVariable %_ptr_Private_bool Private %2
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
 %_ptr_Input_v3int = OpTypePointer Input %v3int
         %x_1 = OpVariable %_ptr_Input_v3int Input
 %_ptr_Output_int = OpTypePointer Output %int
-          %7 = OpConstantNull %int
-      %value = OpVariable %_ptr_Output_int Output %7
-       %bool = OpTypeBool
-          %9 = OpConstantNull %bool
-%_ptr_Private_bool = OpTypePointer Private %bool
-%tint_discard = OpVariable %_ptr_Private_bool Private %9
+         %11 = OpConstantNull %int
+      %value = OpVariable %_ptr_Output_int Output %11
          %12 = OpTypeFunction %int %int
-%_ptr_Function_bool = OpTypePointer Function %bool
-%_ptr_Function_int = OpTypePointer Function %int
      %int_10 = OpConstant %int 10
        %true = OpConstantTrue %bool
+         %21 = OpTypeFunction %int %v3int
+%_ptr_Function_int = OpTypePointer Function %int
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void
-         %34 = OpTypeFunction %int %v3int
+         %38 = OpTypeFunction %void
           %f = OpFunction %int None %12
           %x = OpFunctionParameter %int
          %15 = OpLabel
-%tint_return_flag = OpVariable %_ptr_Function_bool Function %9
-%tint_return_value = OpVariable %_ptr_Function_int Function %7
-         %21 = OpIEqual %bool %x %int_10
-               OpSelectionMerge %22 None
-               OpBranchConditional %21 %23 %22
-         %23 = OpLabel
-               OpStore %tint_discard %true
-               OpStore %tint_return_flag %true
-               OpStore %tint_return_value %7
-               OpBranch %22
-         %22 = OpLabel
-         %26 = OpLoad %bool %tint_return_flag
-         %25 = OpLogicalNot %bool %26
-               OpSelectionMerge %27 None
-               OpBranchConditional %25 %28 %27
-         %28 = OpLabel
-               OpStore %tint_return_flag %true
-               OpStore %tint_return_value %x
-               OpBranch %27
-         %27 = OpLabel
-         %29 = OpLoad %int %tint_return_value
-               OpReturnValue %29
+         %17 = OpIEqual %bool %x %int_10
+               OpSelectionMerge %18 None
+               OpBranchConditional %17 %19 %18
+         %19 = OpLabel
+               OpStore %tint_discarded %true
+               OpBranch %18
+         %18 = OpLabel
+               OpReturnValue %x
                OpFunctionEnd
-%tint_discard_func = OpFunction %void None %30
-         %33 = OpLabel
-               OpKill
-               OpFunctionEnd
- %main_inner = OpFunction %int None %34
+ %main_inner = OpFunction %int None %21
         %x_0 = OpFunctionParameter %v3int
-         %37 = OpLabel
-          %y = OpVariable %_ptr_Function_int Function %7
-         %38 = OpCompositeExtract %int %x_0 0
-               OpStore %y %38
-               OpBranch %40
-         %40 = OpLabel
-               OpLoopMerge %41 %42 None
-               OpBranch %43
-         %43 = OpLabel
-         %45 = OpLoad %int %y
-         %44 = OpFunctionCall %int %f %45
-         %46 = OpLoad %bool %tint_discard
-               OpSelectionMerge %47 None
-               OpBranchConditional %46 %48 %47
-         %48 = OpLabel
-         %49 = OpFunctionCall %void %tint_discard_func
-               OpReturnValue %7
-         %47 = OpLabel
-         %50 = OpIEqual %bool %44 %7
-               OpSelectionMerge %51 None
-               OpBranchConditional %50 %52 %51
-         %52 = OpLabel
-               OpBranch %41
-         %51 = OpLabel
-               OpBranch %42
-         %42 = OpLabel
-               OpBranch %40
-         %41 = OpLabel
-         %53 = OpLoad %int %y
-               OpReturnValue %53
+         %24 = OpLabel
+          %y = OpVariable %_ptr_Function_int Function %11
+         %25 = OpCompositeExtract %int %x_0 0
+               OpStore %y %25
+               OpBranch %28
+         %28 = OpLabel
+               OpLoopMerge %29 %30 None
+               OpBranch %31
+         %31 = OpLabel
+         %33 = OpLoad %int %y
+         %32 = OpFunctionCall %int %f %33
+         %34 = OpIEqual %bool %32 %11
+               OpSelectionMerge %35 None
+               OpBranchConditional %34 %36 %35
+         %36 = OpLabel
+               OpBranch %29
+         %35 = OpLabel
+               OpBranch %30
+         %30 = OpLabel
+               OpBranch %28
+         %29 = OpLabel
+         %37 = OpLoad %int %y
+               OpReturnValue %37
                OpFunctionEnd
-       %main = OpFunction %void None %30
-         %55 = OpLabel
-         %57 = OpLoad %v3int %x_1
-         %56 = OpFunctionCall %int %main_inner %57
-               OpStore %value %56
+       %main = OpFunction %void None %38
+         %41 = OpLabel
+         %43 = OpLoad %v3int %x_1
+         %42 = OpFunctionCall %int %main_inner %43
+               OpStore %value %42
+         %44 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %45 None
+               OpBranchConditional %44 %46 %45
+         %46 = OpLabel
+               OpKill
+         %45 = OpLabel
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/1118.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/1118.wgsl.expected.dxc.hlsl
index e348eb1..9b18484 100644
--- a/test/tint/bug/tint/1118.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/1118.wgsl.expected.dxc.hlsl
@@ -1,3 +1,5 @@
+static bool tint_discarded = false;
+
 static float fClipDistance3 = 0.0f;
 static float fClipDistance4 = 0.0f;
 cbuffer cbuffer_x_29 : register(b0, space0) {
@@ -10,7 +12,6 @@
   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,13 +32,11 @@
   float4 color = float4(0.0f, 0.0f, 0.0f, 0.0f);
   const float x_9 = fClipDistance3;
   if ((x_9 > 0.0f)) {
-    tint_discard = true;
-    return;
+    tint_discarded = true;
   }
   const float x_17 = fClipDistance4;
   if ((x_17 > 0.0f)) {
-    tint_discard = true;
-    return;
+    tint_discarded = true;
   }
   const float4 x_34 = asfloat(x_29[0]);
   const float3 x_38 = (0.0f).xxx;
@@ -105,26 +104,16 @@
   fClipDistance3 = fClipDistance3_param;
   fClipDistance4 = fClipDistance4_param;
   main_1();
-  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;
+  const main_out tint_symbol_8 = {glFragColor};
+  return tint_symbol_8;
 }
 
 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;
+  if (tint_discarded) {
+    discard;
+  }
   return wrapper_result;
 }
diff --git a/test/tint/bug/tint/1118.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/1118.wgsl.expected.fxc.hlsl
index e348eb1..9b18484 100644
--- a/test/tint/bug/tint/1118.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/1118.wgsl.expected.fxc.hlsl
@@ -1,3 +1,5 @@
+static bool tint_discarded = false;
+
 static float fClipDistance3 = 0.0f;
 static float fClipDistance4 = 0.0f;
 cbuffer cbuffer_x_29 : register(b0, space0) {
@@ -10,7 +12,6 @@
   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,13 +32,11 @@
   float4 color = float4(0.0f, 0.0f, 0.0f, 0.0f);
   const float x_9 = fClipDistance3;
   if ((x_9 > 0.0f)) {
-    tint_discard = true;
-    return;
+    tint_discarded = true;
   }
   const float x_17 = fClipDistance4;
   if ((x_17 > 0.0f)) {
-    tint_discard = true;
-    return;
+    tint_discarded = true;
   }
   const float4 x_34 = asfloat(x_29[0]);
   const float3 x_38 = (0.0f).xxx;
@@ -105,26 +104,16 @@
   fClipDistance3 = fClipDistance3_param;
   fClipDistance4 = fClipDistance4_param;
   main_1();
-  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;
+  const main_out tint_symbol_8 = {glFragColor};
+  return tint_symbol_8;
 }
 
 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;
+  if (tint_discarded) {
+    discard;
+  }
   return wrapper_result;
 }
diff --git a/test/tint/bug/tint/1118.wgsl.expected.glsl b/test/tint/bug/tint/1118.wgsl.expected.glsl
index 7b0565a..671c869 100644
--- a/test/tint/bug/tint/1118.wgsl.expected.glsl
+++ b/test/tint/bug/tint/1118.wgsl.expected.glsl
@@ -1,6 +1,7 @@
 #version 310 es
 precision mediump float;
 
+bool tint_discarded = false;
 layout(location = 2) in float fClipDistance3_param_1;
 layout(location = 3) in float fClipDistance4_param_1;
 layout(location = 0) out vec4 glFragColor_1_1;
@@ -38,7 +39,6 @@
 } 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);
@@ -58,13 +58,11 @@
   vec4 color = vec4(0.0f, 0.0f, 0.0f, 0.0f);
   float x_9 = fClipDistance3;
   if ((x_9 > 0.0f)) {
-    tint_discard = true;
-    return;
+    tint_discarded = true;
   }
   float x_17 = fClipDistance4;
   if ((x_17 > 0.0f)) {
-    tint_discard = true;
-    return;
+    tint_discarded = true;
   }
   vec4 x_34 = x_29.inner.vEyePosition;
   vec3 x_38 = vec3(0.0f);
@@ -125,24 +123,15 @@
   fClipDistance3 = fClipDistance3_param;
   fClipDistance4 = fClipDistance4_param;
   main_1();
-  if (tint_discard) {
-    main_out tint_symbol_1 = main_out(vec4(0.0f));
-    return tint_symbol_1;
-  }
-  main_out tint_symbol_2 = main_out(glFragColor);
-  return tint_symbol_2;
-}
-
-void tint_discard_func() {
-  discard;
+  main_out tint_symbol_1 = main_out(glFragColor);
+  return tint_symbol_1;
 }
 
 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;
+  if (tint_discarded) {
+    discard;
+  }
   return;
 }
diff --git a/test/tint/bug/tint/1118.wgsl.expected.msl b/test/tint/bug/tint/1118.wgsl.expected.msl
index 5539c67..9dc50df 100644
--- a/test/tint/bug/tint/1118.wgsl.expected.msl
+++ b/test/tint/bug/tint/1118.wgsl.expected.msl
@@ -17,7 +17,7 @@
   /* 0x0000 */ float visibility;
 };
 
-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) {
+void main_1(thread float* const tint_symbol_5, thread bool* const tint_symbol_6, thread float* const tint_symbol_7, const constant Scene* const tint_symbol_8, const constant Material* const tint_symbol_9, const constant Mesh* const tint_symbol_10, thread float4* const tint_symbol_11) {
   float3 viewDirectionW = 0.0f;
   float4 baseColor = 0.0f;
   float3 diffuseColor = 0.0f;
@@ -34,23 +34,21 @@
   float3 finalDiffuse = 0.0f;
   float3 finalSpecular = 0.0f;
   float4 color = 0.0f;
-  float const x_9 = *(tint_symbol_7);
+  float const x_9 = *(tint_symbol_5);
   if ((x_9 > 0.0f)) {
-    *(tint_symbol_8) = true;
-    return;
+    *(tint_symbol_6) = true;
   }
-  float const x_17 = *(tint_symbol_9);
+  float const x_17 = *(tint_symbol_7);
   if ((x_17 > 0.0f)) {
-    *(tint_symbol_8) = true;
-    return;
+    *(tint_symbol_6) = true;
   }
-  float4 const x_34 = (*(tint_symbol_10)).vEyePosition;
+  float4 const x_34 = (*(tint_symbol_8)).vEyePosition;
   float3 const x_38 = float3(0.0f);
   viewDirectionW = normalize((float3(x_34[0], x_34[1], x_34[2]) - x_38));
   baseColor = float4(1.0f);
-  float4 const x_52 = (*(tint_symbol_11)).vDiffuseColor;
+  float4 const x_52 = (*(tint_symbol_9)).vDiffuseColor;
   diffuseColor = float3(x_52[0], x_52[1], x_52[2]);
-  float const x_60 = (*(tint_symbol_11)).vDiffuseColor[3];
+  float const x_60 = (*(tint_symbol_9)).vDiffuseColor[3];
   alpha = x_60;
   float3 const x_62 = float3(0.0f);
   float3 const x_64 = float3(0.0f);
@@ -66,12 +64,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 = float3((*(tint_symbol_11)).vEmissiveColor);
+  float3 const x_94 = float3((*(tint_symbol_9)).vEmissiveColor);
   emissiveColor = x_94;
   float3 const x_96 = diffuseBase;
   float3 const x_97 = diffuseColor;
   float3 const x_99 = emissiveColor;
-  float3 const x_103 = float3((*(tint_symbol_11)).vAmbientColor);
+  float3 const x_103 = float3((*(tint_symbol_9)).vAmbientColor);
   float4 const x_108 = baseColor;
   finalDiffuse = (clamp((((x_96 * x_97) + x_99) + x_103), float3(0.0f), float3(1.0f)) * float3(x_108[0], x_108[1], x_108[2]));
   finalSpecular = float3(0.0f);
@@ -87,11 +85,11 @@
   float3 const x_132 = fmax(float3(x_129[0], x_129[1], x_129[2]), float3(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_12)).visibility;
+  float const x_140 = (*(tint_symbol_10)).visibility;
   float const x_142 = color[3];
   color[3] = (x_142 * x_140);
   float4 const x_147 = color;
-  *(tint_symbol_13) = x_147;
+  *(tint_symbol_11) = x_147;
   return;
 }
 
@@ -108,35 +106,25 @@
   float4 glFragColor_1 [[color(0)]];
 };
 
-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 = main_out{};
-    return tint_symbol_4;
-  }
-  main_out const tint_symbol_5 = {.glFragColor_1=*(tint_symbol_20)};
-  return tint_symbol_5;
+main_out tint_symbol_inner(float fClipDistance3_param, float fClipDistance4_param, thread float* const tint_symbol_12, thread float* const tint_symbol_13, thread bool* const tint_symbol_14, const constant Scene* const tint_symbol_15, const constant Material* const tint_symbol_16, const constant Mesh* const tint_symbol_17, thread float4* const tint_symbol_18) {
+  *(tint_symbol_12) = fClipDistance3_param;
+  *(tint_symbol_13) = fClipDistance4_param;
+  main_1(tint_symbol_12, tint_symbol_14, tint_symbol_13, tint_symbol_15, tint_symbol_16, tint_symbol_17, tint_symbol_18);
+  main_out const tint_symbol_4 = {.glFragColor_1=*(tint_symbol_18)};
+  return tint_symbol_4;
 }
 
-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 = tint_symbol_3{};
-    return tint_symbol_6;
-  }
+fragment tint_symbol_3 tint_symbol(const constant Scene* tint_symbol_22 [[buffer(0)]], const constant Material* tint_symbol_23 [[buffer(1)]], const constant Mesh* tint_symbol_24 [[buffer(2)]], tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+  thread float tint_symbol_19 = 0.0f;
+  thread float tint_symbol_20 = 0.0f;
+  thread bool tint_symbol_21 = false;
+  thread float4 tint_symbol_25 = 0.0f;
+  main_out const inner_result = tint_symbol_inner(tint_symbol_1.fClipDistance3_param, tint_symbol_1.fClipDistance4_param, &(tint_symbol_19), &(tint_symbol_20), &(tint_symbol_21), tint_symbol_22, tint_symbol_23, tint_symbol_24, &(tint_symbol_25));
   tint_symbol_3 wrapper_result = {};
   wrapper_result.glFragColor_1 = inner_result.glFragColor_1;
+  if (tint_symbol_21) {
+    discard_fragment();
+  }
   return wrapper_result;
 }
 
diff --git a/test/tint/bug/tint/1118.wgsl.expected.spvasm b/test/tint/bug/tint/1118.wgsl.expected.spvasm
index bde22d6..5fb873a 100644
--- a/test/tint/bug/tint/1118.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/1118.wgsl.expected.spvasm
@@ -1,13 +1,14 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 202
+; Bound: 188
 ; Schema: 0
                OpCapability Shader
-         %84 = OpExtInstImport "GLSL.std.450"
+         %74 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
                OpEntryPoint Fragment %main "main" %fClipDistance3_param_1 %fClipDistance4_param_1 %glFragColor_1_1
                OpExecutionMode %main OriginUpperLeft
+               OpName %tint_discarded "tint_discarded"
                OpName %fClipDistance3_param_1 "fClipDistance3_param_1"
                OpName %fClipDistance4_param_1 "fClipDistance4_param_1"
                OpName %glFragColor_1_1 "glFragColor_1_1"
@@ -33,9 +34,7 @@
                OpMemberName %Mesh 0 "visibility"
                OpName %x_137 "x_137"
                OpName %glFragColor "glFragColor"
-               OpName %tint_discard "tint_discard"
                OpName %main_1 "main_1"
-               OpName %tint_return_flag "tint_return_flag"
                OpName %viewDirectionW "viewDirectionW"
                OpName %baseColor "baseColor"
                OpName %diffuseColor "diffuseColor"
@@ -52,7 +51,6 @@
                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"
@@ -85,18 +83,22 @@
                OpDecorate %x_137 DescriptorSet 0
                OpDecorate %x_137 Binding 2
                OpMemberDecorate %main_out 0 Offset 0
+       %bool = OpTypeBool
+          %2 = OpConstantNull %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discarded = OpVariable %_ptr_Private_bool Private %2
       %float = OpTypeFloat 32
 %_ptr_Input_float = OpTypePointer Input %float
 %fClipDistance3_param_1 = OpVariable %_ptr_Input_float Input
 %fClipDistance4_param_1 = OpVariable %_ptr_Input_float Input
     %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
-          %8 = OpConstantNull %v4float
-%glFragColor_1_1 = OpVariable %_ptr_Output_v4float Output %8
+         %12 = OpConstantNull %v4float
+%glFragColor_1_1 = OpVariable %_ptr_Output_v4float Output %12
 %_ptr_Private_float = OpTypePointer Private %float
-         %11 = OpConstantNull %float
-%fClipDistance3 = OpVariable %_ptr_Private_float Private %11
-%fClipDistance4 = OpVariable %_ptr_Private_float Private %11
+         %15 = OpConstantNull %float
+%fClipDistance3 = OpVariable %_ptr_Private_float Private %15
+%fClipDistance4 = OpVariable %_ptr_Private_float Private %15
       %Scene = OpTypeStruct %v4float
  %x_29_block = OpTypeStruct %Scene
 %_ptr_Uniform_x_29_block = OpTypePointer Uniform %x_29_block
@@ -111,227 +113,198 @@
 %_ptr_Uniform_x_137_block = OpTypePointer Uniform %x_137_block
       %x_137 = OpVariable %_ptr_Uniform_x_137_block Uniform
 %_ptr_Private_v4float = OpTypePointer Private %v4float
-%glFragColor = OpVariable %_ptr_Private_v4float Private %8
-       %bool = OpTypeBool
-         %29 = OpConstantNull %bool
-%_ptr_Private_bool = OpTypePointer Private %bool
-%tint_discard = OpVariable %_ptr_Private_bool Private %29
+%glFragColor = OpVariable %_ptr_Private_v4float Private %12
        %void = OpTypeVoid
          %32 = OpTypeFunction %void
-%_ptr_Function_bool = OpTypePointer Function %bool
 %_ptr_Function_v3float = OpTypePointer Function %v3float
-         %40 = OpConstantNull %v3float
+         %38 = OpConstantNull %v3float
 %_ptr_Function_v4float = OpTypePointer Function %v4float
 %_ptr_Function_float = OpTypePointer Function %float
     %v2float = OpTypeVector %float 2
 %_ptr_Function_v2float = OpTypePointer Function %v2float
-         %50 = OpConstantNull %v2float
+         %48 = OpConstantNull %v2float
        %true = OpConstantTrue %bool
        %uint = OpTypeInt 32 0
      %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
     %float_1 = OpConstant %float 1
-         %91 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+         %81 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
      %uint_3 = OpConstant %uint 3
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-        %118 = OpConstantComposite %v3float %float_1 %float_1 %float_1
-        %119 = OpConstantComposite %v4float %11 %11 %11 %float_1
+        %108 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+        %109 = OpConstantComposite %v4float %15 %15 %15 %float_1
 %_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
      %uint_1 = OpConstant %uint 1
    %main_out = OpTypeStruct %v4float
-        %182 = OpTypeFunction %main_out %float %float
-        %193 = OpConstantNull %main_out
+        %170 = OpTypeFunction %main_out %float %float
      %main_1 = OpFunction %void None %32
          %35 = OpLabel
-%tint_return_flag = OpVariable %_ptr_Function_bool Function %29
-%viewDirectionW = OpVariable %_ptr_Function_v3float Function %40
-  %baseColor = OpVariable %_ptr_Function_v4float Function %8
-%diffuseColor = OpVariable %_ptr_Function_v3float Function %40
-      %alpha = OpVariable %_ptr_Function_float Function %11
-    %normalW = OpVariable %_ptr_Function_v3float Function %40
-   %uvOffset = OpVariable %_ptr_Function_v2float Function %50
-%baseAmbientColor = OpVariable %_ptr_Function_v3float Function %40
- %glossiness = OpVariable %_ptr_Function_float Function %11
-%diffuseBase = OpVariable %_ptr_Function_v3float Function %40
-     %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 %40
-%finalDiffuse = OpVariable %_ptr_Function_v3float Function %40
-%finalSpecular = OpVariable %_ptr_Function_v3float Function %40
-      %color = OpVariable %_ptr_Function_v4float Function %8
-         %61 = OpLoad %float %fClipDistance3
-         %62 = OpFOrdGreaterThan %bool %61 %11
-               OpSelectionMerge %63 None
-               OpBranchConditional %62 %64 %63
-         %64 = OpLabel
-               OpStore %tint_discard %true
-               OpStore %tint_return_flag %true
-               OpBranch %63
-         %63 = OpLabel
-         %67 = OpLoad %bool %tint_return_flag
-         %66 = OpLogicalNot %bool %67
-               OpSelectionMerge %68 None
-               OpBranchConditional %66 %69 %68
-         %69 = OpLabel
-         %70 = OpLoad %float %fClipDistance4
-         %71 = OpFOrdGreaterThan %bool %70 %11
-               OpSelectionMerge %72 None
-               OpBranchConditional %71 %73 %72
-         %73 = OpLabel
-               OpStore %tint_discard %true
-               OpStore %tint_return_flag %true
-               OpBranch %72
-         %72 = OpLabel
-         %75 = OpLoad %bool %tint_return_flag
-         %74 = OpLogicalNot %bool %75
-               OpSelectionMerge %76 None
-               OpBranchConditional %74 %77 %76
-         %77 = OpLabel
-         %81 = OpAccessChain %_ptr_Uniform_v4float %x_29 %uint_0 %uint_0
-         %82 = OpLoad %v4float %81
-         %85 = OpCompositeExtract %float %82 0
-         %86 = OpCompositeExtract %float %82 1
-         %87 = OpCompositeExtract %float %82 2
-         %88 = OpCompositeConstruct %v3float %85 %86 %87
-         %89 = OpFSub %v3float %88 %40
-         %83 = OpExtInst %v3float %84 Normalize %89
-               OpStore %viewDirectionW %83
-               OpStore %baseColor %91
-         %92 = OpAccessChain %_ptr_Uniform_v4float %x_49 %uint_0 %uint_0
-         %93 = OpLoad %v4float %92
-         %94 = OpCompositeExtract %float %93 0
-         %95 = OpCompositeExtract %float %93 1
-         %96 = OpCompositeExtract %float %93 2
-         %97 = OpCompositeConstruct %v3float %94 %95 %96
-               OpStore %diffuseColor %97
-        %100 = OpAccessChain %_ptr_Uniform_float %x_49 %uint_0 %uint_0 %uint_3
-        %101 = OpLoad %float %100
-               OpStore %alpha %101
-               OpStore %uvOffset %50
+%viewDirectionW = OpVariable %_ptr_Function_v3float Function %38
+  %baseColor = OpVariable %_ptr_Function_v4float Function %12
+%diffuseColor = OpVariable %_ptr_Function_v3float Function %38
+      %alpha = OpVariable %_ptr_Function_float Function %15
+    %normalW = OpVariable %_ptr_Function_v3float Function %38
+   %uvOffset = OpVariable %_ptr_Function_v2float Function %48
+%baseAmbientColor = OpVariable %_ptr_Function_v3float Function %38
+ %glossiness = OpVariable %_ptr_Function_float Function %15
+%diffuseBase = OpVariable %_ptr_Function_v3float Function %38
+     %shadow = OpVariable %_ptr_Function_float Function %15
+%refractionColor = OpVariable %_ptr_Function_v4float Function %12
+%reflectionColor = OpVariable %_ptr_Function_v4float Function %12
+%emissiveColor = OpVariable %_ptr_Function_v3float Function %38
+%finalDiffuse = OpVariable %_ptr_Function_v3float Function %38
+%finalSpecular = OpVariable %_ptr_Function_v3float Function %38
+      %color = OpVariable %_ptr_Function_v4float Function %12
+         %59 = OpLoad %float %fClipDistance3
+         %60 = OpFOrdGreaterThan %bool %59 %15
+               OpSelectionMerge %61 None
+               OpBranchConditional %60 %62 %61
+         %62 = OpLabel
+               OpStore %tint_discarded %true
+               OpBranch %61
+         %61 = OpLabel
+         %64 = OpLoad %float %fClipDistance4
+         %65 = OpFOrdGreaterThan %bool %64 %15
+               OpSelectionMerge %66 None
+               OpBranchConditional %65 %67 %66
+         %67 = OpLabel
+               OpStore %tint_discarded %true
+               OpBranch %66
+         %66 = OpLabel
+         %71 = OpAccessChain %_ptr_Uniform_v4float %x_29 %uint_0 %uint_0
+         %72 = OpLoad %v4float %71
+         %75 = OpCompositeExtract %float %72 0
+         %76 = OpCompositeExtract %float %72 1
+         %77 = OpCompositeExtract %float %72 2
+         %78 = OpCompositeConstruct %v3float %75 %76 %77
+         %79 = OpFSub %v3float %78 %38
+         %73 = OpExtInst %v3float %74 Normalize %79
+               OpStore %viewDirectionW %73
+               OpStore %baseColor %81
+         %82 = OpAccessChain %_ptr_Uniform_v4float %x_49 %uint_0 %uint_0
+         %83 = OpLoad %v4float %82
+         %84 = OpCompositeExtract %float %83 0
+         %85 = OpCompositeExtract %float %83 1
+         %86 = OpCompositeExtract %float %83 2
+         %87 = OpCompositeConstruct %v3float %84 %85 %86
+               OpStore %diffuseColor %87
+         %90 = OpAccessChain %_ptr_Uniform_float %x_49 %uint_0 %uint_0 %uint_3
+         %91 = OpLoad %float %90
+               OpStore %alpha %91
+               OpStore %uvOffset %48
+         %92 = OpLoad %v4float %baseColor
+         %93 = OpCompositeExtract %float %92 0
+         %94 = OpCompositeExtract %float %92 1
+         %95 = OpCompositeExtract %float %92 2
+         %96 = OpCompositeConstruct %v3float %93 %94 %95
+         %97 = OpCompositeExtract %float %12 0
+         %98 = OpCompositeExtract %float %12 1
+         %99 = OpCompositeExtract %float %12 2
+        %100 = OpCompositeConstruct %v3float %97 %98 %99
+        %101 = OpFMul %v3float %96 %100
         %102 = OpLoad %v4float %baseColor
-        %103 = OpCompositeExtract %float %102 0
-        %104 = OpCompositeExtract %float %102 1
-        %105 = OpCompositeExtract %float %102 2
-        %106 = OpCompositeConstruct %v3float %103 %104 %105
-        %107 = OpCompositeExtract %float %8 0
-        %108 = OpCompositeExtract %float %8 1
-        %109 = OpCompositeExtract %float %8 2
-        %110 = OpCompositeConstruct %v3float %107 %108 %109
-        %111 = OpFMul %v3float %106 %110
-        %112 = OpLoad %v4float %baseColor
-        %113 = OpCompositeExtract %float %111 0
-        %114 = OpCompositeExtract %float %111 1
-        %115 = OpCompositeExtract %float %111 2
-        %116 = OpCompositeExtract %float %112 3
-        %117 = OpCompositeConstruct %v4float %113 %114 %115 %116
-               OpStore %baseColor %117
-               OpStore %baseAmbientColor %118
-               OpStore %glossiness %11
-               OpStore %diffuseBase %40
+        %103 = OpCompositeExtract %float %101 0
+        %104 = OpCompositeExtract %float %101 1
+        %105 = OpCompositeExtract %float %101 2
+        %106 = OpCompositeExtract %float %102 3
+        %107 = OpCompositeConstruct %v4float %103 %104 %105 %106
+               OpStore %baseColor %107
+               OpStore %baseAmbientColor %108
+               OpStore %glossiness %15
+               OpStore %diffuseBase %38
                OpStore %shadow %float_1
-               OpStore %refractionColor %119
-               OpStore %reflectionColor %119
-        %121 = OpAccessChain %_ptr_Uniform_v3float %x_49 %uint_0 %uint_3
-        %122 = OpLoad %v3float %121
-               OpStore %emissiveColor %122
-        %123 = OpLoad %v3float %diffuseBase
-        %124 = OpLoad %v3float %diffuseColor
-        %125 = OpLoad %v3float %emissiveColor
-        %127 = OpAccessChain %_ptr_Uniform_v3float %x_49 %uint_0 %uint_1
-        %128 = OpLoad %v3float %127
-        %129 = OpLoad %v4float %baseColor
-        %131 = OpFMul %v3float %123 %124
-        %132 = OpFAdd %v3float %131 %125
-        %133 = OpFAdd %v3float %132 %128
-        %130 = OpExtInst %v3float %84 NClamp %133 %40 %118
-        %134 = OpCompositeExtract %float %129 0
-        %135 = OpCompositeExtract %float %129 1
-        %136 = OpCompositeExtract %float %129 2
-        %137 = OpCompositeConstruct %v3float %134 %135 %136
-        %138 = OpFMul %v3float %130 %137
-               OpStore %finalDiffuse %138
-               OpStore %finalSpecular %40
-        %139 = OpLoad %v3float %finalDiffuse
-        %140 = OpLoad %v3float %baseAmbientColor
-        %141 = OpLoad %v3float %finalSpecular
-        %142 = OpLoad %v4float %reflectionColor
-        %143 = OpLoad %v4float %refractionColor
-        %144 = OpFMul %v3float %139 %140
-        %145 = OpFAdd %v3float %144 %141
-        %146 = OpCompositeExtract %float %142 0
-        %147 = OpCompositeExtract %float %142 1
-        %148 = OpCompositeExtract %float %142 2
-        %149 = OpCompositeConstruct %v3float %146 %147 %148
-        %150 = OpFAdd %v3float %145 %149
-        %151 = OpCompositeExtract %float %143 0
-        %152 = OpCompositeExtract %float %143 1
-        %153 = OpCompositeExtract %float %143 2
-        %154 = OpCompositeConstruct %v3float %151 %152 %153
-        %155 = OpFAdd %v3float %150 %154
-        %156 = OpLoad %float %alpha
-        %157 = OpCompositeExtract %float %155 0
-        %158 = OpCompositeExtract %float %155 1
-        %159 = OpCompositeExtract %float %155 2
-        %160 = OpCompositeConstruct %v4float %157 %158 %159 %156
-               OpStore %color %160
-        %161 = OpLoad %v4float %color
-        %163 = OpCompositeExtract %float %161 0
-        %164 = OpCompositeExtract %float %161 1
-        %165 = OpCompositeExtract %float %161 2
-        %166 = OpCompositeConstruct %v3float %163 %164 %165
-        %162 = OpExtInst %v3float %84 NMax %166 %40
-        %167 = OpLoad %v4float %color
-        %168 = OpCompositeExtract %float %162 0
-        %169 = OpCompositeExtract %float %162 1
-        %170 = OpCompositeExtract %float %162 2
-        %171 = OpCompositeExtract %float %167 3
-        %172 = OpCompositeConstruct %v4float %168 %169 %170 %171
-               OpStore %color %172
-        %173 = OpAccessChain %_ptr_Uniform_float %x_137 %uint_0 %uint_0
-        %174 = OpLoad %float %173
-        %175 = OpAccessChain %_ptr_Function_float %color %uint_3
-        %176 = OpLoad %float %175
-        %177 = OpAccessChain %_ptr_Function_float %color %uint_3
-        %178 = OpFMul %float %176 %174
-               OpStore %177 %178
-        %179 = OpLoad %v4float %color
-               OpStore %glFragColor %179
-               OpStore %tint_return_flag %true
-               OpBranch %76
-         %76 = OpLabel
-               OpBranch %68
-         %68 = OpLabel
+               OpStore %refractionColor %109
+               OpStore %reflectionColor %109
+        %111 = OpAccessChain %_ptr_Uniform_v3float %x_49 %uint_0 %uint_3
+        %112 = OpLoad %v3float %111
+               OpStore %emissiveColor %112
+        %113 = OpLoad %v3float %diffuseBase
+        %114 = OpLoad %v3float %diffuseColor
+        %115 = OpLoad %v3float %emissiveColor
+        %117 = OpAccessChain %_ptr_Uniform_v3float %x_49 %uint_0 %uint_1
+        %118 = OpLoad %v3float %117
+        %119 = OpLoad %v4float %baseColor
+        %121 = OpFMul %v3float %113 %114
+        %122 = OpFAdd %v3float %121 %115
+        %123 = OpFAdd %v3float %122 %118
+        %120 = OpExtInst %v3float %74 NClamp %123 %38 %108
+        %124 = OpCompositeExtract %float %119 0
+        %125 = OpCompositeExtract %float %119 1
+        %126 = OpCompositeExtract %float %119 2
+        %127 = OpCompositeConstruct %v3float %124 %125 %126
+        %128 = OpFMul %v3float %120 %127
+               OpStore %finalDiffuse %128
+               OpStore %finalSpecular %38
+        %129 = OpLoad %v3float %finalDiffuse
+        %130 = OpLoad %v3float %baseAmbientColor
+        %131 = OpLoad %v3float %finalSpecular
+        %132 = OpLoad %v4float %reflectionColor
+        %133 = OpLoad %v4float %refractionColor
+        %134 = OpFMul %v3float %129 %130
+        %135 = OpFAdd %v3float %134 %131
+        %136 = OpCompositeExtract %float %132 0
+        %137 = OpCompositeExtract %float %132 1
+        %138 = OpCompositeExtract %float %132 2
+        %139 = OpCompositeConstruct %v3float %136 %137 %138
+        %140 = OpFAdd %v3float %135 %139
+        %141 = OpCompositeExtract %float %133 0
+        %142 = OpCompositeExtract %float %133 1
+        %143 = OpCompositeExtract %float %133 2
+        %144 = OpCompositeConstruct %v3float %141 %142 %143
+        %145 = OpFAdd %v3float %140 %144
+        %146 = OpLoad %float %alpha
+        %147 = OpCompositeExtract %float %145 0
+        %148 = OpCompositeExtract %float %145 1
+        %149 = OpCompositeExtract %float %145 2
+        %150 = OpCompositeConstruct %v4float %147 %148 %149 %146
+               OpStore %color %150
+        %151 = OpLoad %v4float %color
+        %153 = OpCompositeExtract %float %151 0
+        %154 = OpCompositeExtract %float %151 1
+        %155 = OpCompositeExtract %float %151 2
+        %156 = OpCompositeConstruct %v3float %153 %154 %155
+        %152 = OpExtInst %v3float %74 NMax %156 %38
+        %157 = OpLoad %v4float %color
+        %158 = OpCompositeExtract %float %152 0
+        %159 = OpCompositeExtract %float %152 1
+        %160 = OpCompositeExtract %float %152 2
+        %161 = OpCompositeExtract %float %157 3
+        %162 = OpCompositeConstruct %v4float %158 %159 %160 %161
+               OpStore %color %162
+        %163 = OpAccessChain %_ptr_Uniform_float %x_137 %uint_0 %uint_0
+        %164 = OpLoad %float %163
+        %165 = OpAccessChain %_ptr_Function_float %color %uint_3
+        %166 = OpLoad %float %165
+        %167 = OpAccessChain %_ptr_Function_float %color %uint_3
+        %168 = OpFMul %float %166 %164
+               OpStore %167 %168
+        %169 = OpLoad %v4float %color
+               OpStore %glFragColor %169
                OpReturn
                OpFunctionEnd
-%tint_discard_func = OpFunction %void None %32
-        %181 = OpLabel
-               OpKill
-               OpFunctionEnd
- %main_inner = OpFunction %main_out None %182
+ %main_inner = OpFunction %main_out None %170
 %fClipDistance3_param = OpFunctionParameter %float
 %fClipDistance4_param = OpFunctionParameter %float
-        %187 = OpLabel
+        %175 = OpLabel
                OpStore %fClipDistance3 %fClipDistance3_param
                OpStore %fClipDistance4 %fClipDistance4_param
-        %188 = OpFunctionCall %void %main_1
-        %189 = OpLoad %bool %tint_discard
-               OpSelectionMerge %190 None
-               OpBranchConditional %189 %191 %190
-        %191 = OpLabel
-        %192 = OpFunctionCall %void %tint_discard_func
-               OpReturnValue %193
-        %190 = OpLabel
-        %194 = OpLoad %v4float %glFragColor
-        %195 = OpCompositeConstruct %main_out %194
-               OpReturnValue %195
+        %176 = OpFunctionCall %void %main_1
+        %177 = OpLoad %v4float %glFragColor
+        %178 = OpCompositeConstruct %main_out %177
+               OpReturnValue %178
                OpFunctionEnd
        %main = OpFunction %void None %32
-        %197 = OpLabel
-        %199 = OpLoad %float %fClipDistance3_param_1
-        %200 = OpLoad %float %fClipDistance4_param_1
-        %198 = OpFunctionCall %main_out %main_inner %199 %200
-        %201 = OpCompositeExtract %v4float %198 0
-               OpStore %glFragColor_1_1 %201
+        %180 = OpLabel
+        %182 = OpLoad %float %fClipDistance3_param_1
+        %183 = OpLoad %float %fClipDistance4_param_1
+        %181 = OpFunctionCall %main_out %main_inner %182 %183
+        %184 = OpCompositeExtract %v4float %181 0
+               OpStore %glFragColor_1_1 %184
+        %185 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %186 None
+               OpBranchConditional %185 %187 %186
+        %187 = OpLabel
+               OpKill
+        %186 = OpLabel
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/1369.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/1369.wgsl.expected.dxc.hlsl
index 0981f38..dde30f9 100644
--- a/test/tint/bug/tint/1369.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/1369.wgsl.expected.dxc.hlsl
@@ -1,29 +1,15 @@
-bug/tint/1369.wgsl:3:3 warning: code is unreachable
-  return true;
-  ^^^^^^
-
-bug/tint/1369.wgsl:9:5 warning: code is unreachable
-    var also_unreachable : bool;
-    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-static bool tint_discard = false;
+static bool tint_discarded = false;
 
 bool call_discard() {
-  tint_discard = true;
-  return false;
+  tint_discarded = true;
   return true;
 }
 
-void tint_discard_func() {
-  discard;
-}
-
 void f() {
   bool v = call_discard();
-  if (tint_discard) {
-    tint_discard_func();
-    return;
-  }
   bool also_unreachable = false;
+  if (tint_discarded) {
+    discard;
+  }
   return;
 }
diff --git a/test/tint/bug/tint/1369.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/1369.wgsl.expected.fxc.hlsl
index 0981f38..dde30f9 100644
--- a/test/tint/bug/tint/1369.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/1369.wgsl.expected.fxc.hlsl
@@ -1,29 +1,15 @@
-bug/tint/1369.wgsl:3:3 warning: code is unreachable
-  return true;
-  ^^^^^^
-
-bug/tint/1369.wgsl:9:5 warning: code is unreachable
-    var also_unreachable : bool;
-    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-static bool tint_discard = false;
+static bool tint_discarded = false;
 
 bool call_discard() {
-  tint_discard = true;
-  return false;
+  tint_discarded = true;
   return true;
 }
 
-void tint_discard_func() {
-  discard;
-}
-
 void f() {
   bool v = call_discard();
-  if (tint_discard) {
-    tint_discard_func();
-    return;
-  }
   bool also_unreachable = false;
+  if (tint_discarded) {
+    discard;
+  }
   return;
 }
diff --git a/test/tint/bug/tint/1369.wgsl.expected.glsl b/test/tint/bug/tint/1369.wgsl.expected.glsl
index 82b1904..e288349 100644
--- a/test/tint/bug/tint/1369.wgsl.expected.glsl
+++ b/test/tint/bug/tint/1369.wgsl.expected.glsl
@@ -1,38 +1,21 @@
-bug/tint/1369.wgsl:3:3 warning: code is unreachable
-  return true;
-  ^^^^^^
-
-bug/tint/1369.wgsl:9:5 warning: code is unreachable
-    var also_unreachable : bool;
-    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 #version 310 es
 precision mediump float;
 
-bool tint_discard = false;
+bool tint_discarded = false;
 bool call_discard() {
-  tint_discard = true;
-  return false;
+  tint_discarded = true;
   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;
+  if (tint_discarded) {
+    discard;
   }
   return;
 }
diff --git a/test/tint/bug/tint/1369.wgsl.expected.msl b/test/tint/bug/tint/1369.wgsl.expected.msl
index 32624c3..8793220 100644
--- a/test/tint/bug/tint/1369.wgsl.expected.msl
+++ b/test/tint/bug/tint/1369.wgsl.expected.msl
@@ -1,32 +1,18 @@
-bug/tint/1369.wgsl:3:3 warning: code is unreachable
-  return true;
-  ^^^^^^
-
-bug/tint/1369.wgsl:9:5 warning: code is unreachable
-    var also_unreachable : bool;
-    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 #include <metal_stdlib>
 
 using namespace metal;
 bool call_discard(thread bool* const tint_symbol) {
   *(tint_symbol) = true;
-  return false;
   return true;
 }
 
-void tint_discard_func() {
-  discard_fragment();
-}
-
 fragment void f() {
   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;
+  if (tint_symbol_1) {
+    discard_fragment();
+  }
   return;
 }
 
diff --git a/test/tint/bug/tint/1369.wgsl.expected.spvasm b/test/tint/bug/tint/1369.wgsl.expected.spvasm
index 803df82..6d26689 100644
--- a/test/tint/bug/tint/1369.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/1369.wgsl.expected.spvasm
@@ -1,29 +1,21 @@
-bug/tint/1369.wgsl:3:3 warning: code is unreachable
-  return true;
-  ^^^^^^
-
-bug/tint/1369.wgsl:9:5 warning: code is unreachable
-    var also_unreachable : bool;
-    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 22
+; Bound: 20
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint Fragment %f "f"
                OpExecutionMode %f OriginUpperLeft
-               OpName %tint_discard "tint_discard"
+               OpName %tint_discarded "tint_discarded"
                OpName %call_discard "call_discard"
-               OpName %tint_discard_func "tint_discard_func"
                OpName %f "f"
                OpName %v "v"
+               OpName %also_unreachable "also_unreachable"
        %bool = OpTypeBool
           %2 = OpConstantNull %bool
 %_ptr_Private_bool = OpTypePointer Private %bool
-%tint_discard = OpVariable %_ptr_Private_bool Private %2
+%tint_discarded = OpVariable %_ptr_Private_bool Private %2
           %5 = OpTypeFunction %bool
        %true = OpConstantTrue %bool
        %void = OpTypeVoid
@@ -31,24 +23,20 @@
 %_ptr_Function_bool = OpTypePointer Function %bool
 %call_discard = OpFunction %bool None %5
           %7 = OpLabel
-               OpStore %tint_discard %true
-               OpReturnValue %2
-               OpFunctionEnd
-%tint_discard_func = OpFunction %void None %9
-         %12 = OpLabel
-               OpKill
+               OpStore %tint_discarded %true
+               OpReturnValue %true
                OpFunctionEnd
           %f = OpFunction %void None %9
-         %14 = OpLabel
+         %12 = OpLabel
           %v = OpVariable %_ptr_Function_bool Function %2
-         %15 = OpFunctionCall %bool %call_discard
-               OpStore %v %15
-         %18 = OpLoad %bool %tint_discard
-               OpSelectionMerge %19 None
-               OpBranchConditional %18 %20 %19
-         %20 = OpLabel
-         %21 = OpFunctionCall %void %tint_discard_func
-               OpReturn
+%also_unreachable = OpVariable %_ptr_Function_bool Function %2
+         %13 = OpFunctionCall %bool %call_discard
+               OpStore %v %13
+         %17 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %18 None
+               OpBranchConditional %17 %19 %18
          %19 = OpLabel
+               OpKill
+         %18 = OpLabel
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/1369.wgsl.expected.wgsl b/test/tint/bug/tint/1369.wgsl.expected.wgsl
index 5b3ca83..c327510 100644
--- a/test/tint/bug/tint/1369.wgsl.expected.wgsl
+++ b/test/tint/bug/tint/1369.wgsl.expected.wgsl
@@ -1,11 +1,3 @@
-bug/tint/1369.wgsl:3:3 warning: code is unreachable
-  return true;
-  ^^^^^^
-
-bug/tint/1369.wgsl:9:5 warning: code is unreachable
-    var also_unreachable : bool;
-    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 fn call_discard() -> bool {
   discard;
   return true;
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl
new file mode 100644
index 0000000..325a019
--- /dev/null
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl
@@ -0,0 +1,17 @@
+@group(0) @binding(0) var t : texture_2d<f32>;
+
+@group(0) @binding(1) var s : sampler;
+
+@group(0) @binding(2) var<storage, read_write> a : atomic<i32>;
+
+@fragment
+fn foo(@location(0) in : f32, @location(1) coord : vec2<f32>) -> @location(0) i32 {
+  if (in == 0.0) {
+    discard;
+  }
+  var result = i32(textureSample(t, s, coord).x);
+  for (var i = 0; i < 10; i = atomicAdd(&a, 1)) {
+    result += i;
+  }
+  return result;
+}
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.dxc.hlsl b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..44d8b38
--- /dev/null
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.dxc.hlsl
@@ -0,0 +1,55 @@
+static bool tint_discarded = false;
+Texture2D<float4> t : register(t0, space0);
+SamplerState s : register(s1, space0);
+RWByteAddressBuffer a : register(u2, space0);
+
+struct tint_symbol_2 {
+  float tint_symbol : TEXCOORD0;
+  float2 coord : TEXCOORD1;
+};
+struct tint_symbol_3 {
+  int value : SV_Target0;
+};
+
+int tint_atomicAdd(RWByteAddressBuffer buffer, uint offset, int value) {
+  int original_value = 0;
+  buffer.InterlockedAdd(offset, value, original_value);
+  return original_value;
+}
+
+
+int foo_inner(float tint_symbol, float2 coord) {
+  if ((tint_symbol == 0.0f)) {
+    tint_discarded = true;
+  }
+  int result = int(t.Sample(s, coord).x);
+  {
+    int i = 0;
+    while (true) {
+      if (!((i < 10))) {
+        break;
+      }
+      {
+        result = (result + i);
+      }
+      {
+        int tint_symbol_4 = 0;
+        if (!(tint_discarded)) {
+          tint_symbol_4 = tint_atomicAdd(a, 0u, 1);
+        }
+        i = tint_symbol_4;
+      }
+    }
+  }
+  return result;
+}
+
+tint_symbol_3 foo(tint_symbol_2 tint_symbol_1) {
+  const int inner_result = foo_inner(tint_symbol_1.tint_symbol, tint_symbol_1.coord);
+  tint_symbol_3 wrapper_result = (tint_symbol_3)0;
+  wrapper_result.value = inner_result;
+  if (tint_discarded) {
+    discard;
+  }
+  return wrapper_result;
+}
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.fxc.hlsl b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..44d8b38
--- /dev/null
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.fxc.hlsl
@@ -0,0 +1,55 @@
+static bool tint_discarded = false;
+Texture2D<float4> t : register(t0, space0);
+SamplerState s : register(s1, space0);
+RWByteAddressBuffer a : register(u2, space0);
+
+struct tint_symbol_2 {
+  float tint_symbol : TEXCOORD0;
+  float2 coord : TEXCOORD1;
+};
+struct tint_symbol_3 {
+  int value : SV_Target0;
+};
+
+int tint_atomicAdd(RWByteAddressBuffer buffer, uint offset, int value) {
+  int original_value = 0;
+  buffer.InterlockedAdd(offset, value, original_value);
+  return original_value;
+}
+
+
+int foo_inner(float tint_symbol, float2 coord) {
+  if ((tint_symbol == 0.0f)) {
+    tint_discarded = true;
+  }
+  int result = int(t.Sample(s, coord).x);
+  {
+    int i = 0;
+    while (true) {
+      if (!((i < 10))) {
+        break;
+      }
+      {
+        result = (result + i);
+      }
+      {
+        int tint_symbol_4 = 0;
+        if (!(tint_discarded)) {
+          tint_symbol_4 = tint_atomicAdd(a, 0u, 1);
+        }
+        i = tint_symbol_4;
+      }
+    }
+  }
+  return result;
+}
+
+tint_symbol_3 foo(tint_symbol_2 tint_symbol_1) {
+  const int inner_result = foo_inner(tint_symbol_1.tint_symbol, tint_symbol_1.coord);
+  tint_symbol_3 wrapper_result = (tint_symbol_3)0;
+  wrapper_result.value = inner_result;
+  if (tint_discarded) {
+    discard;
+  }
+  return wrapper_result;
+}
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.glsl b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.glsl
new file mode 100644
index 0000000..3af238a
--- /dev/null
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.glsl
@@ -0,0 +1,47 @@
+#version 310 es
+precision mediump float;
+
+bool tint_discarded = false;
+layout(location = 0) in float tint_symbol_1;
+layout(location = 1) in vec2 coord_1;
+layout(location = 0) out int value;
+layout(binding = 2, std430) buffer a_block_ssbo {
+  int inner;
+} a;
+
+uniform highp sampler2D t_s;
+
+int foo(float tint_symbol, vec2 coord) {
+  if ((tint_symbol == 0.0f)) {
+    tint_discarded = true;
+  }
+  int result = int(texture(t_s, coord).x);
+  {
+    int i = 0;
+    while (true) {
+      if (!((i < 10))) {
+        break;
+      }
+      {
+        result = (result + i);
+      }
+      {
+        int tint_symbol_2 = 0;
+        if (!(tint_discarded)) {
+          tint_symbol_2 = atomicAdd(a.inner, 1);
+        }
+        i = tint_symbol_2;
+      }
+    }
+  }
+  return result;
+}
+
+void main() {
+  int inner_result = foo(tint_symbol_1, coord_1);
+  value = inner_result;
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.msl b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.msl
new file mode 100644
index 0000000..1da2b90
--- /dev/null
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_1 {
+  float in [[user(locn0)]];
+  float2 coord [[user(locn1)]];
+};
+
+struct tint_symbol_2 {
+  int value [[color(0)]];
+};
+
+int foo_inner(float in, float2 coord, thread bool* const tint_symbol_4, texture2d<float, access::sample> tint_symbol_5, sampler tint_symbol_6, device atomic_int* const tint_symbol_7) {
+  if ((in == 0.0f)) {
+    *(tint_symbol_4) = true;
+  }
+  int result = int(tint_symbol_5.sample(tint_symbol_6, coord)[0]);
+  {
+    int i = 0;
+    while (true) {
+      if (!((i < 10))) {
+        break;
+      }
+      {
+        result = as_type<int>((as_type<uint>(result) + as_type<uint>(i)));
+      }
+      {
+        int tint_symbol_3 = 0;
+        if (!(*(tint_symbol_4))) {
+          tint_symbol_3 = atomic_fetch_add_explicit(tint_symbol_7, 1, memory_order_relaxed);
+        }
+        i = tint_symbol_3;
+      }
+    }
+  }
+  return result;
+}
+
+fragment tint_symbol_2 foo(texture2d<float, access::sample> tint_symbol_9 [[texture(0)]], sampler tint_symbol_10 [[sampler(0)]], device atomic_int* tint_symbol_11 [[buffer(0)]], tint_symbol_1 tint_symbol [[stage_in]]) {
+  thread bool tint_symbol_8 = false;
+  int const inner_result = foo_inner(tint_symbol.in, tint_symbol.coord, &(tint_symbol_8), tint_symbol_9, tint_symbol_10, tint_symbol_11);
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.value = inner_result;
+  if (tint_symbol_8) {
+    discard_fragment();
+  }
+  return wrapper_result;
+}
+
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.spvasm b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.spvasm
new file mode 100644
index 0000000..c482728
--- /dev/null
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.spvasm
@@ -0,0 +1,145 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 83
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %foo "foo" %in_1 %coord_1 %value
+               OpExecutionMode %foo OriginUpperLeft
+               OpName %tint_discarded "tint_discarded"
+               OpName %in_1 "in_1"
+               OpName %coord_1 "coord_1"
+               OpName %value "value"
+               OpName %t "t"
+               OpName %s "s"
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %foo_inner "foo_inner"
+               OpName %in "in"
+               OpName %coord "coord"
+               OpName %result "result"
+               OpName %i "i"
+               OpName %tint_symbol "tint_symbol"
+               OpName %foo "foo"
+               OpDecorate %in_1 Location 0
+               OpDecorate %coord_1 Location 1
+               OpDecorate %value Location 0
+               OpDecorate %t DescriptorSet 0
+               OpDecorate %t Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 2
+       %bool = OpTypeBool
+          %2 = OpConstantNull %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discarded = OpVariable %_ptr_Private_bool Private %2
+      %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+       %in_1 = OpVariable %_ptr_Input_float Input
+    %v2float = OpTypeVector %float 2
+%_ptr_Input_v2float = OpTypePointer Input %v2float
+    %coord_1 = OpVariable %_ptr_Input_v2float Input
+        %int = OpTypeInt 32 1
+%_ptr_Output_int = OpTypePointer Output %int
+         %14 = OpConstantNull %int
+      %value = OpVariable %_ptr_Output_int Output %14
+         %17 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17
+          %t = OpVariable %_ptr_UniformConstant_17 UniformConstant
+         %20 = OpTypeSampler
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+          %s = OpVariable %_ptr_UniformConstant_20 UniformConstant
+    %a_block = OpTypeStruct %int
+%_ptr_StorageBuffer_a_block = OpTypePointer StorageBuffer %a_block
+          %a = OpVariable %_ptr_StorageBuffer_a_block StorageBuffer
+         %24 = OpTypeFunction %int %float %v2float
+         %29 = OpConstantNull %float
+       %true = OpConstantTrue %bool
+    %v4float = OpTypeVector %float 4
+         %39 = OpTypeSampledImage %17
+%_ptr_Function_int = OpTypePointer Function %int
+     %int_10 = OpConstant %int 10
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %73 = OpTypeFunction %void
+  %foo_inner = OpFunction %int None %24
+         %in = OpFunctionParameter %float
+      %coord = OpFunctionParameter %v2float
+         %28 = OpLabel
+     %result = OpVariable %_ptr_Function_int Function %14
+          %i = OpVariable %_ptr_Function_int Function %14
+%tint_symbol = OpVariable %_ptr_Function_int Function %14
+         %30 = OpFOrdEqual %bool %in %29
+               OpSelectionMerge %31 None
+               OpBranchConditional %30 %32 %31
+         %32 = OpLabel
+               OpStore %tint_discarded %true
+               OpBranch %31
+         %31 = OpLabel
+         %37 = OpLoad %20 %s
+         %38 = OpLoad %17 %t
+         %40 = OpSampledImage %39 %38 %37
+         %35 = OpImageSampleImplicitLod %v4float %40 %coord
+         %41 = OpCompositeExtract %float %35 0
+         %34 = OpConvertFToS %int %41
+               OpStore %result %34
+               OpStore %i %14
+               OpBranch %45
+         %45 = OpLabel
+               OpLoopMerge %46 %47 None
+               OpBranch %48
+         %48 = OpLabel
+         %50 = OpLoad %int %i
+         %52 = OpSLessThan %bool %50 %int_10
+         %49 = OpLogicalNot %bool %52
+               OpSelectionMerge %53 None
+               OpBranchConditional %49 %54 %53
+         %54 = OpLabel
+               OpBranch %46
+         %53 = OpLabel
+         %55 = OpLoad %int %result
+         %56 = OpLoad %int %i
+         %57 = OpIAdd %int %55 %56
+               OpStore %result %57
+               OpBranch %47
+         %47 = OpLabel
+         %60 = OpLoad %bool %tint_discarded
+         %59 = OpLogicalNot %bool %60
+               OpSelectionMerge %61 None
+               OpBranchConditional %59 %62 %61
+         %62 = OpLabel
+         %69 = OpAccessChain %_ptr_StorageBuffer_int %a %uint_0
+         %63 = OpAtomicIAdd %int %69 %uint_1 %uint_0 %int_1
+               OpStore %tint_symbol %63
+               OpBranch %61
+         %61 = OpLabel
+         %71 = OpLoad %int %tint_symbol
+               OpStore %i %71
+               OpBranch %45
+         %46 = OpLabel
+         %72 = OpLoad %int %result
+               OpReturnValue %72
+               OpFunctionEnd
+        %foo = OpFunction %void None %73
+         %76 = OpLabel
+         %78 = OpLoad %float %in_1
+         %79 = OpLoad %v2float %coord_1
+         %77 = OpFunctionCall %int %foo_inner %78 %79
+               OpStore %value %77
+         %80 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %81 None
+               OpBranchConditional %80 %82 %81
+         %82 = OpLabel
+               OpKill
+         %81 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.wgsl b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.wgsl
new file mode 100644
index 0000000..7d8d3fa
--- /dev/null
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.wgsl
@@ -0,0 +1,17 @@
+@group(0) @binding(0) var t : texture_2d<f32>;
+
+@group(0) @binding(1) var s : sampler;
+
+@group(0) @binding(2) var<storage, read_write> a : atomic<i32>;
+
+@fragment
+fn foo(@location(0) in : f32, @location(1) coord : vec2<f32>) -> @location(0) i32 {
+  if ((in == 0.0)) {
+    discard;
+  }
+  var result = i32(textureSample(t, s, coord).x);
+  for(var i = 0; (i < 10); i = atomicAdd(&(a), 1)) {
+    result += i;
+  }
+  return result;
+}
diff --git a/test/tint/statements/discard/helper_functions.wgsl b/test/tint/statements/discard/helper_functions.wgsl
new file mode 100644
index 0000000..9dc2445
--- /dev/null
+++ b/test/tint/statements/discard/helper_functions.wgsl
@@ -0,0 +1,19 @@
+@group(0) @binding(0) var<storage, read_write> non_uniform_global : i32;
+
+@group(0) @binding(1) var<storage, read_write> output : f32;
+
+fn foo() {
+  if (non_uniform_global < 0) {
+    discard;
+  }
+}
+
+fn bar() {
+   output = dpdx(1.0);
+}
+
+@fragment
+fn main() {
+  foo();
+  bar();
+}
diff --git a/test/tint/statements/discard/helper_functions.wgsl.expected.dxc.hlsl b/test/tint/statements/discard/helper_functions.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8b015e8
--- /dev/null
+++ b/test/tint/statements/discard/helper_functions.wgsl.expected.dxc.hlsl
@@ -0,0 +1,24 @@
+static bool tint_discarded = false;
+RWByteAddressBuffer non_uniform_global : register(u0, space0);
+RWByteAddressBuffer output : register(u1, space0);
+
+void foo() {
+  if ((asint(non_uniform_global.Load(0u)) < 0)) {
+    tint_discarded = true;
+  }
+}
+
+void bar() {
+  if (!(tint_discarded)) {
+    output.Store(0u, asuint(ddx(1.0f)));
+  }
+}
+
+void main() {
+  foo();
+  bar();
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/helper_functions.wgsl.expected.fxc.hlsl b/test/tint/statements/discard/helper_functions.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8b015e8
--- /dev/null
+++ b/test/tint/statements/discard/helper_functions.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+static bool tint_discarded = false;
+RWByteAddressBuffer non_uniform_global : register(u0, space0);
+RWByteAddressBuffer output : register(u1, space0);
+
+void foo() {
+  if ((asint(non_uniform_global.Load(0u)) < 0)) {
+    tint_discarded = true;
+  }
+}
+
+void bar() {
+  if (!(tint_discarded)) {
+    output.Store(0u, asuint(ddx(1.0f)));
+  }
+}
+
+void main() {
+  foo();
+  bar();
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/helper_functions.wgsl.expected.glsl b/test/tint/statements/discard/helper_functions.wgsl.expected.glsl
new file mode 100644
index 0000000..a17e8f5
--- /dev/null
+++ b/test/tint/statements/discard/helper_functions.wgsl.expected.glsl
@@ -0,0 +1,36 @@
+#version 310 es
+precision mediump float;
+
+bool tint_discarded = false;
+layout(binding = 0, std430) buffer non_uniform_global_block_ssbo {
+  int inner;
+} non_uniform_global;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo {
+  float inner;
+} tint_symbol;
+
+void foo() {
+  if ((non_uniform_global.inner < 0)) {
+    tint_discarded = true;
+  }
+}
+
+void bar() {
+  if (!(tint_discarded)) {
+    tint_symbol.inner = dFdx(1.0f);
+  }
+}
+
+void tint_symbol_1() {
+  foo();
+  bar();
+}
+
+void main() {
+  tint_symbol_1();
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/helper_functions.wgsl.expected.msl b/test/tint/statements/discard/helper_functions.wgsl.expected.msl
new file mode 100644
index 0000000..57e769e
--- /dev/null
+++ b/test/tint/statements/discard/helper_functions.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void foo(device int* const tint_symbol_1, thread bool* const tint_symbol_2) {
+  if ((*(tint_symbol_1) < 0)) {
+    *(tint_symbol_2) = true;
+  }
+}
+
+void bar(thread bool* const tint_symbol_3, device float* const tint_symbol_4) {
+  if (!(*(tint_symbol_3))) {
+    *(tint_symbol_4) = dfdx(1.0f);
+  }
+}
+
+fragment void tint_symbol(device int* tint_symbol_5 [[buffer(0)]], device float* tint_symbol_7 [[buffer(1)]]) {
+  thread bool tint_symbol_6 = false;
+  foo(tint_symbol_5, &(tint_symbol_6));
+  bar(&(tint_symbol_6), tint_symbol_7);
+  if (tint_symbol_6) {
+    discard_fragment();
+  }
+  return;
+}
+
diff --git a/test/tint/statements/discard/helper_functions.wgsl.expected.spvasm b/test/tint/statements/discard/helper_functions.wgsl.expected.spvasm
new file mode 100644
index 0000000..9758c25
--- /dev/null
+++ b/test/tint/statements/discard/helper_functions.wgsl.expected.spvasm
@@ -0,0 +1,87 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpName %tint_discarded "tint_discarded"
+               OpName %non_uniform_global_block "non_uniform_global_block"
+               OpMemberName %non_uniform_global_block 0 "inner"
+               OpName %non_uniform_global "non_uniform_global"
+               OpName %output_block "output_block"
+               OpMemberName %output_block 0 "inner"
+               OpName %output "output"
+               OpName %foo "foo"
+               OpName %bar "bar"
+               OpName %main "main"
+               OpDecorate %non_uniform_global_block Block
+               OpMemberDecorate %non_uniform_global_block 0 Offset 0
+               OpDecorate %non_uniform_global DescriptorSet 0
+               OpDecorate %non_uniform_global Binding 0
+               OpDecorate %output_block Block
+               OpMemberDecorate %output_block 0 Offset 0
+               OpDecorate %output DescriptorSet 0
+               OpDecorate %output Binding 1
+       %bool = OpTypeBool
+          %2 = OpConstantNull %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discarded = OpVariable %_ptr_Private_bool Private %2
+        %int = OpTypeInt 32 1
+%non_uniform_global_block = OpTypeStruct %int
+%_ptr_StorageBuffer_non_uniform_global_block = OpTypePointer StorageBuffer %non_uniform_global_block
+%non_uniform_global = OpVariable %_ptr_StorageBuffer_non_uniform_global_block StorageBuffer
+      %float = OpTypeFloat 32
+%output_block = OpTypeStruct %float
+%_ptr_StorageBuffer_output_block = OpTypePointer StorageBuffer %output_block
+     %output = OpVariable %_ptr_StorageBuffer_output_block StorageBuffer
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+         %22 = OpConstantNull %int
+       %true = OpConstantTrue %bool
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+    %float_1 = OpConstant %float 1
+        %foo = OpFunction %void None %13
+         %16 = OpLabel
+         %20 = OpAccessChain %_ptr_StorageBuffer_int %non_uniform_global %uint_0
+         %21 = OpLoad %int %20
+         %23 = OpSLessThan %bool %21 %22
+               OpSelectionMerge %24 None
+               OpBranchConditional %23 %25 %24
+         %25 = OpLabel
+               OpStore %tint_discarded %true
+               OpBranch %24
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+        %bar = OpFunction %void None %13
+         %28 = OpLabel
+         %30 = OpLoad %bool %tint_discarded
+         %29 = OpLogicalNot %bool %30
+               OpSelectionMerge %31 None
+               OpBranchConditional %29 %32 %31
+         %32 = OpLabel
+         %34 = OpAccessChain %_ptr_StorageBuffer_float %output %uint_0
+         %35 = OpDPdx %float %float_1
+               OpStore %34 %35
+               OpBranch %31
+         %31 = OpLabel
+               OpReturn
+               OpFunctionEnd
+       %main = OpFunction %void None %13
+         %38 = OpLabel
+         %39 = OpFunctionCall %void %foo
+         %40 = OpFunctionCall %void %bar
+         %41 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %42 None
+               OpBranchConditional %41 %43 %42
+         %43 = OpLabel
+               OpKill
+         %42 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/statements/discard/helper_functions.wgsl.expected.wgsl b/test/tint/statements/discard/helper_functions.wgsl.expected.wgsl
new file mode 100644
index 0000000..a900752
--- /dev/null
+++ b/test/tint/statements/discard/helper_functions.wgsl.expected.wgsl
@@ -0,0 +1,19 @@
+@group(0) @binding(0) var<storage, read_write> non_uniform_global : i32;
+
+@group(0) @binding(1) var<storage, read_write> output : f32;
+
+fn foo() {
+  if ((non_uniform_global < 0)) {
+    discard;
+  }
+}
+
+fn bar() {
+  output = dpdx(1.0);
+}
+
+@fragment
+fn main() {
+  foo();
+  bar();
+}
diff --git a/test/tint/statements/discard/multiple_returns.wgsl b/test/tint/statements/discard/multiple_returns.wgsl
new file mode 100644
index 0000000..2464f3f
--- /dev/null
+++ b/test/tint/statements/discard/multiple_returns.wgsl
@@ -0,0 +1,26 @@
+@group(0) @binding(0) var<storage, read_write> non_uniform_global : i32;
+
+@group(0) @binding(1) var<storage, read_write> output : f32;
+
+@fragment
+fn main() {
+  if (non_uniform_global < 0) {
+    discard;
+  }
+  output = dpdx(1.0);
+  if (output < 0) {
+    var i = 0;
+    loop {
+      if (output > f32(i)) {
+        output = f32(i);
+        return;
+      }
+      continuing {
+        i++;
+        break if i == 5;
+      }
+    }
+    return;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/multiple_returns.wgsl.expected.dxc.hlsl b/test/tint/statements/discard/multiple_returns.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f7b1a26
--- /dev/null
+++ b/test/tint/statements/discard/multiple_returns.wgsl.expected.dxc.hlsl
@@ -0,0 +1,38 @@
+static bool tint_discarded = false;
+RWByteAddressBuffer non_uniform_global : register(u0, space0);
+RWByteAddressBuffer output : register(u1, space0);
+
+void main() {
+  if ((asint(non_uniform_global.Load(0u)) < 0)) {
+    tint_discarded = true;
+  }
+  if (!(tint_discarded)) {
+    output.Store(0u, asuint(ddx(1.0f)));
+  }
+  if ((asfloat(output.Load(0u)) < 0.0f)) {
+    int i = 0;
+    while (true) {
+      if ((asfloat(output.Load(0u)) > float(i))) {
+        if (!(tint_discarded)) {
+          output.Store(0u, asuint(float(i)));
+        }
+        if (tint_discarded) {
+          discard;
+        }
+        return;
+      }
+      {
+        i = (i + 1);
+        if ((i == 5)) { break; }
+      }
+    }
+    if (tint_discarded) {
+      discard;
+    }
+    return;
+  }
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/multiple_returns.wgsl.expected.fxc.hlsl b/test/tint/statements/discard/multiple_returns.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f7b1a26
--- /dev/null
+++ b/test/tint/statements/discard/multiple_returns.wgsl.expected.fxc.hlsl
@@ -0,0 +1,38 @@
+static bool tint_discarded = false;
+RWByteAddressBuffer non_uniform_global : register(u0, space0);
+RWByteAddressBuffer output : register(u1, space0);
+
+void main() {
+  if ((asint(non_uniform_global.Load(0u)) < 0)) {
+    tint_discarded = true;
+  }
+  if (!(tint_discarded)) {
+    output.Store(0u, asuint(ddx(1.0f)));
+  }
+  if ((asfloat(output.Load(0u)) < 0.0f)) {
+    int i = 0;
+    while (true) {
+      if ((asfloat(output.Load(0u)) > float(i))) {
+        if (!(tint_discarded)) {
+          output.Store(0u, asuint(float(i)));
+        }
+        if (tint_discarded) {
+          discard;
+        }
+        return;
+      }
+      {
+        i = (i + 1);
+        if ((i == 5)) { break; }
+      }
+    }
+    if (tint_discarded) {
+      discard;
+    }
+    return;
+  }
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/multiple_returns.wgsl.expected.glsl b/test/tint/statements/discard/multiple_returns.wgsl.expected.glsl
new file mode 100644
index 0000000..8cd3e99
--- /dev/null
+++ b/test/tint/statements/discard/multiple_returns.wgsl.expected.glsl
@@ -0,0 +1,45 @@
+#version 310 es
+precision mediump float;
+
+bool tint_discarded = false;
+layout(binding = 0, std430) buffer non_uniform_global_block_ssbo {
+  int inner;
+} non_uniform_global;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo {
+  float inner;
+} tint_symbol;
+
+void tint_symbol_1() {
+  if ((non_uniform_global.inner < 0)) {
+    tint_discarded = true;
+  }
+  if (!(tint_discarded)) {
+    tint_symbol.inner = dFdx(1.0f);
+  }
+  if ((tint_symbol.inner < 0.0f)) {
+    int i = 0;
+    while (true) {
+      if ((tint_symbol.inner > float(i))) {
+        if (!(tint_discarded)) {
+          tint_symbol.inner = float(i);
+        }
+        return;
+      }
+      {
+        i = (i + 1);
+        if ((i == 5)) { break; }
+      }
+    }
+    return;
+  }
+  return;
+}
+
+void main() {
+  tint_symbol_1();
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/multiple_returns.wgsl.expected.msl b/test/tint/statements/discard/multiple_returns.wgsl.expected.msl
new file mode 100644
index 0000000..751016e
--- /dev/null
+++ b/test/tint/statements/discard/multiple_returns.wgsl.expected.msl
@@ -0,0 +1,39 @@
+#include <metal_stdlib>
+
+using namespace metal;
+fragment void tint_symbol(device int* tint_symbol_1 [[buffer(0)]], device float* tint_symbol_3 [[buffer(1)]]) {
+  thread bool tint_symbol_2 = false;
+  if ((*(tint_symbol_1) < 0)) {
+    tint_symbol_2 = true;
+  }
+  if (!(tint_symbol_2)) {
+    *(tint_symbol_3) = dfdx(1.0f);
+  }
+  if ((*(tint_symbol_3) < 0.0f)) {
+    int i = 0;
+    while (true) {
+      if ((*(tint_symbol_3) > float(i))) {
+        if (!(tint_symbol_2)) {
+          *(tint_symbol_3) = float(i);
+        }
+        if (tint_symbol_2) {
+          discard_fragment();
+        }
+        return;
+      }
+      {
+        i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)));
+        if ((i == 5)) { break; }
+      }
+    }
+    if (tint_symbol_2) {
+      discard_fragment();
+    }
+    return;
+  }
+  if (tint_symbol_2) {
+    discard_fragment();
+  }
+  return;
+}
+
diff --git a/test/tint/statements/discard/multiple_returns.wgsl.expected.spvasm b/test/tint/statements/discard/multiple_returns.wgsl.expected.spvasm
new file mode 100644
index 0000000..6e83367
--- /dev/null
+++ b/test/tint/statements/discard/multiple_returns.wgsl.expected.spvasm
@@ -0,0 +1,137 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 76
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpName %tint_discarded "tint_discarded"
+               OpName %non_uniform_global_block "non_uniform_global_block"
+               OpMemberName %non_uniform_global_block 0 "inner"
+               OpName %non_uniform_global "non_uniform_global"
+               OpName %output_block "output_block"
+               OpMemberName %output_block 0 "inner"
+               OpName %output "output"
+               OpName %main "main"
+               OpName %i "i"
+               OpDecorate %non_uniform_global_block Block
+               OpMemberDecorate %non_uniform_global_block 0 Offset 0
+               OpDecorate %non_uniform_global DescriptorSet 0
+               OpDecorate %non_uniform_global Binding 0
+               OpDecorate %output_block Block
+               OpMemberDecorate %output_block 0 Offset 0
+               OpDecorate %output DescriptorSet 0
+               OpDecorate %output Binding 1
+       %bool = OpTypeBool
+          %2 = OpConstantNull %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discarded = OpVariable %_ptr_Private_bool Private %2
+        %int = OpTypeInt 32 1
+%non_uniform_global_block = OpTypeStruct %int
+%_ptr_StorageBuffer_non_uniform_global_block = OpTypePointer StorageBuffer %non_uniform_global_block
+%non_uniform_global = OpVariable %_ptr_StorageBuffer_non_uniform_global_block StorageBuffer
+      %float = OpTypeFloat 32
+%output_block = OpTypeStruct %float
+%_ptr_StorageBuffer_output_block = OpTypePointer StorageBuffer %output_block
+     %output = OpVariable %_ptr_StorageBuffer_output_block StorageBuffer
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+         %22 = OpConstantNull %int
+       %true = OpConstantTrue %bool
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+    %float_1 = OpConstant %float 1
+         %37 = OpConstantNull %float
+%_ptr_Function_int = OpTypePointer Function %int
+      %int_1 = OpConstant %int 1
+      %int_5 = OpConstant %int 5
+       %main = OpFunction %void None %13
+         %16 = OpLabel
+          %i = OpVariable %_ptr_Function_int Function %22
+         %20 = OpAccessChain %_ptr_StorageBuffer_int %non_uniform_global %uint_0
+         %21 = OpLoad %int %20
+         %23 = OpSLessThan %bool %21 %22
+               OpSelectionMerge %24 None
+               OpBranchConditional %23 %25 %24
+         %25 = OpLabel
+               OpStore %tint_discarded %true
+               OpBranch %24
+         %24 = OpLabel
+         %28 = OpLoad %bool %tint_discarded
+         %27 = OpLogicalNot %bool %28
+               OpSelectionMerge %29 None
+               OpBranchConditional %27 %30 %29
+         %30 = OpLabel
+         %32 = OpAccessChain %_ptr_StorageBuffer_float %output %uint_0
+         %33 = OpDPdx %float %float_1
+               OpStore %32 %33
+               OpBranch %29
+         %29 = OpLabel
+         %35 = OpAccessChain %_ptr_StorageBuffer_float %output %uint_0
+         %36 = OpLoad %float %35
+         %38 = OpFOrdLessThan %bool %36 %37
+               OpSelectionMerge %39 None
+               OpBranchConditional %38 %40 %39
+         %40 = OpLabel
+               OpStore %i %22
+               OpBranch %43
+         %43 = OpLabel
+               OpLoopMerge %44 %45 None
+               OpBranch %46
+         %46 = OpLabel
+         %47 = OpAccessChain %_ptr_StorageBuffer_float %output %uint_0
+         %48 = OpLoad %float %47
+         %50 = OpLoad %int %i
+         %49 = OpConvertSToF %float %50
+         %51 = OpFOrdGreaterThan %bool %48 %49
+               OpSelectionMerge %52 None
+               OpBranchConditional %51 %53 %52
+         %53 = OpLabel
+         %55 = OpLoad %bool %tint_discarded
+         %54 = OpLogicalNot %bool %55
+               OpSelectionMerge %56 None
+               OpBranchConditional %54 %57 %56
+         %57 = OpLabel
+         %58 = OpAccessChain %_ptr_StorageBuffer_float %output %uint_0
+         %60 = OpLoad %int %i
+         %59 = OpConvertSToF %float %60
+               OpStore %58 %59
+               OpBranch %56
+         %56 = OpLabel
+         %61 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %62 None
+               OpBranchConditional %61 %63 %62
+         %63 = OpLabel
+               OpKill
+         %62 = OpLabel
+               OpReturn
+         %52 = OpLabel
+               OpBranch %45
+         %45 = OpLabel
+         %64 = OpLoad %int %i
+         %66 = OpIAdd %int %64 %int_1
+               OpStore %i %66
+         %67 = OpLoad %int %i
+         %69 = OpIEqual %bool %67 %int_5
+               OpBranchConditional %69 %44 %43
+         %44 = OpLabel
+         %70 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %71 None
+               OpBranchConditional %70 %72 %71
+         %72 = OpLabel
+               OpKill
+         %71 = OpLabel
+               OpReturn
+         %39 = OpLabel
+         %73 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %74 None
+               OpBranchConditional %73 %75 %74
+         %75 = OpLabel
+               OpKill
+         %74 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/statements/discard/multiple_returns.wgsl.expected.wgsl b/test/tint/statements/discard/multiple_returns.wgsl.expected.wgsl
new file mode 100644
index 0000000..4d52f05
--- /dev/null
+++ b/test/tint/statements/discard/multiple_returns.wgsl.expected.wgsl
@@ -0,0 +1,27 @@
+@group(0) @binding(0) var<storage, read_write> non_uniform_global : i32;
+
+@group(0) @binding(1) var<storage, read_write> output : f32;
+
+@fragment
+fn main() {
+  if ((non_uniform_global < 0)) {
+    discard;
+  }
+  output = dpdx(1.0);
+  if ((output < 0)) {
+    var i = 0;
+    loop {
+      if ((output > f32(i))) {
+        output = f32(i);
+        return;
+      }
+
+      continuing {
+        i++;
+        break if (i == 5);
+      }
+    }
+    return;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/nested_return.wgsl b/test/tint/statements/discard/nested_return.wgsl
new file mode 100644
index 0000000..75bcdb0
--- /dev/null
+++ b/test/tint/statements/discard/nested_return.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<storage, read_write> non_uniform_global : i32;
+
+@fragment
+fn main() {
+  if (non_uniform_global < 0) {
+    discard;
+  }
+  {
+    {
+      return;
+    }
+  }
+}
diff --git a/test/tint/statements/discard/nested_return.wgsl.expected.dxc.hlsl b/test/tint/statements/discard/nested_return.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c8e4eda
--- /dev/null
+++ b/test/tint/statements/discard/nested_return.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+static bool tint_discarded = false;
+RWByteAddressBuffer non_uniform_global : register(u0, space0);
+
+void main() {
+  if ((asint(non_uniform_global.Load(0u)) < 0)) {
+    tint_discarded = true;
+  }
+  {
+    {
+      if (tint_discarded) {
+        discard;
+      }
+      return;
+    }
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/nested_return.wgsl.expected.fxc.hlsl b/test/tint/statements/discard/nested_return.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c8e4eda
--- /dev/null
+++ b/test/tint/statements/discard/nested_return.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+static bool tint_discarded = false;
+RWByteAddressBuffer non_uniform_global : register(u0, space0);
+
+void main() {
+  if ((asint(non_uniform_global.Load(0u)) < 0)) {
+    tint_discarded = true;
+  }
+  {
+    {
+      if (tint_discarded) {
+        discard;
+      }
+      return;
+    }
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/nested_return.wgsl.expected.glsl b/test/tint/statements/discard/nested_return.wgsl.expected.glsl
new file mode 100644
index 0000000..601c669
--- /dev/null
+++ b/test/tint/statements/discard/nested_return.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+precision mediump float;
+
+bool tint_discarded = false;
+layout(binding = 0, std430) buffer non_uniform_global_block_ssbo {
+  int inner;
+} non_uniform_global;
+
+void tint_symbol() {
+  if ((non_uniform_global.inner < 0)) {
+    tint_discarded = true;
+  }
+  {
+    {
+      return;
+    }
+  }
+}
+
+void main() {
+  tint_symbol();
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/nested_return.wgsl.expected.msl b/test/tint/statements/discard/nested_return.wgsl.expected.msl
new file mode 100644
index 0000000..eac069d
--- /dev/null
+++ b/test/tint/statements/discard/nested_return.wgsl.expected.msl
@@ -0,0 +1,19 @@
+#include <metal_stdlib>
+
+using namespace metal;
+fragment void tint_symbol(device int* tint_symbol_1 [[buffer(0)]]) {
+  thread bool tint_symbol_2 = false;
+  if ((*(tint_symbol_1) < 0)) {
+    tint_symbol_2 = true;
+  }
+  {
+    {
+      if (tint_symbol_2) {
+        discard_fragment();
+      }
+      return;
+    }
+  }
+  return;
+}
+
diff --git a/test/tint/statements/discard/nested_return.wgsl.expected.spvasm b/test/tint/statements/discard/nested_return.wgsl.expected.spvasm
new file mode 100644
index 0000000..c1c59a3
--- /dev/null
+++ b/test/tint/statements/discard/nested_return.wgsl.expected.spvasm
@@ -0,0 +1,52 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 26
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpName %tint_discarded "tint_discarded"
+               OpName %non_uniform_global_block "non_uniform_global_block"
+               OpMemberName %non_uniform_global_block 0 "inner"
+               OpName %non_uniform_global "non_uniform_global"
+               OpName %main "main"
+               OpDecorate %non_uniform_global_block Block
+               OpMemberDecorate %non_uniform_global_block 0 Offset 0
+               OpDecorate %non_uniform_global DescriptorSet 0
+               OpDecorate %non_uniform_global Binding 0
+       %bool = OpTypeBool
+          %2 = OpConstantNull %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discarded = OpVariable %_ptr_Private_bool Private %2
+        %int = OpTypeInt 32 1
+%non_uniform_global_block = OpTypeStruct %int
+%_ptr_StorageBuffer_non_uniform_global_block = OpTypePointer StorageBuffer %non_uniform_global_block
+%non_uniform_global = OpVariable %_ptr_StorageBuffer_non_uniform_global_block StorageBuffer
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+         %18 = OpConstantNull %int
+       %true = OpConstantTrue %bool
+       %main = OpFunction %void None %9
+         %12 = OpLabel
+         %16 = OpAccessChain %_ptr_StorageBuffer_int %non_uniform_global %uint_0
+         %17 = OpLoad %int %16
+         %19 = OpSLessThan %bool %17 %18
+               OpSelectionMerge %20 None
+               OpBranchConditional %19 %21 %20
+         %21 = OpLabel
+               OpStore %tint_discarded %true
+               OpBranch %20
+         %20 = OpLabel
+         %23 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %24 None
+               OpBranchConditional %23 %25 %24
+         %25 = OpLabel
+               OpKill
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/statements/discard/nested_return.wgsl.expected.wgsl b/test/tint/statements/discard/nested_return.wgsl.expected.wgsl
new file mode 100644
index 0000000..a33d273
--- /dev/null
+++ b/test/tint/statements/discard/nested_return.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<storage, read_write> non_uniform_global : i32;
+
+@fragment
+fn main() {
+  if ((non_uniform_global < 0)) {
+    discard;
+  }
+  {
+    {
+      return;
+    }
+  }
+}
diff --git a/test/tint/statements/discard/non_uniform.wgsl b/test/tint/statements/discard/non_uniform.wgsl
new file mode 100644
index 0000000..06c9927
--- /dev/null
+++ b/test/tint/statements/discard/non_uniform.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<storage, read_write> non_uniform_global : i32;
+
+@group(0) @binding(1) var<storage, read_write> output : f32;
+
+@fragment
+fn main() {
+  if (non_uniform_global < 0) {
+    discard;
+  }
+  output = dpdx(1.0);
+}
diff --git a/test/tint/statements/discard/non_uniform.wgsl.expected.dxc.hlsl b/test/tint/statements/discard/non_uniform.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..88ce6fa
--- /dev/null
+++ b/test/tint/statements/discard/non_uniform.wgsl.expected.dxc.hlsl
@@ -0,0 +1,16 @@
+static bool tint_discarded = false;
+RWByteAddressBuffer non_uniform_global : register(u0, space0);
+RWByteAddressBuffer output : register(u1, space0);
+
+void main() {
+  if ((asint(non_uniform_global.Load(0u)) < 0)) {
+    tint_discarded = true;
+  }
+  if (!(tint_discarded)) {
+    output.Store(0u, asuint(ddx(1.0f)));
+  }
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/non_uniform.wgsl.expected.fxc.hlsl b/test/tint/statements/discard/non_uniform.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..88ce6fa
--- /dev/null
+++ b/test/tint/statements/discard/non_uniform.wgsl.expected.fxc.hlsl
@@ -0,0 +1,16 @@
+static bool tint_discarded = false;
+RWByteAddressBuffer non_uniform_global : register(u0, space0);
+RWByteAddressBuffer output : register(u1, space0);
+
+void main() {
+  if ((asint(non_uniform_global.Load(0u)) < 0)) {
+    tint_discarded = true;
+  }
+  if (!(tint_discarded)) {
+    output.Store(0u, asuint(ddx(1.0f)));
+  }
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/non_uniform.wgsl.expected.glsl b/test/tint/statements/discard/non_uniform.wgsl.expected.glsl
new file mode 100644
index 0000000..b6be83a
--- /dev/null
+++ b/test/tint/statements/discard/non_uniform.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+precision mediump float;
+
+bool tint_discarded = false;
+layout(binding = 0, std430) buffer non_uniform_global_block_ssbo {
+  int inner;
+} non_uniform_global;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo {
+  float inner;
+} tint_symbol;
+
+void tint_symbol_1() {
+  if ((non_uniform_global.inner < 0)) {
+    tint_discarded = true;
+  }
+  if (!(tint_discarded)) {
+    tint_symbol.inner = dFdx(1.0f);
+  }
+}
+
+void main() {
+  tint_symbol_1();
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/statements/discard/non_uniform.wgsl.expected.msl b/test/tint/statements/discard/non_uniform.wgsl.expected.msl
new file mode 100644
index 0000000..2ada21d
--- /dev/null
+++ b/test/tint/statements/discard/non_uniform.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+fragment void tint_symbol(device int* tint_symbol_1 [[buffer(0)]], device float* tint_symbol_3 [[buffer(1)]]) {
+  thread bool tint_symbol_2 = false;
+  if ((*(tint_symbol_1) < 0)) {
+    tint_symbol_2 = true;
+  }
+  if (!(tint_symbol_2)) {
+    *(tint_symbol_3) = dfdx(1.0f);
+  }
+  if (tint_symbol_2) {
+    discard_fragment();
+  }
+  return;
+}
+
diff --git a/test/tint/statements/discard/non_uniform.wgsl.expected.spvasm b/test/tint/statements/discard/non_uniform.wgsl.expected.spvasm
new file mode 100644
index 0000000..a023542
--- /dev/null
+++ b/test/tint/statements/discard/non_uniform.wgsl.expected.spvasm
@@ -0,0 +1,75 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 38
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpName %tint_discarded "tint_discarded"
+               OpName %non_uniform_global_block "non_uniform_global_block"
+               OpMemberName %non_uniform_global_block 0 "inner"
+               OpName %non_uniform_global "non_uniform_global"
+               OpName %output_block "output_block"
+               OpMemberName %output_block 0 "inner"
+               OpName %output "output"
+               OpName %main "main"
+               OpDecorate %non_uniform_global_block Block
+               OpMemberDecorate %non_uniform_global_block 0 Offset 0
+               OpDecorate %non_uniform_global DescriptorSet 0
+               OpDecorate %non_uniform_global Binding 0
+               OpDecorate %output_block Block
+               OpMemberDecorate %output_block 0 Offset 0
+               OpDecorate %output DescriptorSet 0
+               OpDecorate %output Binding 1
+       %bool = OpTypeBool
+          %2 = OpConstantNull %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discarded = OpVariable %_ptr_Private_bool Private %2
+        %int = OpTypeInt 32 1
+%non_uniform_global_block = OpTypeStruct %int
+%_ptr_StorageBuffer_non_uniform_global_block = OpTypePointer StorageBuffer %non_uniform_global_block
+%non_uniform_global = OpVariable %_ptr_StorageBuffer_non_uniform_global_block StorageBuffer
+      %float = OpTypeFloat 32
+%output_block = OpTypeStruct %float
+%_ptr_StorageBuffer_output_block = OpTypePointer StorageBuffer %output_block
+     %output = OpVariable %_ptr_StorageBuffer_output_block StorageBuffer
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+         %22 = OpConstantNull %int
+       %true = OpConstantTrue %bool
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+    %float_1 = OpConstant %float 1
+       %main = OpFunction %void None %13
+         %16 = OpLabel
+         %20 = OpAccessChain %_ptr_StorageBuffer_int %non_uniform_global %uint_0
+         %21 = OpLoad %int %20
+         %23 = OpSLessThan %bool %21 %22
+               OpSelectionMerge %24 None
+               OpBranchConditional %23 %25 %24
+         %25 = OpLabel
+               OpStore %tint_discarded %true
+               OpBranch %24
+         %24 = OpLabel
+         %28 = OpLoad %bool %tint_discarded
+         %27 = OpLogicalNot %bool %28
+               OpSelectionMerge %29 None
+               OpBranchConditional %27 %30 %29
+         %30 = OpLabel
+         %32 = OpAccessChain %_ptr_StorageBuffer_float %output %uint_0
+         %33 = OpDPdx %float %float_1
+               OpStore %32 %33
+               OpBranch %29
+         %29 = OpLabel
+         %35 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %36 None
+               OpBranchConditional %35 %37 %36
+         %37 = OpLabel
+               OpKill
+         %36 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/statements/discard/non_uniform.wgsl.expected.wgsl b/test/tint/statements/discard/non_uniform.wgsl.expected.wgsl
new file mode 100644
index 0000000..5d697d4
--- /dev/null
+++ b/test/tint/statements/discard/non_uniform.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<storage, read_write> non_uniform_global : i32;
+
+@group(0) @binding(1) var<storage, read_write> output : f32;
+
+@fragment
+fn main() {
+  if ((non_uniform_global < 0)) {
+    discard;
+  }
+  output = dpdx(1.0);
+}
diff --git a/test/tint/unittest/reader/spirv/SpvParserCFGTest_EmitBody_Kill_InsideLoop.spvasm b/test/tint/unittest/reader/spirv/SpvParserCFGTest_EmitBody_Kill_InsideLoop.spvasm
deleted file mode 100644
index 85a2d5b..0000000
--- a/test/tint/unittest/reader/spirv/SpvParserCFGTest_EmitBody_Kill_InsideLoop.spvasm
+++ /dev/null
@@ -1,55 +0,0 @@
-; Test: SpvParserCFGTest_EmitBody_Kill_InsideLoop.spvasm
-; SPIR-V
-; Version: 1.0
-; Generator: Khronos SPIR-V Tools Assembler; 0
-; Bound: 1000
-; Schema: 0
-OpCapability Shader
-OpMemoryModel Logical Simple
-OpEntryPoint Fragment %100 "main"
-OpExecutionMode %100 OriginUpperLeft
-OpName %var "var"
-%void = OpTypeVoid
-%3 = OpTypeFunction %void
-%bool = OpTypeBool
-%5 = OpConstantNull %bool
-%true = OpConstantTrue %bool
-%false = OpConstantFalse %bool
-%uint = OpTypeInt 32 0
-%int = OpTypeInt 32 1
-%uint_42 = OpConstant %uint 42
-%int_42 = OpConstant %int 42
-%13 = OpTypeFunction %uint
-%uint_0 = OpConstant %uint 0
-%uint_1 = OpConstant %uint 1
-%uint_2 = OpConstant %uint 2
-%uint_3 = OpConstant %uint 3
-%uint_4 = OpConstant %uint 4
-%uint_5 = OpConstant %uint 5
-%uint_6 = OpConstant %uint 6
-%uint_7 = OpConstant %uint 7
-%uint_8 = OpConstant %uint 8
-%uint_10 = OpConstant %uint 10
-%uint_20 = OpConstant %uint 20
-%uint_30 = OpConstant %uint 30
-%uint_40 = OpConstant %uint 40
-%uint_50 = OpConstant %uint 50
-%uint_90 = OpConstant %uint 90
-%uint_99 = OpConstant %uint 99
-%_ptr_Private_uint = OpTypePointer Private %uint
-%var = OpVariable %_ptr_Private_uint Private
-%uint_999 = OpConstant %uint 999
-%100 = OpFunction %void None %3
-%10 = OpLabel
-OpBranch %20
-%20 = OpLabel
-OpLoopMerge %99 %80 None
-OpBranchConditional %5 %30 %30
-%30 = OpLabel
-OpKill
-%80 = OpLabel
-OpBranch %20
-%99 = OpLabel
-OpKill
-OpFunctionEnd
-
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.spvasm b/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.spvasm
deleted file mode 100644
index 235ec03..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.spvasm
+++ /dev/null
@@ -1,1053 +0,0 @@
-               OpCapability Shader
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %main "main" %gl_FragCoord %_GLF_color
-               OpExecutionMode %main OriginUpperLeft
-               OpSource ESSL 320
-               OpName %main "main"
-               OpName %BST "BST"
-               OpMemberName %BST 0 "data"
-               OpMemberName %BST 1 "leftIndex"
-               OpMemberName %BST 2 "rightIndex"
-               OpName %tree "tree"
-               OpName %buf0 "buf0"
-               OpMemberName %buf0 0 "injectionSwitch"
-               OpName %_ ""
-               OpName %gl_FragCoord "gl_FragCoord"
-               OpName %_GLF_color "_GLF_color"
-               OpMemberDecorate %buf0 0 Offset 0
-               OpDecorate %buf0 Block
-               OpDecorate %_ DescriptorSet 0
-               OpDecorate %_ Binding 0
-               OpDecorate %gl_FragCoord BuiltIn FragCoord
-               OpDecorate %_GLF_color Location 0
-       %void = OpTypeVoid
-         %10 = OpTypeFunction %void
-        %int = OpTypeInt 32 1
-        %BST = OpTypeStruct %int %int %int
-%_ptr_Function_BST = OpTypePointer Function %BST
-%_ptr_Function_int = OpTypePointer Function %int
-      %int_0 = OpConstant %int 0
-      %int_1 = OpConstant %int 1
-     %int_n1 = OpConstant %int -1
-      %int_2 = OpConstant %int 2
-       %bool = OpTypeBool
-       %uint = OpTypeInt 32 0
-    %uint_10 = OpConstant %uint 10
-%_arr_BST_uint_10 = OpTypeArray %BST %uint_10
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-       %buf0 = OpTypeStruct %v2float
-%_ptr_Uniform_buf0 = OpTypePointer Uniform %buf0
-          %_ = OpVariable %_ptr_Uniform_buf0 Uniform
-     %uint_1 = OpConstant %uint 1
-%_ptr_Uniform_float = OpTypePointer Uniform %float
-     %uint_0 = OpConstant %uint 0
-      %int_9 = OpConstant %int 9
-      %int_5 = OpConstant %int 5
-    %v4float = OpTypeVector %float 4
-%_ptr_Input_v4float = OpTypePointer Input %v4float
-%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-%_ptr_Input_float = OpTypePointer Input %float
-    %float_0 = OpConstant %float 0
-     %int_12 = OpConstant %int 12
-     %int_15 = OpConstant %int 15
-      %int_7 = OpConstant %int 7
-      %int_8 = OpConstant %int 8
-      %int_6 = OpConstant %int 6
-     %int_17 = OpConstant %int 17
-     %int_13 = OpConstant %int 13
-     %int_20 = OpConstant %int 20
-%_ptr_Output_v4float = OpTypePointer Output %v4float
- %_GLF_color = OpVariable %_ptr_Output_v4float Output
-    %float_1 = OpConstant %float 1
-         %44 = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1
-         %45 = OpConstantComposite %v4float %float_0 %float_0 %float_1 %float_1
-      %false = OpConstantFalse %bool
-       %true = OpConstantTrue %bool
-%_ptr_Function__arr_BST_uint_10 = OpTypePointer Function %_arr_BST_uint_10
-         %49 = OpUndef %int
-         %50 = OpConstantComposite %BST %int_9 %int_n1 %int_n1
-         %51 = OpConstantComposite %BST %int_5 %int_n1 %int_n1
-      %int_3 = OpConstant %int 3
-         %53 = OpConstantComposite %BST %int_12 %int_n1 %int_n1
-         %54 = OpConstantComposite %BST %int_15 %int_n1 %int_n1
-      %int_4 = OpConstant %int 4
-         %56 = OpConstantComposite %BST %int_7 %int_n1 %int_n1
-         %57 = OpConstantComposite %BST %int_8 %int_n1 %int_n1
-         %58 = OpConstantComposite %BST %int_2 %int_n1 %int_n1
-         %59 = OpConstantComposite %BST %int_6 %int_n1 %int_n1
-         %60 = OpConstantComposite %BST %int_17 %int_n1 %int_n1
-         %61 = OpConstantComposite %BST %int_13 %int_n1 %int_n1
-       %main = OpFunction %void None %10
-         %62 = OpLabel
-       %tree = OpVariable %_ptr_Function__arr_BST_uint_10 Function
-         %63 = OpAccessChain %_ptr_Function_BST %tree %int_0
-               OpStore %63 %50
-               OpSelectionMerge %64 None
-               OpSwitch %uint_0 %65
-         %65 = OpLabel
-               OpBranch %66
-         %66 = OpLabel
-         %67 = OpPhi %bool %false %65 %68 %69
-         %70 = OpPhi %int %int_0 %65 %71 %69
-         %72 = OpSLessThanEqual %bool %70 %int_1
-               OpLoopMerge %73 %69 None
-               OpBranchConditional %72 %74 %73
-         %74 = OpLabel
-         %75 = OpAccessChain %_ptr_Function_int %tree %70 %int_0
-         %76 = OpLoad %int %75
-         %77 = OpSLessThanEqual %bool %int_5 %76
-               OpSelectionMerge %78 None
-               OpBranchConditional %77 %79 %80
-         %80 = OpLabel
-         %81 = OpAccessChain %_ptr_Function_int %tree %70 %int_2
-         %82 = OpLoad %int %81
-         %83 = OpIEqual %bool %82 %int_n1
-               OpSelectionMerge %84 None
-               OpBranchConditional %83 %85 %86
-         %86 = OpLabel
-         %87 = OpLoad %int %81
-               OpBranch %69
-         %85 = OpLabel
-               OpStore %81 %int_1
-         %88 = OpAccessChain %_ptr_Function_BST %tree %int_1
-               OpStore %88 %51
-               OpBranch %73
-         %84 = OpLabel
-               OpUnreachable
-         %79 = OpLabel
-         %89 = OpAccessChain %_ptr_Function_int %tree %70 %int_1
-         %90 = OpLoad %int %89
-         %91 = OpIEqual %bool %90 %int_n1
-               OpSelectionMerge %92 None
-               OpBranchConditional %91 %93 %94
-         %94 = OpLabel
-         %95 = OpLoad %int %89
-               OpBranch %69
-         %93 = OpLabel
-         %96 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_1
-         %97 = OpLoad %float %96
-         %98 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_0
-         %99 = OpLoad %float %98
-        %100 = OpFOrdLessThan %bool %97 %99
-               OpSelectionMerge %101 None
-               OpBranchConditional %100 %102 %101
-        %102 = OpLabel
-               OpBranch %103
-        %103 = OpLabel
-               OpLoopMerge %104 %105 None
-               OpBranch %106
-        %106 = OpLabel
-               OpKill
-        %105 = OpLabel
-               OpBranch %103
-        %104 = OpLabel
-               OpUnreachable
-        %101 = OpLabel
-               OpStore %89 %int_1
-        %107 = OpAccessChain %_ptr_Function_BST %tree %int_1
-               OpStore %107 %51
-               OpBranch %108
-        %108 = OpLabel
-        %109 = OpConvertFToS %int %97
-        %110 = OpSLessThan %bool %int_0 %109
-               OpLoopMerge %111 %112 None
-               OpBranchConditional %110 %113 %111
-        %113 = OpLabel
-               OpBranch %111
-        %112 = OpLabel
-               OpBranch %108
-        %111 = OpLabel
-        %114 = OpPhi %bool %67 %108 %true %113
-               OpSelectionMerge %115 None
-               OpBranchConditional %114 %73 %115
-        %115 = OpLabel
-               OpBranch %92
-         %92 = OpLabel
-               OpBranch %78
-         %78 = OpLabel
-               OpBranch %69
-         %69 = OpLabel
-         %68 = OpPhi %bool %67 %94 %67 %86 %114 %78
-         %71 = OpPhi %int %95 %94 %87 %86 %70 %78
-               OpBranch %66
-         %73 = OpLabel
-        %116 = OpPhi %bool %67 %66 %114 %111 %true %85
-               OpSelectionMerge %117 None
-               OpBranchConditional %116 %64 %117
-        %117 = OpLabel
-               OpBranch %64
-         %64 = OpLabel
-               OpBranch %118
-        %118 = OpLabel
-        %119 = OpPhi %int %int_0 %64 %120 %121
-               OpLoopMerge %122 %121 None
-               OpBranch %123
-        %123 = OpLabel
-        %124 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_1
-        %125 = OpLoad %float %124
-        %126 = OpFOrdLessThan %bool %125 %float_0
-        %127 = OpLogicalNot %bool %126
-               OpSelectionMerge %128 None
-               OpBranchConditional %127 %129 %128
-        %129 = OpLabel
-        %130 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_1
-        %131 = OpLoad %float %130
-        %132 = OpConvertFToS %int %131
-        %133 = OpINotEqual %bool %119 %132
-               OpBranch %128
-        %128 = OpLabel
-        %134 = OpPhi %bool %126 %123 %133 %129
-               OpBranchConditional %134 %135 %122
-        %135 = OpLabel
-               OpSelectionMerge %136 None
-               OpSwitch %uint_0 %137
-        %137 = OpLabel
-               OpBranch %138
-        %138 = OpLabel
-        %139 = OpPhi %bool %false %137 %140 %141
-        %142 = OpPhi %int %int_0 %137 %143 %141
-        %144 = OpSLessThanEqual %bool %142 %int_2
-               OpLoopMerge %145 %141 None
-               OpBranchConditional %144 %146 %145
-        %146 = OpLabel
-        %147 = OpAccessChain %_ptr_Function_int %tree %142 %int_0
-        %148 = OpLoad %int %147
-        %149 = OpSLessThanEqual %bool %int_12 %148
-               OpSelectionMerge %150 None
-               OpBranchConditional %149 %151 %152
-        %152 = OpLabel
-        %153 = OpAccessChain %_ptr_Function_int %tree %142 %int_2
-        %154 = OpLoad %int %153
-        %155 = OpIEqual %bool %154 %int_n1
-               OpSelectionMerge %156 None
-               OpBranchConditional %155 %157 %158
-        %158 = OpLabel
-        %159 = OpLoad %int %153
-               OpBranch %141
-        %157 = OpLabel
-               OpStore %153 %int_2
-        %160 = OpAccessChain %_ptr_Function_BST %tree %int_2
-               OpStore %160 %53
-               OpBranch %145
-        %156 = OpLabel
-               OpUnreachable
-        %151 = OpLabel
-        %161 = OpAccessChain %_ptr_Function_int %tree %142 %int_1
-        %162 = OpLoad %int %161
-        %163 = OpIEqual %bool %162 %int_n1
-               OpSelectionMerge %164 None
-               OpBranchConditional %163 %165 %166
-        %166 = OpLabel
-        %167 = OpLoad %int %161
-               OpBranch %141
-        %165 = OpLabel
-        %168 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_1
-        %169 = OpLoad %float %168
-        %170 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_0
-        %171 = OpLoad %float %170
-        %172 = OpFOrdLessThan %bool %169 %171
-               OpSelectionMerge %173 None
-               OpBranchConditional %172 %174 %173
-        %174 = OpLabel
-               OpBranch %175
-        %175 = OpLabel
-               OpLoopMerge %176 %177 None
-               OpBranch %178
-        %178 = OpLabel
-               OpKill
-        %177 = OpLabel
-               OpBranch %175
-        %176 = OpLabel
-               OpUnreachable
-        %173 = OpLabel
-               OpStore %161 %int_2
-        %179 = OpAccessChain %_ptr_Function_BST %tree %int_2
-               OpStore %179 %53
-               OpBranch %180
-        %180 = OpLabel
-        %181 = OpConvertFToS %int %169
-        %182 = OpSLessThan %bool %int_0 %181
-               OpLoopMerge %183 %184 None
-               OpBranchConditional %182 %185 %183
-        %185 = OpLabel
-               OpBranch %183
-        %184 = OpLabel
-               OpBranch %180
-        %183 = OpLabel
-        %186 = OpPhi %bool %139 %180 %true %185
-               OpSelectionMerge %187 None
-               OpBranchConditional %186 %145 %187
-        %187 = OpLabel
-               OpBranch %164
-        %164 = OpLabel
-               OpBranch %150
-        %150 = OpLabel
-               OpBranch %141
-        %141 = OpLabel
-        %140 = OpPhi %bool %139 %166 %139 %158 %186 %150
-        %143 = OpPhi %int %167 %166 %159 %158 %142 %150
-               OpBranch %138
-        %145 = OpLabel
-        %188 = OpPhi %bool %139 %138 %186 %183 %true %157
-               OpSelectionMerge %189 None
-               OpBranchConditional %188 %136 %189
-        %189 = OpLabel
-               OpBranch %136
-        %136 = OpLabel
-               OpBranch %121
-        %121 = OpLabel
-        %120 = OpIAdd %int %119 %int_1
-               OpBranch %118
-        %122 = OpLabel
-               OpSelectionMerge %190 None
-               OpSwitch %uint_0 %191
-        %191 = OpLabel
-               OpBranch %192
-        %192 = OpLabel
-        %193 = OpPhi %bool %false %191 %194 %195
-        %196 = OpPhi %int %int_0 %191 %197 %195
-        %198 = OpSLessThanEqual %bool %196 %int_3
-               OpLoopMerge %199 %195 None
-               OpBranchConditional %198 %200 %199
-        %200 = OpLabel
-        %201 = OpAccessChain %_ptr_Function_int %tree %196 %int_0
-        %202 = OpLoad %int %201
-        %203 = OpSLessThanEqual %bool %int_15 %202
-               OpSelectionMerge %204 None
-               OpBranchConditional %203 %205 %206
-        %206 = OpLabel
-        %207 = OpAccessChain %_ptr_Function_int %tree %196 %int_2
-        %208 = OpLoad %int %207
-        %209 = OpIEqual %bool %208 %int_n1
-               OpSelectionMerge %210 None
-               OpBranchConditional %209 %211 %212
-        %212 = OpLabel
-        %213 = OpLoad %int %207
-               OpBranch %195
-        %211 = OpLabel
-               OpStore %207 %int_3
-        %214 = OpAccessChain %_ptr_Function_BST %tree %int_3
-               OpStore %214 %54
-               OpBranch %199
-        %210 = OpLabel
-               OpUnreachable
-        %205 = OpLabel
-        %215 = OpAccessChain %_ptr_Function_int %tree %196 %int_1
-        %216 = OpLoad %int %215
-        %217 = OpIEqual %bool %216 %int_n1
-               OpSelectionMerge %218 None
-               OpBranchConditional %217 %219 %220
-        %220 = OpLabel
-        %221 = OpLoad %int %215
-               OpBranch %195
-        %219 = OpLabel
-        %222 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_1
-        %223 = OpLoad %float %222
-        %224 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_0
-        %225 = OpLoad %float %224
-        %226 = OpFOrdLessThan %bool %223 %225
-               OpSelectionMerge %227 None
-               OpBranchConditional %226 %228 %227
-        %228 = OpLabel
-               OpBranch %229
-        %229 = OpLabel
-               OpLoopMerge %230 %231 None
-               OpBranch %232
-        %232 = OpLabel
-               OpKill
-        %231 = OpLabel
-               OpBranch %229
-        %230 = OpLabel
-               OpUnreachable
-        %227 = OpLabel
-               OpStore %215 %int_3
-        %233 = OpAccessChain %_ptr_Function_BST %tree %int_3
-               OpStore %233 %54
-               OpBranch %234
-        %234 = OpLabel
-        %235 = OpConvertFToS %int %223
-        %236 = OpSLessThan %bool %int_0 %235
-               OpLoopMerge %237 %238 None
-               OpBranchConditional %236 %239 %237
-        %239 = OpLabel
-               OpBranch %237
-        %238 = OpLabel
-               OpBranch %234
-        %237 = OpLabel
-        %240 = OpPhi %bool %193 %234 %true %239
-               OpSelectionMerge %241 None
-               OpBranchConditional %240 %199 %241
-        %241 = OpLabel
-               OpBranch %218
-        %218 = OpLabel
-               OpBranch %204
-        %204 = OpLabel
-               OpBranch %195
-        %195 = OpLabel
-        %194 = OpPhi %bool %193 %220 %193 %212 %240 %204
-        %197 = OpPhi %int %221 %220 %213 %212 %196 %204
-               OpBranch %192
-        %199 = OpLabel
-        %242 = OpPhi %bool %193 %192 %240 %237 %true %211
-               OpSelectionMerge %243 None
-               OpBranchConditional %242 %190 %243
-        %243 = OpLabel
-               OpBranch %190
-        %190 = OpLabel
-               OpSelectionMerge %244 None
-               OpSwitch %uint_0 %245
-        %245 = OpLabel
-               OpBranch %246
-        %246 = OpLabel
-        %247 = OpPhi %bool %false %245 %248 %249
-        %250 = OpPhi %int %int_0 %245 %251 %249
-        %252 = OpSLessThanEqual %bool %250 %int_4
-               OpLoopMerge %253 %249 None
-               OpBranchConditional %252 %254 %253
-        %254 = OpLabel
-        %255 = OpAccessChain %_ptr_Function_int %tree %250 %int_0
-        %256 = OpLoad %int %255
-        %257 = OpSLessThanEqual %bool %int_7 %256
-               OpSelectionMerge %258 None
-               OpBranchConditional %257 %259 %260
-        %260 = OpLabel
-        %261 = OpAccessChain %_ptr_Function_int %tree %250 %int_2
-        %262 = OpLoad %int %261
-        %263 = OpIEqual %bool %262 %int_n1
-               OpSelectionMerge %264 None
-               OpBranchConditional %263 %265 %266
-        %266 = OpLabel
-        %267 = OpLoad %int %261
-               OpBranch %249
-        %265 = OpLabel
-               OpStore %261 %int_4
-        %268 = OpAccessChain %_ptr_Function_BST %tree %int_4
-               OpStore %268 %56
-               OpBranch %253
-        %264 = OpLabel
-               OpUnreachable
-        %259 = OpLabel
-        %269 = OpAccessChain %_ptr_Function_int %tree %250 %int_1
-        %270 = OpLoad %int %269
-        %271 = OpIEqual %bool %270 %int_n1
-               OpSelectionMerge %272 None
-               OpBranchConditional %271 %273 %274
-        %274 = OpLabel
-        %275 = OpLoad %int %269
-               OpBranch %249
-        %273 = OpLabel
-        %276 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_1
-        %277 = OpLoad %float %276
-        %278 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_0
-        %279 = OpLoad %float %278
-        %280 = OpFOrdLessThan %bool %277 %279
-               OpSelectionMerge %281 None
-               OpBranchConditional %280 %282 %281
-        %282 = OpLabel
-               OpBranch %283
-        %283 = OpLabel
-               OpLoopMerge %284 %285 None
-               OpBranch %286
-        %286 = OpLabel
-               OpKill
-        %285 = OpLabel
-               OpBranch %283
-        %284 = OpLabel
-               OpUnreachable
-        %281 = OpLabel
-               OpStore %269 %int_4
-        %287 = OpAccessChain %_ptr_Function_BST %tree %int_4
-               OpStore %287 %56
-               OpBranch %288
-        %288 = OpLabel
-        %289 = OpConvertFToS %int %277
-        %290 = OpSLessThan %bool %int_0 %289
-               OpLoopMerge %291 %292 None
-               OpBranchConditional %290 %293 %291
-        %293 = OpLabel
-               OpBranch %291
-        %292 = OpLabel
-               OpBranch %288
-        %291 = OpLabel
-        %294 = OpPhi %bool %247 %288 %true %293
-               OpSelectionMerge %295 None
-               OpBranchConditional %294 %253 %295
-        %295 = OpLabel
-               OpBranch %272
-        %272 = OpLabel
-               OpBranch %258
-        %258 = OpLabel
-               OpBranch %249
-        %249 = OpLabel
-        %248 = OpPhi %bool %247 %274 %247 %266 %294 %258
-        %251 = OpPhi %int %275 %274 %267 %266 %250 %258
-               OpBranch %246
-        %253 = OpLabel
-        %296 = OpPhi %bool %247 %246 %294 %291 %true %265
-               OpSelectionMerge %297 None
-               OpBranchConditional %296 %244 %297
-        %297 = OpLabel
-               OpBranch %244
-        %244 = OpLabel
-               OpSelectionMerge %298 None
-               OpSwitch %uint_0 %299
-        %299 = OpLabel
-               OpBranch %300
-        %300 = OpLabel
-        %301 = OpPhi %bool %false %299 %302 %303
-        %304 = OpPhi %int %int_0 %299 %305 %303
-        %306 = OpSLessThanEqual %bool %304 %int_5
-               OpLoopMerge %307 %303 None
-               OpBranchConditional %306 %308 %307
-        %308 = OpLabel
-        %309 = OpAccessChain %_ptr_Function_int %tree %304 %int_0
-        %310 = OpLoad %int %309
-        %311 = OpSLessThanEqual %bool %int_8 %310
-               OpSelectionMerge %312 None
-               OpBranchConditional %311 %313 %314
-        %314 = OpLabel
-        %315 = OpAccessChain %_ptr_Function_int %tree %304 %int_2
-        %316 = OpLoad %int %315
-        %317 = OpIEqual %bool %316 %int_n1
-               OpSelectionMerge %318 None
-               OpBranchConditional %317 %319 %320
-        %320 = OpLabel
-        %321 = OpLoad %int %315
-               OpBranch %303
-        %319 = OpLabel
-               OpStore %315 %int_5
-        %322 = OpAccessChain %_ptr_Function_BST %tree %int_5
-               OpStore %322 %57
-               OpBranch %307
-        %318 = OpLabel
-               OpUnreachable
-        %313 = OpLabel
-        %323 = OpAccessChain %_ptr_Function_int %tree %304 %int_1
-        %324 = OpLoad %int %323
-        %325 = OpIEqual %bool %324 %int_n1
-               OpSelectionMerge %326 None
-               OpBranchConditional %325 %327 %328
-        %328 = OpLabel
-        %329 = OpLoad %int %323
-               OpBranch %303
-        %327 = OpLabel
-        %330 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_1
-        %331 = OpLoad %float %330
-        %332 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_0
-        %333 = OpLoad %float %332
-        %334 = OpFOrdLessThan %bool %331 %333
-               OpSelectionMerge %335 None
-               OpBranchConditional %334 %336 %335
-        %336 = OpLabel
-               OpBranch %337
-        %337 = OpLabel
-               OpLoopMerge %338 %339 None
-               OpBranch %340
-        %340 = OpLabel
-               OpKill
-        %339 = OpLabel
-               OpBranch %337
-        %338 = OpLabel
-               OpUnreachable
-        %335 = OpLabel
-               OpStore %323 %int_5
-        %341 = OpAccessChain %_ptr_Function_BST %tree %int_5
-               OpStore %341 %57
-               OpBranch %342
-        %342 = OpLabel
-        %343 = OpConvertFToS %int %331
-        %344 = OpSLessThan %bool %int_0 %343
-               OpLoopMerge %345 %346 None
-               OpBranchConditional %344 %347 %345
-        %347 = OpLabel
-               OpBranch %345
-        %346 = OpLabel
-               OpBranch %342
-        %345 = OpLabel
-        %348 = OpPhi %bool %301 %342 %true %347
-               OpSelectionMerge %349 None
-               OpBranchConditional %348 %307 %349
-        %349 = OpLabel
-               OpBranch %326
-        %326 = OpLabel
-               OpBranch %312
-        %312 = OpLabel
-               OpBranch %303
-        %303 = OpLabel
-        %302 = OpPhi %bool %301 %328 %301 %320 %348 %312
-        %305 = OpPhi %int %329 %328 %321 %320 %304 %312
-               OpBranch %300
-        %307 = OpLabel
-        %350 = OpPhi %bool %301 %300 %348 %345 %true %319
-               OpSelectionMerge %351 None
-               OpBranchConditional %350 %298 %351
-        %351 = OpLabel
-               OpBranch %298
-        %298 = OpLabel
-               OpSelectionMerge %352 None
-               OpSwitch %uint_0 %353
-        %353 = OpLabel
-               OpBranch %354
-        %354 = OpLabel
-        %355 = OpPhi %bool %false %353 %356 %357
-        %358 = OpPhi %int %int_0 %353 %359 %357
-        %360 = OpSLessThanEqual %bool %358 %int_6
-               OpLoopMerge %361 %357 None
-               OpBranchConditional %360 %362 %361
-        %362 = OpLabel
-        %363 = OpAccessChain %_ptr_Function_int %tree %358 %int_0
-        %364 = OpLoad %int %363
-        %365 = OpSLessThanEqual %bool %int_2 %364
-               OpSelectionMerge %366 None
-               OpBranchConditional %365 %367 %368
-        %368 = OpLabel
-        %369 = OpAccessChain %_ptr_Function_int %tree %358 %int_2
-        %370 = OpLoad %int %369
-        %371 = OpIEqual %bool %370 %int_n1
-               OpSelectionMerge %372 None
-               OpBranchConditional %371 %373 %374
-        %374 = OpLabel
-        %375 = OpLoad %int %369
-               OpBranch %357
-        %373 = OpLabel
-               OpStore %369 %int_6
-        %376 = OpAccessChain %_ptr_Function_BST %tree %int_6
-               OpStore %376 %58
-               OpBranch %361
-        %372 = OpLabel
-               OpUnreachable
-        %367 = OpLabel
-        %377 = OpAccessChain %_ptr_Function_int %tree %358 %int_1
-        %378 = OpLoad %int %377
-        %379 = OpIEqual %bool %378 %int_n1
-               OpSelectionMerge %380 None
-               OpBranchConditional %379 %381 %382
-        %382 = OpLabel
-        %383 = OpLoad %int %377
-               OpBranch %357
-        %381 = OpLabel
-        %384 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_1
-        %385 = OpLoad %float %384
-        %386 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_0
-        %387 = OpLoad %float %386
-        %388 = OpFOrdLessThan %bool %385 %387
-               OpSelectionMerge %389 None
-               OpBranchConditional %388 %390 %389
-        %390 = OpLabel
-               OpBranch %391
-        %391 = OpLabel
-               OpLoopMerge %392 %393 None
-               OpBranch %394
-        %394 = OpLabel
-               OpKill
-        %393 = OpLabel
-               OpBranch %391
-        %392 = OpLabel
-               OpUnreachable
-        %389 = OpLabel
-               OpStore %377 %int_6
-        %395 = OpAccessChain %_ptr_Function_BST %tree %int_6
-               OpStore %395 %58
-               OpBranch %396
-        %396 = OpLabel
-        %397 = OpConvertFToS %int %385
-        %398 = OpSLessThan %bool %int_0 %397
-               OpLoopMerge %399 %400 None
-               OpBranchConditional %398 %401 %399
-        %401 = OpLabel
-               OpBranch %399
-        %400 = OpLabel
-               OpBranch %396
-        %399 = OpLabel
-        %402 = OpPhi %bool %355 %396 %true %401
-               OpSelectionMerge %403 None
-               OpBranchConditional %402 %361 %403
-        %403 = OpLabel
-               OpBranch %380
-        %380 = OpLabel
-               OpBranch %366
-        %366 = OpLabel
-               OpBranch %357
-        %357 = OpLabel
-        %356 = OpPhi %bool %355 %382 %355 %374 %402 %366
-        %359 = OpPhi %int %383 %382 %375 %374 %358 %366
-               OpBranch %354
-        %361 = OpLabel
-        %404 = OpPhi %bool %355 %354 %402 %399 %true %373
-               OpSelectionMerge %405 None
-               OpBranchConditional %404 %352 %405
-        %405 = OpLabel
-               OpBranch %352
-        %352 = OpLabel
-               OpSelectionMerge %406 None
-               OpSwitch %uint_0 %407
-        %407 = OpLabel
-               OpBranch %408
-        %408 = OpLabel
-        %409 = OpPhi %bool %false %407 %410 %411
-        %412 = OpPhi %int %int_0 %407 %413 %411
-        %414 = OpSLessThanEqual %bool %412 %int_7
-               OpLoopMerge %415 %411 None
-               OpBranchConditional %414 %416 %415
-        %416 = OpLabel
-        %417 = OpAccessChain %_ptr_Function_int %tree %412 %int_0
-        %418 = OpLoad %int %417
-        %419 = OpSLessThanEqual %bool %int_6 %418
-               OpSelectionMerge %420 None
-               OpBranchConditional %419 %421 %422
-        %422 = OpLabel
-        %423 = OpAccessChain %_ptr_Function_int %tree %412 %int_2
-        %424 = OpLoad %int %423
-        %425 = OpIEqual %bool %424 %int_n1
-               OpSelectionMerge %426 None
-               OpBranchConditional %425 %427 %428
-        %428 = OpLabel
-        %429 = OpLoad %int %423
-               OpBranch %411
-        %427 = OpLabel
-               OpStore %423 %int_7
-        %430 = OpAccessChain %_ptr_Function_BST %tree %int_7
-               OpStore %430 %59
-               OpBranch %415
-        %426 = OpLabel
-               OpUnreachable
-        %421 = OpLabel
-        %431 = OpAccessChain %_ptr_Function_int %tree %412 %int_1
-        %432 = OpLoad %int %431
-        %433 = OpIEqual %bool %432 %int_n1
-               OpSelectionMerge %434 None
-               OpBranchConditional %433 %435 %436
-        %436 = OpLabel
-        %437 = OpLoad %int %431
-               OpBranch %411
-        %435 = OpLabel
-        %438 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_1
-        %439 = OpLoad %float %438
-        %440 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_0
-        %441 = OpLoad %float %440
-        %442 = OpFOrdLessThan %bool %439 %441
-               OpSelectionMerge %443 None
-               OpBranchConditional %442 %444 %443
-        %444 = OpLabel
-               OpBranch %445
-        %445 = OpLabel
-               OpLoopMerge %446 %447 None
-               OpBranch %448
-        %448 = OpLabel
-               OpKill
-        %447 = OpLabel
-               OpBranch %445
-        %446 = OpLabel
-               OpUnreachable
-        %443 = OpLabel
-               OpStore %431 %int_7
-        %449 = OpAccessChain %_ptr_Function_BST %tree %int_7
-               OpStore %449 %59
-               OpBranch %450
-        %450 = OpLabel
-        %451 = OpConvertFToS %int %439
-        %452 = OpSLessThan %bool %int_0 %451
-               OpLoopMerge %453 %454 None
-               OpBranchConditional %452 %455 %453
-        %455 = OpLabel
-               OpBranch %453
-        %454 = OpLabel
-               OpBranch %450
-        %453 = OpLabel
-        %456 = OpPhi %bool %409 %450 %true %455
-               OpSelectionMerge %457 None
-               OpBranchConditional %456 %415 %457
-        %457 = OpLabel
-               OpBranch %434
-        %434 = OpLabel
-               OpBranch %420
-        %420 = OpLabel
-               OpBranch %411
-        %411 = OpLabel
-        %410 = OpPhi %bool %409 %436 %409 %428 %456 %420
-        %413 = OpPhi %int %437 %436 %429 %428 %412 %420
-               OpBranch %408
-        %415 = OpLabel
-        %458 = OpPhi %bool %409 %408 %456 %453 %true %427
-               OpSelectionMerge %459 None
-               OpBranchConditional %458 %406 %459
-        %459 = OpLabel
-               OpBranch %406
-        %406 = OpLabel
-               OpSelectionMerge %460 None
-               OpSwitch %uint_0 %461
-        %461 = OpLabel
-               OpBranch %462
-        %462 = OpLabel
-        %463 = OpPhi %bool %false %461 %464 %465
-        %466 = OpPhi %int %int_0 %461 %467 %465
-        %468 = OpSLessThanEqual %bool %466 %int_8
-               OpLoopMerge %469 %465 None
-               OpBranchConditional %468 %470 %469
-        %470 = OpLabel
-        %471 = OpAccessChain %_ptr_Function_int %tree %466 %int_0
-        %472 = OpLoad %int %471
-        %473 = OpSLessThanEqual %bool %int_17 %472
-               OpSelectionMerge %474 None
-               OpBranchConditional %473 %475 %476
-        %476 = OpLabel
-        %477 = OpAccessChain %_ptr_Function_int %tree %466 %int_2
-        %478 = OpLoad %int %477
-        %479 = OpIEqual %bool %478 %int_n1
-               OpSelectionMerge %480 None
-               OpBranchConditional %479 %481 %482
-        %482 = OpLabel
-        %483 = OpLoad %int %477
-               OpBranch %465
-        %481 = OpLabel
-               OpStore %477 %int_8
-        %484 = OpAccessChain %_ptr_Function_BST %tree %int_8
-               OpStore %484 %60
-               OpBranch %469
-        %480 = OpLabel
-               OpUnreachable
-        %475 = OpLabel
-        %485 = OpAccessChain %_ptr_Function_int %tree %466 %int_1
-        %486 = OpLoad %int %485
-        %487 = OpIEqual %bool %486 %int_n1
-               OpSelectionMerge %488 None
-               OpBranchConditional %487 %489 %490
-        %490 = OpLabel
-        %491 = OpLoad %int %485
-               OpBranch %465
-        %489 = OpLabel
-        %492 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_1
-        %493 = OpLoad %float %492
-        %494 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_0
-        %495 = OpLoad %float %494
-        %496 = OpFOrdLessThan %bool %493 %495
-               OpSelectionMerge %497 None
-               OpBranchConditional %496 %498 %497
-        %498 = OpLabel
-               OpBranch %499
-        %499 = OpLabel
-               OpLoopMerge %500 %501 None
-               OpBranch %502
-        %502 = OpLabel
-               OpKill
-        %501 = OpLabel
-               OpBranch %499
-        %500 = OpLabel
-               OpUnreachable
-        %497 = OpLabel
-               OpStore %485 %int_8
-        %503 = OpAccessChain %_ptr_Function_BST %tree %int_8
-               OpStore %503 %60
-               OpBranch %504
-        %504 = OpLabel
-        %505 = OpConvertFToS %int %493
-        %506 = OpSLessThan %bool %int_0 %505
-               OpLoopMerge %507 %508 None
-               OpBranchConditional %506 %509 %507
-        %509 = OpLabel
-               OpBranch %507
-        %508 = OpLabel
-               OpBranch %504
-        %507 = OpLabel
-        %510 = OpPhi %bool %463 %504 %true %509
-               OpSelectionMerge %511 None
-               OpBranchConditional %510 %469 %511
-        %511 = OpLabel
-               OpBranch %488
-        %488 = OpLabel
-               OpBranch %474
-        %474 = OpLabel
-               OpBranch %465
-        %465 = OpLabel
-        %464 = OpPhi %bool %463 %490 %463 %482 %510 %474
-        %467 = OpPhi %int %491 %490 %483 %482 %466 %474
-               OpBranch %462
-        %469 = OpLabel
-        %512 = OpPhi %bool %463 %462 %510 %507 %true %481
-               OpSelectionMerge %513 None
-               OpBranchConditional %512 %460 %513
-        %513 = OpLabel
-               OpBranch %460
-        %460 = OpLabel
-               OpSelectionMerge %514 None
-               OpSwitch %uint_0 %515
-        %515 = OpLabel
-               OpBranch %516
-        %516 = OpLabel
-        %517 = OpPhi %bool %false %515 %518 %519
-        %520 = OpPhi %int %int_0 %515 %521 %519
-        %522 = OpSLessThanEqual %bool %520 %int_9
-               OpLoopMerge %523 %519 None
-               OpBranchConditional %522 %524 %523
-        %524 = OpLabel
-        %525 = OpAccessChain %_ptr_Function_int %tree %520 %int_0
-        %526 = OpLoad %int %525
-        %527 = OpSLessThanEqual %bool %int_13 %526
-               OpSelectionMerge %528 None
-               OpBranchConditional %527 %529 %530
-        %530 = OpLabel
-        %531 = OpAccessChain %_ptr_Function_int %tree %520 %int_2
-        %532 = OpLoad %int %531
-        %533 = OpIEqual %bool %532 %int_n1
-               OpSelectionMerge %534 None
-               OpBranchConditional %533 %535 %536
-        %536 = OpLabel
-        %537 = OpLoad %int %531
-               OpBranch %519
-        %535 = OpLabel
-               OpStore %531 %int_9
-        %538 = OpAccessChain %_ptr_Function_BST %tree %int_9
-               OpStore %538 %61
-               OpBranch %523
-        %534 = OpLabel
-               OpUnreachable
-        %529 = OpLabel
-        %539 = OpAccessChain %_ptr_Function_int %tree %520 %int_1
-        %540 = OpLoad %int %539
-        %541 = OpIEqual %bool %540 %int_n1
-               OpSelectionMerge %542 None
-               OpBranchConditional %541 %543 %544
-        %544 = OpLabel
-        %545 = OpLoad %int %539
-               OpBranch %519
-        %543 = OpLabel
-        %546 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_1
-        %547 = OpLoad %float %546
-        %548 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %uint_0
-        %549 = OpLoad %float %548
-        %550 = OpFOrdLessThan %bool %547 %549
-               OpSelectionMerge %551 None
-               OpBranchConditional %550 %552 %551
-        %552 = OpLabel
-               OpBranch %553
-        %553 = OpLabel
-               OpLoopMerge %554 %555 None
-               OpBranch %556
-        %556 = OpLabel
-               OpKill
-        %555 = OpLabel
-               OpBranch %553
-        %554 = OpLabel
-               OpUnreachable
-        %551 = OpLabel
-               OpStore %539 %int_9
-        %557 = OpAccessChain %_ptr_Function_BST %tree %int_9
-               OpStore %557 %61
-               OpBranch %558
-        %558 = OpLabel
-        %559 = OpConvertFToS %int %547
-        %560 = OpSLessThan %bool %int_0 %559
-               OpLoopMerge %561 %562 None
-               OpBranchConditional %560 %563 %561
-        %563 = OpLabel
-               OpBranch %561
-        %562 = OpLabel
-               OpBranch %558
-        %561 = OpLabel
-        %564 = OpPhi %bool %517 %558 %true %563
-               OpSelectionMerge %565 None
-               OpBranchConditional %564 %523 %565
-        %565 = OpLabel
-               OpBranch %542
-        %542 = OpLabel
-               OpBranch %528
-        %528 = OpLabel
-               OpBranch %519
-        %519 = OpLabel
-        %518 = OpPhi %bool %517 %544 %517 %536 %564 %528
-        %521 = OpPhi %int %545 %544 %537 %536 %520 %528
-               OpBranch %516
-        %523 = OpLabel
-        %566 = OpPhi %bool %517 %516 %564 %561 %true %535
-               OpSelectionMerge %567 None
-               OpBranchConditional %566 %514 %567
-        %567 = OpLabel
-               OpBranch %514
-        %514 = OpLabel
-               OpBranch %568
-        %568 = OpLabel
-        %569 = OpPhi %int %49 %514 %570 %571
-        %572 = OpPhi %int %int_0 %514 %573 %571
-        %574 = OpPhi %int %int_0 %514 %575 %571
-        %576 = OpSLessThan %bool %574 %int_20
-               OpLoopMerge %577 %571 None
-               OpBranchConditional %576 %578 %577
-        %578 = OpLabel
-               OpSelectionMerge %579 None
-               OpSwitch %uint_0 %580
-        %580 = OpLabel
-               OpBranch %581
-        %581 = OpLabel
-        %582 = OpPhi %int %int_0 %580 %583 %584
-        %585 = OpINotEqual %bool %582 %int_n1
-               OpLoopMerge %586 %584 None
-               OpBranchConditional %585 %587 %586
-        %587 = OpLabel
-        %588 = OpAccessChain %_ptr_Function_BST %tree %582
-        %589 = OpLoad %BST %588
-        %590 = OpCompositeExtract %int %589 0
-        %591 = OpCompositeExtract %int %589 1
-        %592 = OpCompositeExtract %int %589 2
-        %593 = OpIEqual %bool %590 %574
-               OpSelectionMerge %594 None
-               OpBranchConditional %593 %595 %594
-        %595 = OpLabel
-               OpBranch %586
-        %594 = OpLabel
-        %596 = OpSGreaterThan %bool %574 %590
-        %583 = OpSelect %int %596 %592 %591
-               OpBranch %584
-        %584 = OpLabel
-               OpBranch %581
-        %586 = OpLabel
-        %597 = OpPhi %int %569 %581 %574 %595
-        %598 = OpPhi %bool %false %581 %true %595
-               OpSelectionMerge %599 None
-               OpBranchConditional %598 %579 %599
-        %599 = OpLabel
-               OpBranch %579
-        %579 = OpLabel
-        %570 = OpPhi %int %597 %586 %int_n1 %599
-               OpSelectionMerge %600 None
-               OpSwitch %574 %601 9 %602 5 %602 12 %602 15 %602 7 %602 8 %602 2 %602 6 %602 17 %602 13 %602
-        %602 = OpLabel
-        %603 = OpIEqual %bool %570 %574
-               OpSelectionMerge %604 None
-               OpBranchConditional %603 %605 %604
-        %605 = OpLabel
-        %606 = OpIAdd %int %572 %int_1
-               OpBranch %604
-        %604 = OpLabel
-        %607 = OpPhi %int %572 %602 %606 %605
-               OpBranch %600
-        %601 = OpLabel
-        %608 = OpIEqual %bool %570 %int_n1
-               OpSelectionMerge %609 None
-               OpBranchConditional %608 %610 %609
-        %610 = OpLabel
-        %611 = OpIAdd %int %572 %int_1
-               OpBranch %609
-        %609 = OpLabel
-        %612 = OpPhi %int %572 %601 %611 %610
-               OpBranch %600
-        %600 = OpLabel
-        %573 = OpPhi %int %612 %609 %607 %604
-               OpBranch %571
-        %571 = OpLabel
-        %575 = OpIAdd %int %574 %int_1
-               OpBranch %568
-        %577 = OpLabel
-        %613 = OpIEqual %bool %572 %int_20
-               OpSelectionMerge %614 None
-               OpBranchConditional %613 %615 %616
-        %616 = OpLabel
-               OpStore %_GLF_color %45
-               OpBranch %614
-        %615 = OpLabel
-               OpStore %_GLF_color %44
-               OpBranch %614
-        %614 = OpLabel
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.wgsl b/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.wgsl
deleted file mode 100644
index 8fe63ef..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.wgsl
+++ /dev/null
@@ -1,958 +0,0 @@
-struct BST {
-  data : i32,
-  leftIndex : i32,
-  rightIndex : i32,
-}
-
-struct buf0 {
-  injectionSwitch : vec2<f32>,
-}
-
-@group(0) @binding(0) var<uniform> x_8 : buf0;
-
-var<private> gl_FragCoord : vec4<f32>;
-
-var<private> x_GLF_color : vec4<f32>;
-
-fn main_1() {
-  var tree : array<BST, 10u>;
-  var x_67 : bool;
-  var x_114 : bool;
-  var x_572 : i32;
-  var x_67_phi : bool;
-  var x_70_phi : i32;
-  var x_116_phi : bool;
-  var x_119_phi : i32;
-  var x_569_phi : i32;
-  var x_572_phi : i32;
-  var x_574_phi : i32;
-  tree[0] = BST(9, -1, -1);
-  switch(0u) {
-    default: {
-      x_67_phi = false;
-      x_70_phi = 0;
-      loop {
-        var x_95 : i32;
-        var x_87 : i32;
-        var x_68 : bool;
-        var x_71 : i32;
-        var x_68_phi : bool;
-        var x_71_phi : i32;
-        x_67 = x_67_phi;
-        let x_70 : i32 = x_70_phi;
-        x_116_phi = x_67;
-        if ((x_70 <= 1)) {
-        } else {
-          break;
-        }
-        let x_76 : i32 = tree[x_70].data;
-        if ((5 <= x_76)) {
-          var x_114_phi : bool;
-          let x_89_save = x_70;
-          let x_90 : i32 = tree[x_89_save].leftIndex;
-          if ((x_90 == -1)) {
-            let x_97 : f32 = x_8.injectionSwitch.y;
-            let x_99 : f32 = x_8.injectionSwitch.x;
-            if ((x_97 < x_99)) {
-              loop {
-                discard;
-              }
-            }
-            tree[x_89_save].leftIndex = 1;
-            tree[1] = BST(5, -1, -1);
-            loop {
-              x_114_phi = x_67;
-              if ((0 < i32(x_97))) {
-              } else {
-                break;
-              }
-              x_114_phi = true;
-              break;
-            }
-            x_114 = x_114_phi;
-            x_116_phi = x_114;
-            if (x_114) {
-              break;
-            }
-          } else {
-            x_95 = tree[x_89_save].leftIndex;
-            x_68_phi = x_67;
-            x_71_phi = x_95;
-            continue;
-          }
-        } else {
-          let x_81_save = x_70;
-          let x_82 : i32 = tree[x_81_save].rightIndex;
-          if ((x_82 == -1)) {
-            tree[x_81_save].rightIndex = 1;
-            tree[1] = BST(5, -1, -1);
-            x_116_phi = true;
-            break;
-          } else {
-            x_87 = tree[x_81_save].rightIndex;
-            x_68_phi = x_67;
-            x_71_phi = x_87;
-            continue;
-          }
-        }
-        x_68_phi = x_114;
-        x_71_phi = x_70;
-
-        continuing {
-          x_68 = x_68_phi;
-          x_71 = x_71_phi;
-          x_67_phi = x_68;
-          x_70_phi = x_71;
-        }
-      }
-      let x_116 : bool = x_116_phi;
-      if (x_116) {
-        break;
-      }
-    }
-  }
-  x_119_phi = 0;
-  loop {
-    var x_133 : bool;
-    var x_120 : i32;
-    var x_134_phi : bool;
-    let x_119 : i32 = x_119_phi;
-    let x_125 : f32 = gl_FragCoord.y;
-    let x_126 : bool = (x_125 < 0.0);
-    x_134_phi = x_126;
-    if (!(x_126)) {
-      let x_131 : f32 = x_8.injectionSwitch.y;
-      x_133 = (x_119 != i32(x_131));
-      x_134_phi = x_133;
-    }
-    let x_134 : bool = x_134_phi;
-    if (x_134) {
-    } else {
-      break;
-    }
-    var x_139 : bool;
-    var x_186 : bool;
-    var x_139_phi : bool;
-    var x_142_phi : i32;
-    var x_188_phi : bool;
-    switch(0u) {
-      default: {
-        x_139_phi = false;
-        x_142_phi = 0;
-        loop {
-          var x_167 : i32;
-          var x_159 : i32;
-          var x_140 : bool;
-          var x_143 : i32;
-          var x_140_phi : bool;
-          var x_143_phi : i32;
-          x_139 = x_139_phi;
-          let x_142 : i32 = x_142_phi;
-          x_188_phi = x_139;
-          if ((x_142 <= 2)) {
-          } else {
-            break;
-          }
-          let x_148 : i32 = tree[x_142].data;
-          if ((12 <= x_148)) {
-            var x_186_phi : bool;
-            let x_161_save = x_142;
-            let x_162 : i32 = tree[x_161_save].leftIndex;
-            if ((x_162 == -1)) {
-              let x_169 : f32 = x_8.injectionSwitch.y;
-              let x_171 : f32 = x_8.injectionSwitch.x;
-              if ((x_169 < x_171)) {
-                loop {
-                  discard;
-                }
-              }
-              tree[x_161_save].leftIndex = 2;
-              tree[2] = BST(12, -1, -1);
-              loop {
-                x_186_phi = x_139;
-                if ((0 < i32(x_169))) {
-                } else {
-                  break;
-                }
-                x_186_phi = true;
-                break;
-              }
-              x_186 = x_186_phi;
-              x_188_phi = x_186;
-              if (x_186) {
-                break;
-              }
-            } else {
-              x_167 = tree[x_161_save].leftIndex;
-              x_140_phi = x_139;
-              x_143_phi = x_167;
-              continue;
-            }
-          } else {
-            let x_153_save = x_142;
-            let x_154 : i32 = tree[x_153_save].rightIndex;
-            if ((x_154 == -1)) {
-              tree[x_153_save].rightIndex = 2;
-              tree[2] = BST(12, -1, -1);
-              x_188_phi = true;
-              break;
-            } else {
-              x_159 = tree[x_153_save].rightIndex;
-              x_140_phi = x_139;
-              x_143_phi = x_159;
-              continue;
-            }
-          }
-          x_140_phi = x_186;
-          x_143_phi = x_142;
-
-          continuing {
-            x_140 = x_140_phi;
-            x_143 = x_143_phi;
-            x_139_phi = x_140;
-            x_142_phi = x_143;
-          }
-        }
-        let x_188 : bool = x_188_phi;
-        if (x_188) {
-          break;
-        }
-      }
-    }
-
-    continuing {
-      x_120 = (x_119 + 1);
-      x_119_phi = x_120;
-    }
-  }
-  var x_193 : bool;
-  var x_240 : bool;
-  var x_193_phi : bool;
-  var x_196_phi : i32;
-  var x_242_phi : bool;
-  switch(0u) {
-    default: {
-      x_193_phi = false;
-      x_196_phi = 0;
-      loop {
-        var x_221 : i32;
-        var x_213 : i32;
-        var x_194 : bool;
-        var x_197 : i32;
-        var x_194_phi : bool;
-        var x_197_phi : i32;
-        x_193 = x_193_phi;
-        let x_196 : i32 = x_196_phi;
-        x_242_phi = x_193;
-        if ((x_196 <= 3)) {
-        } else {
-          break;
-        }
-        let x_202 : i32 = tree[x_196].data;
-        if ((15 <= x_202)) {
-          var x_240_phi : bool;
-          let x_215_save = x_196;
-          let x_216 : i32 = tree[x_215_save].leftIndex;
-          if ((x_216 == -1)) {
-            let x_223 : f32 = x_8.injectionSwitch.y;
-            let x_225 : f32 = x_8.injectionSwitch.x;
-            if ((x_223 < x_225)) {
-              loop {
-                discard;
-              }
-            }
-            tree[x_215_save].leftIndex = 3;
-            tree[3] = BST(15, -1, -1);
-            loop {
-              x_240_phi = x_193;
-              if ((0 < i32(x_223))) {
-              } else {
-                break;
-              }
-              x_240_phi = true;
-              break;
-            }
-            x_240 = x_240_phi;
-            x_242_phi = x_240;
-            if (x_240) {
-              break;
-            }
-          } else {
-            x_221 = tree[x_215_save].leftIndex;
-            x_194_phi = x_193;
-            x_197_phi = x_221;
-            continue;
-          }
-        } else {
-          let x_207_save = x_196;
-          let x_208 : i32 = tree[x_207_save].rightIndex;
-          if ((x_208 == -1)) {
-            tree[x_207_save].rightIndex = 3;
-            tree[3] = BST(15, -1, -1);
-            x_242_phi = true;
-            break;
-          } else {
-            x_213 = tree[x_207_save].rightIndex;
-            x_194_phi = x_193;
-            x_197_phi = x_213;
-            continue;
-          }
-        }
-        x_194_phi = x_240;
-        x_197_phi = x_196;
-
-        continuing {
-          x_194 = x_194_phi;
-          x_197 = x_197_phi;
-          x_193_phi = x_194;
-          x_196_phi = x_197;
-        }
-      }
-      let x_242 : bool = x_242_phi;
-      if (x_242) {
-        break;
-      }
-    }
-  }
-  var x_247 : bool;
-  var x_294 : bool;
-  var x_247_phi : bool;
-  var x_250_phi : i32;
-  var x_296_phi : bool;
-  switch(0u) {
-    default: {
-      x_247_phi = false;
-      x_250_phi = 0;
-      loop {
-        var x_275 : i32;
-        var x_267 : i32;
-        var x_248 : bool;
-        var x_251 : i32;
-        var x_248_phi : bool;
-        var x_251_phi : i32;
-        x_247 = x_247_phi;
-        let x_250 : i32 = x_250_phi;
-        x_296_phi = x_247;
-        if ((x_250 <= 4)) {
-        } else {
-          break;
-        }
-        let x_256 : i32 = tree[x_250].data;
-        if ((7 <= x_256)) {
-          var x_294_phi : bool;
-          let x_269_save = x_250;
-          let x_270 : i32 = tree[x_269_save].leftIndex;
-          if ((x_270 == -1)) {
-            let x_277 : f32 = x_8.injectionSwitch.y;
-            let x_279 : f32 = x_8.injectionSwitch.x;
-            if ((x_277 < x_279)) {
-              loop {
-                discard;
-              }
-            }
-            tree[x_269_save].leftIndex = 4;
-            tree[4] = BST(7, -1, -1);
-            loop {
-              x_294_phi = x_247;
-              if ((0 < i32(x_277))) {
-              } else {
-                break;
-              }
-              x_294_phi = true;
-              break;
-            }
-            x_294 = x_294_phi;
-            x_296_phi = x_294;
-            if (x_294) {
-              break;
-            }
-          } else {
-            x_275 = tree[x_269_save].leftIndex;
-            x_248_phi = x_247;
-            x_251_phi = x_275;
-            continue;
-          }
-        } else {
-          let x_261_save = x_250;
-          let x_262 : i32 = tree[x_261_save].rightIndex;
-          if ((x_262 == -1)) {
-            tree[x_261_save].rightIndex = 4;
-            tree[4] = BST(7, -1, -1);
-            x_296_phi = true;
-            break;
-          } else {
-            x_267 = tree[x_261_save].rightIndex;
-            x_248_phi = x_247;
-            x_251_phi = x_267;
-            continue;
-          }
-        }
-        x_248_phi = x_294;
-        x_251_phi = x_250;
-
-        continuing {
-          x_248 = x_248_phi;
-          x_251 = x_251_phi;
-          x_247_phi = x_248;
-          x_250_phi = x_251;
-        }
-      }
-      let x_296 : bool = x_296_phi;
-      if (x_296) {
-        break;
-      }
-    }
-  }
-  var x_301 : bool;
-  var x_348 : bool;
-  var x_301_phi : bool;
-  var x_304_phi : i32;
-  var x_350_phi : bool;
-  switch(0u) {
-    default: {
-      x_301_phi = false;
-      x_304_phi = 0;
-      loop {
-        var x_329 : i32;
-        var x_321 : i32;
-        var x_302 : bool;
-        var x_305 : i32;
-        var x_302_phi : bool;
-        var x_305_phi : i32;
-        x_301 = x_301_phi;
-        let x_304 : i32 = x_304_phi;
-        x_350_phi = x_301;
-        if ((x_304 <= 5)) {
-        } else {
-          break;
-        }
-        let x_310 : i32 = tree[x_304].data;
-        if ((8 <= x_310)) {
-          var x_348_phi : bool;
-          let x_323_save = x_304;
-          let x_324 : i32 = tree[x_323_save].leftIndex;
-          if ((x_324 == -1)) {
-            let x_331 : f32 = x_8.injectionSwitch.y;
-            let x_333 : f32 = x_8.injectionSwitch.x;
-            if ((x_331 < x_333)) {
-              loop {
-                discard;
-              }
-            }
-            tree[x_323_save].leftIndex = 5;
-            tree[5] = BST(8, -1, -1);
-            loop {
-              x_348_phi = x_301;
-              if ((0 < i32(x_331))) {
-              } else {
-                break;
-              }
-              x_348_phi = true;
-              break;
-            }
-            x_348 = x_348_phi;
-            x_350_phi = x_348;
-            if (x_348) {
-              break;
-            }
-          } else {
-            x_329 = tree[x_323_save].leftIndex;
-            x_302_phi = x_301;
-            x_305_phi = x_329;
-            continue;
-          }
-        } else {
-          let x_315_save = x_304;
-          let x_316 : i32 = tree[x_315_save].rightIndex;
-          if ((x_316 == -1)) {
-            tree[x_315_save].rightIndex = 5;
-            tree[5] = BST(8, -1, -1);
-            x_350_phi = true;
-            break;
-          } else {
-            x_321 = tree[x_315_save].rightIndex;
-            x_302_phi = x_301;
-            x_305_phi = x_321;
-            continue;
-          }
-        }
-        x_302_phi = x_348;
-        x_305_phi = x_304;
-
-        continuing {
-          x_302 = x_302_phi;
-          x_305 = x_305_phi;
-          x_301_phi = x_302;
-          x_304_phi = x_305;
-        }
-      }
-      let x_350 : bool = x_350_phi;
-      if (x_350) {
-        break;
-      }
-    }
-  }
-  var x_355 : bool;
-  var x_402 : bool;
-  var x_355_phi : bool;
-  var x_358_phi : i32;
-  var x_404_phi : bool;
-  switch(0u) {
-    default: {
-      x_355_phi = false;
-      x_358_phi = 0;
-      loop {
-        var x_383 : i32;
-        var x_375 : i32;
-        var x_356 : bool;
-        var x_359 : i32;
-        var x_356_phi : bool;
-        var x_359_phi : i32;
-        x_355 = x_355_phi;
-        let x_358 : i32 = x_358_phi;
-        x_404_phi = x_355;
-        if ((x_358 <= 6)) {
-        } else {
-          break;
-        }
-        let x_364 : i32 = tree[x_358].data;
-        if ((2 <= x_364)) {
-          var x_402_phi : bool;
-          let x_377_save = x_358;
-          let x_378 : i32 = tree[x_377_save].leftIndex;
-          if ((x_378 == -1)) {
-            let x_385 : f32 = x_8.injectionSwitch.y;
-            let x_387 : f32 = x_8.injectionSwitch.x;
-            if ((x_385 < x_387)) {
-              loop {
-                discard;
-              }
-            }
-            tree[x_377_save].leftIndex = 6;
-            tree[6] = BST(2, -1, -1);
-            loop {
-              x_402_phi = x_355;
-              if ((0 < i32(x_385))) {
-              } else {
-                break;
-              }
-              x_402_phi = true;
-              break;
-            }
-            x_402 = x_402_phi;
-            x_404_phi = x_402;
-            if (x_402) {
-              break;
-            }
-          } else {
-            x_383 = tree[x_377_save].leftIndex;
-            x_356_phi = x_355;
-            x_359_phi = x_383;
-            continue;
-          }
-        } else {
-          let x_369_save = x_358;
-          let x_370 : i32 = tree[x_369_save].rightIndex;
-          if ((x_370 == -1)) {
-            tree[x_369_save].rightIndex = 6;
-            tree[6] = BST(2, -1, -1);
-            x_404_phi = true;
-            break;
-          } else {
-            x_375 = tree[x_369_save].rightIndex;
-            x_356_phi = x_355;
-            x_359_phi = x_375;
-            continue;
-          }
-        }
-        x_356_phi = x_402;
-        x_359_phi = x_358;
-
-        continuing {
-          x_356 = x_356_phi;
-          x_359 = x_359_phi;
-          x_355_phi = x_356;
-          x_358_phi = x_359;
-        }
-      }
-      let x_404 : bool = x_404_phi;
-      if (x_404) {
-        break;
-      }
-    }
-  }
-  var x_409 : bool;
-  var x_456 : bool;
-  var x_409_phi : bool;
-  var x_412_phi : i32;
-  var x_458_phi : bool;
-  switch(0u) {
-    default: {
-      x_409_phi = false;
-      x_412_phi = 0;
-      loop {
-        var x_437 : i32;
-        var x_429 : i32;
-        var x_410 : bool;
-        var x_413 : i32;
-        var x_410_phi : bool;
-        var x_413_phi : i32;
-        x_409 = x_409_phi;
-        let x_412 : i32 = x_412_phi;
-        x_458_phi = x_409;
-        if ((x_412 <= 7)) {
-        } else {
-          break;
-        }
-        let x_418 : i32 = tree[x_412].data;
-        if ((6 <= x_418)) {
-          var x_456_phi : bool;
-          let x_431_save = x_412;
-          let x_432 : i32 = tree[x_431_save].leftIndex;
-          if ((x_432 == -1)) {
-            let x_439 : f32 = x_8.injectionSwitch.y;
-            let x_441 : f32 = x_8.injectionSwitch.x;
-            if ((x_439 < x_441)) {
-              loop {
-                discard;
-              }
-            }
-            tree[x_431_save].leftIndex = 7;
-            tree[7] = BST(6, -1, -1);
-            loop {
-              x_456_phi = x_409;
-              if ((0 < i32(x_439))) {
-              } else {
-                break;
-              }
-              x_456_phi = true;
-              break;
-            }
-            x_456 = x_456_phi;
-            x_458_phi = x_456;
-            if (x_456) {
-              break;
-            }
-          } else {
-            x_437 = tree[x_431_save].leftIndex;
-            x_410_phi = x_409;
-            x_413_phi = x_437;
-            continue;
-          }
-        } else {
-          let x_423_save = x_412;
-          let x_424 : i32 = tree[x_423_save].rightIndex;
-          if ((x_424 == -1)) {
-            tree[x_423_save].rightIndex = 7;
-            tree[7] = BST(6, -1, -1);
-            x_458_phi = true;
-            break;
-          } else {
-            x_429 = tree[x_423_save].rightIndex;
-            x_410_phi = x_409;
-            x_413_phi = x_429;
-            continue;
-          }
-        }
-        x_410_phi = x_456;
-        x_413_phi = x_412;
-
-        continuing {
-          x_410 = x_410_phi;
-          x_413 = x_413_phi;
-          x_409_phi = x_410;
-          x_412_phi = x_413;
-        }
-      }
-      let x_458 : bool = x_458_phi;
-      if (x_458) {
-        break;
-      }
-    }
-  }
-  var x_463 : bool;
-  var x_510 : bool;
-  var x_463_phi : bool;
-  var x_466_phi : i32;
-  var x_512_phi : bool;
-  switch(0u) {
-    default: {
-      x_463_phi = false;
-      x_466_phi = 0;
-      loop {
-        var x_491 : i32;
-        var x_483 : i32;
-        var x_464 : bool;
-        var x_467 : i32;
-        var x_464_phi : bool;
-        var x_467_phi : i32;
-        x_463 = x_463_phi;
-        let x_466 : i32 = x_466_phi;
-        x_512_phi = x_463;
-        if ((x_466 <= 8)) {
-        } else {
-          break;
-        }
-        let x_472 : i32 = tree[x_466].data;
-        if ((17 <= x_472)) {
-          var x_510_phi : bool;
-          let x_485_save = x_466;
-          let x_486 : i32 = tree[x_485_save].leftIndex;
-          if ((x_486 == -1)) {
-            let x_493 : f32 = x_8.injectionSwitch.y;
-            let x_495 : f32 = x_8.injectionSwitch.x;
-            if ((x_493 < x_495)) {
-              loop {
-                discard;
-              }
-            }
-            tree[x_485_save].leftIndex = 8;
-            tree[8] = BST(17, -1, -1);
-            loop {
-              x_510_phi = x_463;
-              if ((0 < i32(x_493))) {
-              } else {
-                break;
-              }
-              x_510_phi = true;
-              break;
-            }
-            x_510 = x_510_phi;
-            x_512_phi = x_510;
-            if (x_510) {
-              break;
-            }
-          } else {
-            x_491 = tree[x_485_save].leftIndex;
-            x_464_phi = x_463;
-            x_467_phi = x_491;
-            continue;
-          }
-        } else {
-          let x_477_save = x_466;
-          let x_478 : i32 = tree[x_477_save].rightIndex;
-          if ((x_478 == -1)) {
-            tree[x_477_save].rightIndex = 8;
-            tree[8] = BST(17, -1, -1);
-            x_512_phi = true;
-            break;
-          } else {
-            x_483 = tree[x_477_save].rightIndex;
-            x_464_phi = x_463;
-            x_467_phi = x_483;
-            continue;
-          }
-        }
-        x_464_phi = x_510;
-        x_467_phi = x_466;
-
-        continuing {
-          x_464 = x_464_phi;
-          x_467 = x_467_phi;
-          x_463_phi = x_464;
-          x_466_phi = x_467;
-        }
-      }
-      let x_512 : bool = x_512_phi;
-      if (x_512) {
-        break;
-      }
-    }
-  }
-  var x_517 : bool;
-  var x_564 : bool;
-  var x_517_phi : bool;
-  var x_520_phi : i32;
-  var x_566_phi : bool;
-  switch(0u) {
-    default: {
-      x_517_phi = false;
-      x_520_phi = 0;
-      loop {
-        var x_545 : i32;
-        var x_537 : i32;
-        var x_518 : bool;
-        var x_521 : i32;
-        var x_518_phi : bool;
-        var x_521_phi : i32;
-        x_517 = x_517_phi;
-        let x_520 : i32 = x_520_phi;
-        x_566_phi = x_517;
-        if ((x_520 <= 9)) {
-        } else {
-          break;
-        }
-        let x_526 : i32 = tree[x_520].data;
-        if ((13 <= x_526)) {
-          var x_564_phi : bool;
-          let x_539_save = x_520;
-          let x_540 : i32 = tree[x_539_save].leftIndex;
-          if ((x_540 == -1)) {
-            let x_547 : f32 = x_8.injectionSwitch.y;
-            let x_549 : f32 = x_8.injectionSwitch.x;
-            if ((x_547 < x_549)) {
-              loop {
-                discard;
-              }
-            }
-            tree[x_539_save].leftIndex = 9;
-            tree[9] = BST(13, -1, -1);
-            loop {
-              x_564_phi = x_517;
-              if ((0 < i32(x_547))) {
-              } else {
-                break;
-              }
-              x_564_phi = true;
-              break;
-            }
-            x_564 = x_564_phi;
-            x_566_phi = x_564;
-            if (x_564) {
-              break;
-            }
-          } else {
-            x_545 = tree[x_539_save].leftIndex;
-            x_518_phi = x_517;
-            x_521_phi = x_545;
-            continue;
-          }
-        } else {
-          let x_531_save = x_520;
-          let x_532 : i32 = tree[x_531_save].rightIndex;
-          if ((x_532 == -1)) {
-            tree[x_531_save].rightIndex = 9;
-            tree[9] = BST(13, -1, -1);
-            x_566_phi = true;
-            break;
-          } else {
-            x_537 = tree[x_531_save].rightIndex;
-            x_518_phi = x_517;
-            x_521_phi = x_537;
-            continue;
-          }
-        }
-        x_518_phi = x_564;
-        x_521_phi = x_520;
-
-        continuing {
-          x_518 = x_518_phi;
-          x_521 = x_521_phi;
-          x_517_phi = x_518;
-          x_520_phi = x_521;
-        }
-      }
-      let x_566 : bool = x_566_phi;
-      if (x_566) {
-        break;
-      }
-    }
-  }
-  x_569_phi = 0;
-  x_572_phi = 0;
-  x_574_phi = 0;
-  loop {
-    var x_597 : i32;
-    var x_607 : i32;
-    var x_612 : i32;
-    var x_575 : i32;
-    var x_570_phi : i32;
-    var x_573_phi : i32;
-    let x_569 : i32 = x_569_phi;
-    x_572 = x_572_phi;
-    let x_574 : i32 = x_574_phi;
-    if ((x_574 < 20)) {
-    } else {
-      break;
-    }
-    var x_582_phi : i32;
-    var x_597_phi : i32;
-    var x_598_phi : bool;
-    switch(0u) {
-      default: {
-        x_582_phi = 0;
-        loop {
-          let x_582 : i32 = x_582_phi;
-          x_597_phi = x_569;
-          x_598_phi = false;
-          if ((x_582 != -1)) {
-          } else {
-            break;
-          }
-          let x_589 : BST = tree[x_582];
-          let x_590 : i32 = x_589.data;
-          let x_591 : i32 = x_589.leftIndex;
-          let x_592 : i32 = x_589.rightIndex;
-          if ((x_590 == x_574)) {
-            x_597_phi = x_574;
-            x_598_phi = true;
-            break;
-          }
-
-          continuing {
-            x_582_phi = select(x_591, x_592, (x_574 > x_590));
-          }
-        }
-        x_597 = x_597_phi;
-        let x_598 : bool = x_598_phi;
-        x_570_phi = x_597;
-        if (x_598) {
-          break;
-        }
-        x_570_phi = -1;
-      }
-    }
-    var x_570 : i32;
-    var x_606 : i32;
-    var x_611 : i32;
-    var x_607_phi : i32;
-    var x_612_phi : i32;
-    x_570 = x_570_phi;
-    switch(x_574) {
-      case 2, 5, 6, 7, 8, 9, 12, 13, 15, 17: {
-        x_607_phi = x_572;
-        if ((x_570 == bitcast<i32>(x_574))) {
-          x_606 = bitcast<i32>((x_572 + bitcast<i32>(1)));
-          x_607_phi = x_606;
-        }
-        x_607 = x_607_phi;
-        x_573_phi = x_607;
-      }
-      default: {
-        x_612_phi = x_572;
-        if ((x_570 == bitcast<i32>(-1))) {
-          x_611 = bitcast<i32>((x_572 + bitcast<i32>(1)));
-          x_612_phi = x_611;
-        }
-        x_612 = x_612_phi;
-        x_573_phi = x_612;
-      }
-    }
-    let x_573 : i32 = x_573_phi;
-
-    continuing {
-      x_575 = (x_574 + 1);
-      x_569_phi = x_570;
-      x_572_phi = x_573;
-      x_574_phi = x_575;
-    }
-  }
-  if ((x_572 == bitcast<i32>(20))) {
-    x_GLF_color = vec4<f32>(1.0, 0.0, 0.0, 1.0);
-  } else {
-    x_GLF_color = vec4<f32>(0.0, 0.0, 1.0, 1.0);
-  }
-  return;
-}
-
-struct main_out {
-  @location(0)
-  x_GLF_color_1 : vec4<f32>,
-}
-
-@fragment
-fn main(@builtin(position) gl_FragCoord_param : vec4<f32>) -> main_out {
-  gl_FragCoord = gl_FragCoord_param;
-  main_1();
-  return main_out(x_GLF_color);
-}