Import Tint changes from Dawn

Changes:
  - 84d370a0b9427bcff3cfaf33558289665edb387a [tintd] Handle lsp::WorkspaceDidChangeWatchedFilesNotific... by Ben Clayton <bclayton@google.com>
  - 3de0f00ef217d7fbce7f5397d1b8f1c52372b9cd Fix some misc-include-cleaner clang-tidy warnings by David Neto <dneto@google.com>
  - 1963f508503cb2e6e2706fd8c614c091cb6275d4 [tint][wgsl] Pull expression inlining out to raise transf... by Ben Clayton <bclayton@google.com>
GitOrigin-RevId: 84d370a0b9427bcff3cfaf33558289665edb387a
Change-Id: I7065a709a066a753932fff4a8d217f3c46d95595
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/181140
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: dan sinclair <dsinclair@google.com>
Commit-Queue: dan sinclair <dsinclair@google.com>
diff --git a/src/tint/lang/wgsl/ls/BUILD.bazel b/src/tint/lang/wgsl/ls/BUILD.bazel
index 25ddd43..8a94377 100644
--- a/src/tint/lang/wgsl/ls/BUILD.bazel
+++ b/src/tint/lang/wgsl/ls/BUILD.bazel
@@ -41,6 +41,7 @@
   srcs = [
     "cancel_request.cc",
     "change_configuration.cc",
+    "change_watched_files.cc",
     "definition.cc",
     "diagnostics.cc",
     "document.cc",
diff --git a/src/tint/lang/wgsl/ls/BUILD.cmake b/src/tint/lang/wgsl/ls/BUILD.cmake
index 611c64d..f5b6632 100644
--- a/src/tint/lang/wgsl/ls/BUILD.cmake
+++ b/src/tint/lang/wgsl/ls/BUILD.cmake
@@ -43,6 +43,7 @@
 tint_add_target(tint_lang_wgsl_ls lib
   lang/wgsl/ls/cancel_request.cc
   lang/wgsl/ls/change_configuration.cc
+  lang/wgsl/ls/change_watched_files.cc
   lang/wgsl/ls/definition.cc
   lang/wgsl/ls/diagnostics.cc
   lang/wgsl/ls/document.cc
diff --git a/src/tint/lang/wgsl/ls/BUILD.gn b/src/tint/lang/wgsl/ls/BUILD.gn
index 6dde581..d3d285e 100644
--- a/src/tint/lang/wgsl/ls/BUILD.gn
+++ b/src/tint/lang/wgsl/ls/BUILD.gn
@@ -46,6 +46,7 @@
     sources = [
       "cancel_request.cc",
       "change_configuration.cc",
+      "change_watched_files.cc",
       "definition.cc",
       "diagnostics.cc",
       "document.cc",
diff --git a/src/tint/lang/wgsl/ls/change_watched_files.cc b/src/tint/lang/wgsl/ls/change_watched_files.cc
new file mode 100644
index 0000000..e004f8e
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/change_watched_files.cc
@@ -0,0 +1,40 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "langsvr/lsp/lsp.h"
+#include "src/tint/lang/wgsl/ls/server.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+langsvr::Result<langsvr::SuccessType> Server::Handle(
+    const lsp::WorkspaceDidChangeWatchedFilesNotification&) {
+    return langsvr::Success;
+}
+
+}  // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/server.cc b/src/tint/lang/wgsl/ls/server.cc
index 6b526de..65e6d62 100644
--- a/src/tint/lang/wgsl/ls/server.cc
+++ b/src/tint/lang/wgsl/ls/server.cc
@@ -27,6 +27,7 @@
 
 #include "src/tint/lang/wgsl/ls/server.h"
 
+#include "langsvr/lsp/lsp.h"
 #include "langsvr/session.h"
 
 #include "src/tint/lang/wgsl/ls/sem_token.h"
@@ -102,6 +103,8 @@
     session.Register(
         [&](const lsp::TextDocumentSemanticTokensFullRequest& r) { return Handle(r); });
     session.Register([&](const lsp::TextDocumentSignatureHelpRequest& r) { return Handle(r); });
+    session.Register(
+        [&](const lsp::WorkspaceDidChangeWatchedFilesNotification& n) { return Handle(n); });
 }
 
 Server::~Server() = default;
diff --git a/src/tint/lang/wgsl/ls/server.h b/src/tint/lang/wgsl/ls/server.h
index e0df2f3..a9c55a1 100644
--- a/src/tint/lang/wgsl/ls/server.h
+++ b/src/tint/lang/wgsl/ls/server.h
@@ -127,6 +127,10 @@
     langsvr::Result<langsvr::SuccessType>  //
     Handle(const langsvr::lsp::WorkspaceDidChangeConfigurationNotification&);
 
+    /// Handler for langsvr::lsp::WorkspaceDidChangeWatchedFilesNotification
+    langsvr::Result<langsvr::SuccessType>  //
+    Handle(const langsvr::lsp::WorkspaceDidChangeWatchedFilesNotification&);
+
     /// Publishes the tint::Program diagnostics to the server via a
     /// TextDocumentPublishDiagnosticsNotification.
     langsvr::Result<langsvr::SuccessType>  //
diff --git a/src/tint/lang/wgsl/writer/BUILD.bazel b/src/tint/lang/wgsl/writer/BUILD.bazel
index 38ef94d..23adfef 100644
--- a/src/tint/lang/wgsl/writer/BUILD.bazel
+++ b/src/tint/lang/wgsl/writer/BUILD.bazel
@@ -91,17 +91,35 @@
   alwayslink = True,
   srcs = [
     "options_test.cc",
+    "writer_test.cc",
   ],
   deps = [
+    "//src/tint/api/common",
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/intrinsic",
+    "//src/tint/lang/core/ir",
+    "//src/tint/lang/core/ir:test",
+    "//src/tint/lang/core/type",
+    "//src/tint/lang/wgsl",
+    "//src/tint/lang/wgsl/ast",
+    "//src/tint/lang/wgsl/common",
+    "//src/tint/lang/wgsl/features",
+    "//src/tint/lang/wgsl/program",
+    "//src/tint/lang/wgsl/sem",
+    "//src/tint/lang/wgsl/writer/ir_to_program",
+    "//src/tint/lang/wgsl/writer/raise",
     "//src/tint/utils/containers",
     "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
+    "//src/tint/utils/id",
     "//src/tint/utils/macros",
     "//src/tint/utils/math",
     "//src/tint/utils/memory",
     "//src/tint/utils/reflection",
     "//src/tint/utils/result",
     "//src/tint/utils/rtti",
+    "//src/tint/utils/symbol",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
     "@gtest",
diff --git a/src/tint/lang/wgsl/writer/BUILD.cmake b/src/tint/lang/wgsl/writer/BUILD.cmake
index add1cf2..5ca9163 100644
--- a/src/tint/lang/wgsl/writer/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/BUILD.cmake
@@ -100,18 +100,36 @@
 ################################################################################
 tint_add_target(tint_lang_wgsl_writer_test test
   lang/wgsl/writer/options_test.cc
+  lang/wgsl/writer/writer_test.cc
 )
 
 tint_target_add_dependencies(tint_lang_wgsl_writer_test test
+  tint_api_common
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_intrinsic
+  tint_lang_core_ir
+  tint_lang_core_ir_test
+  tint_lang_core_type
+  tint_lang_wgsl
+  tint_lang_wgsl_ast
+  tint_lang_wgsl_common
+  tint_lang_wgsl_features
+  tint_lang_wgsl_program
+  tint_lang_wgsl_sem
+  tint_lang_wgsl_writer_ir_to_program
+  tint_lang_wgsl_writer_raise
   tint_utils_containers
   tint_utils_diagnostic
   tint_utils_ice
+  tint_utils_id
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
   tint_utils_reflection
   tint_utils_result
   tint_utils_rtti
+  tint_utils_symbol
   tint_utils_text
   tint_utils_traits
 )
diff --git a/src/tint/lang/wgsl/writer/BUILD.gn b/src/tint/lang/wgsl/writer/BUILD.gn
index e28a833..14ebcde 100644
--- a/src/tint/lang/wgsl/writer/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/BUILD.gn
@@ -90,18 +90,38 @@
 if (tint_build_unittests) {
   if (tint_build_wgsl_writer) {
     tint_unittests_source_set("unittests") {
-      sources = [ "options_test.cc" ]
+      sources = [
+        "options_test.cc",
+        "writer_test.cc",
+      ]
       deps = [
         "${tint_src_dir}:gmock_and_gtest",
+        "${tint_src_dir}/api/common",
+        "${tint_src_dir}/lang/core",
+        "${tint_src_dir}/lang/core/constant",
+        "${tint_src_dir}/lang/core/intrinsic",
+        "${tint_src_dir}/lang/core/ir",
+        "${tint_src_dir}/lang/core/ir:unittests",
+        "${tint_src_dir}/lang/core/type",
+        "${tint_src_dir}/lang/wgsl",
+        "${tint_src_dir}/lang/wgsl/ast",
+        "${tint_src_dir}/lang/wgsl/common",
+        "${tint_src_dir}/lang/wgsl/features",
+        "${tint_src_dir}/lang/wgsl/program",
+        "${tint_src_dir}/lang/wgsl/sem",
+        "${tint_src_dir}/lang/wgsl/writer/ir_to_program",
+        "${tint_src_dir}/lang/wgsl/writer/raise",
         "${tint_src_dir}/utils/containers",
         "${tint_src_dir}/utils/diagnostic",
         "${tint_src_dir}/utils/ice",
+        "${tint_src_dir}/utils/id",
         "${tint_src_dir}/utils/macros",
         "${tint_src_dir}/utils/math",
         "${tint_src_dir}/utils/memory",
         "${tint_src_dir}/utils/reflection",
         "${tint_src_dir}/utils/result",
         "${tint_src_dir}/utils/rtti",
+        "${tint_src_dir}/utils/symbol",
         "${tint_src_dir}/utils/text",
         "${tint_src_dir}/utils/traits",
       ]
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel
index 1c5947a..f1efc80 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel
@@ -85,7 +85,6 @@
     "ir_to_program_test.h",
   ] + select({
     ":tint_build_wgsl_writer": [
-      "inlining_test.cc",
       "ir_to_program_test.cc",
     ],
     "//conditions:default": [],
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake
index 9828bc9..813f157 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake
@@ -121,7 +121,6 @@
 
 if(TINT_BUILD_WGSL_WRITER)
   tint_target_add_sources(tint_lang_wgsl_writer_ir_to_program_test test
-    "lang/wgsl/writer/ir_to_program/inlining_test.cc"
     "lang/wgsl/writer/ir_to_program/ir_to_program_test.cc"
   )
   tint_target_add_dependencies(tint_lang_wgsl_writer_ir_to_program_test test
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
index 3f9583c..1698652 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
@@ -116,10 +116,7 @@
     ]
 
     if (tint_build_wgsl_writer) {
-      sources += [
-        "inlining_test.cc",
-        "ir_to_program_test.cc",
-      ]
+      sources += [ "ir_to_program_test.cc" ]
       deps += [ "${tint_src_dir}/lang/wgsl/writer" ]
     }
   }
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/inlining_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/inlining_test.cc
deleted file mode 100644
index e69347d..0000000
--- a/src/tint/lang/wgsl/writer/ir_to_program/inlining_test.cc
+++ /dev/null
@@ -1,1408 +0,0 @@
-// Copyright 2023 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-//    list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-//    this list of conditions and the following disclaimer in the documentation
-//    and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-//    contributors may be used to endorse or promote products derived from
-//    this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// GEN_BUILD:CONDITION(tint_build_wgsl_writer)
-
-#include <string>
-
-#include "src/tint/lang/core/ir/disassembler.h"
-#include "src/tint/lang/core/type/array.h"
-#include "src/tint/lang/core/type/matrix.h"
-#include "src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h"
-#include "src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.h"
-#include "src/tint/lang/wgsl/writer/writer.h"
-#include "src/tint/utils/text/string.h"
-
-namespace tint::wgsl::writer {
-namespace {
-
-using namespace tint::core::number_suffixes;  // NOLINT
-using namespace tint::core::fluent_types;     // NOLINT
-
-using IRToProgramInliningTest = IRToProgramTest;
-
-////////////////////////////////////////////////////////////////////////////////
-// Load / Store
-////////////////////////////////////////////////////////////////////////////////
-TEST_F(IRToProgramInliningTest, LoadVar_ThenStoreVar_ThenUseLoad) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* load = b.Load(var);
-        b.Store(var, 2_i);
-        b.Return(fn, load);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  let v_1 = v;
-  v = 2i;
-  return v_1;
-}
-)");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Binary op
-////////////////////////////////////////////////////////////////////////////////
-TEST_F(IRToProgramInliningTest, BinaryOpUnsequencedLHSThenUnsequencedRHS) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] {
-        auto* lhs = b.Add(ty.i32(), 1_i, 2_i);
-        auto* rhs = b.Add(ty.i32(), 3_i, 4_i);
-        auto* bin = b.Add(ty.i32(), lhs, rhs);
-        b.Return(fn_b, bin);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b() -> i32 {
-  return ((1i + 2i) + (3i + 4i));
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, BinaryOpSequencedLHSThenUnsequencedRHS) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] {
-        auto* lhs = b.Call(ty.i32(), fn_a, 1_i);
-        auto* rhs = b.Add(ty.i32(), 2_i, 3_i);
-        auto* bin = b.Add(ty.i32(), lhs, rhs);
-        b.Return(fn_b, bin);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b() -> i32 {
-  return (a(1i) + (2i + 3i));
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, BinaryOpUnsequencedLHSThenSequencedRHS) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] {
-        auto* lhs = b.Add(ty.i32(), 1_i, 2_i);
-        auto* rhs = b.Call(ty.i32(), fn_a, 3_i);
-        auto* bin = b.Add(ty.i32(), lhs, rhs);
-        b.Return(fn_b, bin);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b() -> i32 {
-  return ((1i + 2i) + a(3i));
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, BinaryOpSequencedLHSThenSequencedRHS) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] {
-        auto* lhs = b.Call(ty.i32(), fn_a, 1_i);
-        auto* rhs = b.Call(ty.i32(), fn_a, 2_i);
-        auto* bin = b.Add(ty.i32(), lhs, rhs);
-        b.Return(fn_b, bin);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b() -> i32 {
-  return (a(1i) + a(2i));
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, BinaryOpUnsequencedRHSThenUnsequencedLHS) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] {
-        auto* rhs = b.Add(ty.i32(), 3_i, 4_i);
-        auto* lhs = b.Add(ty.i32(), 1_i, 2_i);
-        auto* bin = b.Add(ty.i32(), lhs, rhs);
-        b.Return(fn_b, bin);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b() -> i32 {
-  return ((1i + 2i) + (3i + 4i));
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, BinaryOpUnsequencedRHSThenSequencedLHS) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] {
-        auto* rhs = b.Add(ty.i32(), 2_i, 3_i);
-        auto* lhs = b.Call(ty.i32(), fn_a, 1_i);
-        auto* bin = b.Add(ty.i32(), lhs, rhs);
-        b.Return(fn_b, bin);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b() -> i32 {
-  return (a(1i) + (2i + 3i));
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, BinaryOpSequencedRHSThenUnsequencedLHS) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] {
-        auto* rhs = b.Call(ty.i32(), fn_a, 3_i);
-        auto* lhs = b.Add(ty.i32(), 1_i, 2_i);
-        auto* bin = b.Add(ty.i32(), lhs, rhs);
-        b.Return(fn_b, bin);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b() -> i32 {
-  return ((1i + 2i) + a(3i));
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, BinaryOpSequencedRHSThenSequencedLHS) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] {
-        auto* rhs = b.Call(ty.i32(), fn_a, 2_i);
-        auto* lhs = b.Call(ty.i32(), fn_a, 1_i);
-        auto* bin = b.Add(ty.i32(), lhs, rhs);
-        b.Return(fn_b, bin);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b() -> i32 {
-  let v_1 = a(2i);
-  return (a(1i) + v_1);
-}
-)");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Call
-////////////////////////////////////////////////////////////////////////////////
-TEST_F(IRToProgramInliningTest, CallSequencedXYZ) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
-    fn_b->SetParams(
-        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
-
-    auto* fn_c = b.Function("c", ty.i32());
-    b.Append(fn_c->Block(), [&] {
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
-        b.Return(fn_c, call);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b(v_1 : i32, v_2 : i32, v_3 : i32) -> i32 {
-  return 0i;
-}
-
-fn c() -> i32 {
-  return b(a(1i), a(2i), a(3i));
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, CallSequencedYXZ) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
-    fn_b->SetParams(
-        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
-
-    auto* fn_c = b.Function("c", ty.i32());
-    b.Append(fn_c->Block(), [&] {
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
-        b.Return(fn_c, call);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b(v_1 : i32, v_2 : i32, v_3 : i32) -> i32 {
-  return 0i;
-}
-
-fn c() -> i32 {
-  let v_4 = a(2i);
-  return b(a(1i), v_4, a(3i));
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, CallSequencedXZY) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
-    fn_b->SetParams(
-        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
-
-    auto* fn_c = b.Function("c", ty.i32());
-    b.Append(fn_c->Block(), [&] {
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
-        b.Return(fn_c, call);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b(v_1 : i32, v_2 : i32, v_3 : i32) -> i32 {
-  return 0i;
-}
-
-fn c() -> i32 {
-  let v_4 = a(1i);
-  let v_5 = a(3i);
-  return b(v_4, a(2i), v_5);
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, CallSequencedZXY) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
-    fn_b->SetParams(
-        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
-
-    auto* fn_c = b.Function("c", ty.i32());
-    b.Append(fn_c->Block(), [&] {
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
-        b.Return(fn_c, call);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b(v_1 : i32, v_2 : i32, v_3 : i32) -> i32 {
-  return 0i;
-}
-
-fn c() -> i32 {
-  let v_4 = a(3i);
-  return b(a(1i), a(2i), v_4);
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, CallSequencedYZX) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
-    fn_b->SetParams(
-        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
-
-    auto* fn_c = b.Function("c", ty.i32());
-    b.Append(fn_c->Block(), [&] {
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
-        b.Return(fn_c, call);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b(v_1 : i32, v_2 : i32, v_3 : i32) -> i32 {
-  return 0i;
-}
-
-fn c() -> i32 {
-  let v_4 = a(2i);
-  let v_5 = a(3i);
-  return b(a(1i), v_4, v_5);
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, CallSequencedZYX) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn_b = b.Function("b", ty.i32());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
-    fn_b->SetParams(
-        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
-
-    auto* fn_c = b.Function("c", ty.i32());
-    b.Append(fn_c->Block(), [&] {
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
-        b.Return(fn_c, call);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 0i;
-}
-
-fn b(v_1 : i32, v_2 : i32, v_3 : i32) -> i32 {
-  return 0i;
-}
-
-fn c() -> i32 {
-  let v_4 = a(3i);
-  let v_5 = a(2i);
-  return b(a(1i), v_5, v_4);
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVar_ThenCallVoidFn_ThenUseLoad) {
-    auto* fn_a = b.Function("a", ty.void_());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a); });
-
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* load = b.Load(var);
-        b.Call(ty.void_(), fn_a);
-        b.Return(fn, load);
-    });
-
-    EXPECT_WGSL(R"(
-fn a() {
-}
-
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  let v_1 = v;
-  a();
-  return v_1;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVar_ThenCallUnusedi32Fn_ThenUseLoad) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
-
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* load = b.Load(var);
-        b.Call(ty.i32(), fn_a);
-        b.Return(fn, load);
-    });
-
-    EXPECT_WGSL(R"(
-fn a() -> i32 {
-  return 1i;
-}
-
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  let v_1 = v;
-  a();
-  return v_1;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVar_ThenCalli32Fn_ThenUseLoadBeforeCall) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
-
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* load = b.Load(var);
-        auto* call = b.Call(ty.i32(), fn_a);
-        b.Return(fn, b.Add(ty.i32(), load, call));
-    });
-
-    EXPECT_WGSL(R"(
-fn a() -> i32 {
-  return 1i;
-}
-
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  return (v + a());
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVar_ThenCalli32Fn_ThenUseCallBeforeLoad) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
-
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* load = b.Load(var);
-        auto* call = b.Call(ty.i32(), fn_a);
-        b.Return(fn, b.Add(ty.i32(), call, load));
-    });
-
-    EXPECT_WGSL(R"(
-fn a() -> i32 {
-  return 1i;
-}
-
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  let v_1 = v;
-  return (a() + v_1);
-}
-)");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Access
-////////////////////////////////////////////////////////////////////////////////
-TEST_F(IRToProgramInliningTest, Access_ArrayOfArrayOfArray_XYZ) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* arr = b.Var(ty.ptr<function, array<array<array<i32, 3>, 4>, 5>>());
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z);
-        b.Return(fn, b.Load(access));
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 1i;
-}
-
-fn f() -> i32 {
-  var v_1 : array<array<array<i32, 3u>, 4u>, 5u>;
-  return v_1[a(1i)][a(2i)][a(3i)];
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, Access_ArrayOfArrayOfArray_YXZ) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* arr = b.Var(ty.ptr<function, array<array<array<i32, 3>, 4>, 5>>());
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z);
-        b.Return(fn, b.Load(access));
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 1i;
-}
-
-fn f() -> i32 {
-  var v_1 : array<array<array<i32, 3u>, 4u>, 5u>;
-  let v_2 = a(2i);
-  return v_1[a(1i)][v_2][a(3i)];
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, Access_ArrayOfArrayOfArray_ZXY) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* arr = b.Var(ty.ptr<function, array<array<array<i32, 3>, 4>, 5>>());
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z);
-        b.Return(fn, b.Load(access));
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 1i;
-}
-
-fn f() -> i32 {
-  var v_1 : array<array<array<i32, 3u>, 4u>, 5u>;
-  let v_2 = a(3i);
-  return v_1[a(1i)][a(2i)][v_2];
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, Access_ArrayOfArrayOfArray_ZYX) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* arr = b.Var(ty.ptr<function, array<array<array<i32, 3>, 4>, 5>>());
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z);
-        b.Return(fn, b.Load(access));
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 1i;
-}
-
-fn f() -> i32 {
-  var v_1 : array<array<array<i32, 3u>, 4u>, 5u>;
-  let v_2 = a(3i);
-  let v_3 = a(2i);
-  return v_1[a(1i)][v_3][v_2];
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, Access_ArrayOfMat3x4f_XYZ) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn = b.Function("f", ty.f32());
-    b.Append(fn->Block(), [&] {
-        auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>());
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* access = b.Access(ty.f32(), arr, x, y, z);
-        b.Return(fn, access);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 1i;
-}
-
-fn f() -> f32 {
-  return array<mat3x4<f32>, 5u>()[a(1i)][a(2i)][a(3i)];
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, Access_ArrayOfMat3x4f_YXZ) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn = b.Function("f", ty.f32());
-    b.Append(fn->Block(), [&] {
-        auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>());
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* access = b.Access(ty.f32(), arr, x, y, z);
-        b.Return(fn, access);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 1i;
-}
-
-fn f() -> f32 {
-  let v_1 = a(2i);
-  return array<mat3x4<f32>, 5u>()[a(1i)][v_1][a(3i)];
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, Access_ArrayOfMat3x4f_ZXY) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn = b.Function("f", ty.f32());
-    b.Append(fn->Block(), [&] {
-        auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>());
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* access = b.Access(ty.f32(), arr, x, y, z);
-        b.Return(fn, access);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 1i;
-}
-
-fn f() -> f32 {
-  let v_1 = a(3i);
-  return array<mat3x4<f32>, 5u>()[a(1i)][a(2i)][v_1];
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, Access_ArrayOfMat3x4f_ZYX) {
-    auto* fn_a = b.Function("a", ty.i32());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
-    fn_a->SetParams({b.FunctionParam(ty.i32())});
-
-    auto* fn = b.Function("f", ty.f32());
-    b.Append(fn->Block(), [&] {
-        auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>());
-        auto* z = b.Call(ty.i32(), fn_a, 3_i);
-        auto* y = b.Call(ty.i32(), fn_a, 2_i);
-        auto* x = b.Call(ty.i32(), fn_a, 1_i);
-        auto* access = b.Access(ty.f32(), arr, x, y, z);
-        b.Return(fn, access);
-    });
-
-    EXPECT_WGSL(R"(
-fn a(v : i32) -> i32 {
-  return 1i;
-}
-
-fn f() -> f32 {
-  let v_1 = a(3i);
-  let v_2 = a(2i);
-  return array<mat3x4<f32>, 5u>()[a(1i)][v_2][v_1];
-}
-)");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// If
-////////////////////////////////////////////////////////////////////////////////
-TEST_F(IRToProgramInliningTest, UnsequencedOutsideIf) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* v = b.Add(ty.i32(), 1_i, 2_i);
-        auto* if_ = b.If(true);
-        b.Append(if_->True(), [&] { b.Return(fn, v); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  if (true) {
-    return (1i + 2i);
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, SequencedOutsideIf) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        var->SetInitializer(b.Constant(1_i));
-        auto* v_1 = b.Load(var);
-        auto* v_2 = b.Add(ty.i32(), v_1, 2_i);
-        auto* if_ = b.If(true);
-        b.Append(if_->True(), [&] { b.Return(fn, v_2); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32 = 1i;
-  let v_1 = (v + 2i);
-  if (true) {
-    return v_1;
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, UnsequencedUsedByIfCondition) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* v = b.Equal(ty.bool_(), 1_i, 2_i);
-        auto* if_ = b.If(v);
-        b.Append(if_->True(), [&] { b.Return(fn, 3_i); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  if ((1i == 2i)) {
-    return 3i;
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, SequencedUsedByIfCondition) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        var->SetInitializer(b.Constant(1_i));
-        auto* v_1 = b.Load(var);
-        auto* v_2 = b.Equal(ty.bool_(), v_1, 2_i);
-        auto* if_ = b.If(v_2);
-        b.Append(if_->True(), [&] { b.Return(fn, 3_i); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32 = 1i;
-  if ((v == 2i)) {
-    return 3i;
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVar_ThenWriteToVarInIf_ThenUseLoad) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* load = b.Load(var);
-        auto* if_ = b.If(true);
-        b.Append(if_->True(), [&] {
-            b.Store(var, 2_i);
-            b.ExitIf(if_);
-        });
-        b.Return(fn, load);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  let v_1 = v;
-  if (true) {
-    v = 2i;
-  }
-  return v_1;
-}
-)");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Switch
-////////////////////////////////////////////////////////////////////////////////
-TEST_F(IRToProgramInliningTest, UnsequencedOutsideSwitch) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* v = b.Add(ty.i32(), 1_i, 2_i);
-        auto* switch_ = b.Switch(3_i);
-        auto* case_ = b.DefaultCase(switch_);
-        b.Append(case_, [&] { b.Return(fn, v); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  switch(3i) {
-    default: {
-      return (1i + 2i);
-    }
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, SequencedOutsideSwitch) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        var->SetInitializer(b.Constant(1_i));
-        auto* v_1 = b.Load(var);
-        auto* v_2 = b.Add(ty.i32(), v_1, 2_i);
-        auto* switch_ = b.Switch(3_i);
-        auto* case_ = b.DefaultCase(switch_);
-        b.Append(case_, [&] { b.Return(fn, v_2); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32 = 1i;
-  let v_1 = (v + 2i);
-  switch(3i) {
-    default: {
-      return v_1;
-    }
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, UnsequencedUsedBySwitchCondition) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* v = b.Add(ty.i32(), 1_i, 2_i);
-        auto* switch_ = b.Switch(v);
-        auto* case_ = b.DefaultCase(switch_);
-        b.Append(case_, [&] { b.Return(fn, 3_i); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  switch((1i + 2i)) {
-    default: {
-      return 3i;
-    }
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, SequencedUsedBySwitchCondition) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        var->SetInitializer(b.Constant(1_i));
-        auto* v_1 = b.Load(var);
-        auto* switch_ = b.Switch(v_1);
-        auto* case_ = b.DefaultCase(switch_);
-        b.Append(case_, [&] { b.Return(fn, 3_i); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32 = 1i;
-  switch(v) {
-    default: {
-      return 3i;
-    }
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVar_ThenWriteToVarInSwitch_ThenUseLoad) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* load = b.Load(var);
-        auto* switch_ = b.Switch(1_i);
-        auto* case_ = b.DefaultCase(switch_);
-        b.Append(case_, [&] {
-            b.Store(var, 2_i);
-            b.ExitSwitch(switch_);
-        });
-        b.Return(fn, load);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  let v_1 = v;
-  switch(1i) {
-    default: {
-      v = 2i;
-    }
-  }
-  return v_1;
-}
-)");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Loop
-////////////////////////////////////////////////////////////////////////////////
-TEST_F(IRToProgramInliningTest, UnsequencedOutsideLoopInitializer) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        auto* v = b.Add(ty.i32(), 1_i, 2_i);
-        auto* loop = b.Loop();
-        b.Append(loop->Initializer(), [&] {
-            b.Store(var, v);
-            b.NextIteration(loop);
-        });
-        b.Append(loop->Body(), [&] { b.ExitLoop(loop); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  {
-    v = (1i + 2i);
-    loop {
-      break;
-    }
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, SequencedOutsideLoopInitializer) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        auto* v_1 = b.Load(var);
-        auto* v_2 = b.Add(ty.i32(), v_1, 2_i);
-        auto* loop = b.Loop();
-        b.Append(loop->Initializer(), [&] {
-            b.Store(var, v_2);
-            b.NextIteration(loop);
-        });
-        b.Append(loop->Body(), [&] { b.ExitLoop(loop); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  let v_1 = (v + 2i);
-  {
-    v = v_1;
-    loop {
-      break;
-    }
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVar_ThenWriteToVarInLoopInitializer_ThenUseLoad) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* load = b.Load(var);
-        auto* loop = b.Loop();
-        b.Append(loop->Initializer(), [&] {
-            b.Store(var, 2_i);
-            b.NextIteration(loop);
-        });
-        b.Append(loop->Body(), [&] { b.ExitLoop(loop); });
-        b.Return(fn, load);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  let v_1 = v;
-  {
-    v = 2i;
-    loop {
-      break;
-    }
-  }
-  return v_1;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, UnsequencedOutsideLoopBody) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* v = b.Add(ty.i32(), 1_i, 2_i);
-        auto* loop = b.Loop();
-        b.Append(loop->Body(), [&] { b.Return(fn, v); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  loop {
-    return (1i + 2i);
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, SequencedOutsideLoopBody) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        auto* v_1 = b.Load(var);
-        auto* v_2 = b.Add(ty.i32(), v_1, 2_i);
-        auto* loop = b.Loop();
-        b.Append(loop->Body(), [&] { b.Return(fn, v_2); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  let v_1 = (v + 2i);
-  loop {
-    return v_1;
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVar_ThenWriteToVarInLoopBody_ThenUseLoad) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* load = b.Load(var);
-        auto* loop = b.Loop();
-        b.Append(loop->Body(), [&] {
-            b.Store(var, 2_i);
-            b.ExitLoop(loop);
-        });
-        b.Return(fn, load);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  let v_1 = v;
-  loop {
-    v = 2i;
-    break;
-  }
-  return v_1;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, UnsequencedOutsideLoopContinuing) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* v = b.Add(ty.i32(), 1_i, 2_i);
-        auto* loop = b.Loop();
-        b.Append(loop->Body(), [&] { b.Continue(loop); });
-        b.Append(loop->Continuing(), [&] { b.BreakIf(loop, b.Equal(ty.bool_(), v, 3_i)); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  loop {
-
-    continuing {
-      break if ((1i + 2i) == 3i);
-    }
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, SequencedOutsideLoopContinuing) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        auto* v_1 = b.Load(var);
-        auto* v_2 = b.Add(ty.i32(), v_1, 2_i);
-        auto* loop = b.Loop();
-        b.Append(loop->Body(), [&] { b.Continue(loop); });
-        b.Append(loop->Continuing(), [&] { b.BreakIf(loop, b.Equal(ty.bool_(), v_2, 3_i)); });
-        b.Return(fn, 0_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  let v_1 = (v + 2i);
-  loop {
-
-    continuing {
-      break if (v_1 == 3i);
-    }
-  }
-  return 0i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVar_ThenWriteToVarInLoopContinuing_ThenUseLoad) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* load = b.Load(var);
-        auto* loop = b.Loop();
-        b.Append(loop->Body(), [&] { b.Continue(loop); });
-        b.Append(loop->Continuing(), [&] {
-            b.Store(var, 2_i);
-            b.BreakIf(loop, true);
-        });
-        b.Return(fn, load);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  let v_1 = v;
-  loop {
-
-    continuing {
-      v = 2i;
-      break if true;
-    }
-  }
-  return v_1;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVarInLoopInitializer_ThenReadAndWriteToVarInLoopBody) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* loop = b.Loop();
-        b.Append(loop->Initializer(), [&] {
-            auto* load = b.Load(var);
-            b.NextIteration(loop);
-            b.Append(loop->Body(), [&] {
-                b.Store(var, b.Add(ty.i32(), load, 1_i));
-                b.ExitLoop(loop);
-            });
-        });
-        b.Return(fn, 3_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  {
-    let v_1 = v;
-    loop {
-      v = (v_1 + 1i);
-      break;
-    }
-  }
-  return 3i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVarInLoopInitializer_ThenReadAndWriteToVarInLoopContinuing) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* loop = b.Loop();
-        b.Append(loop->Initializer(), [&] {
-            auto* load = b.Load(var);
-            b.NextIteration(loop);
-            b.Append(loop->Body(), [&] { b.Continue(loop); });
-            b.Append(loop->Continuing(), [&] {
-                b.Store(var, b.Add(ty.i32(), load, 1_i));
-                b.BreakIf(loop, true);
-            });
-        });
-        b.Return(fn, 3_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  {
-    let v_1 = v;
-    loop {
-
-      continuing {
-        v = (v_1 + 1i);
-        break if true;
-      }
-    }
-  }
-  return 3i;
-}
-)");
-}
-
-TEST_F(IRToProgramInliningTest, LoadVarInLoopBody_ThenReadAndWriteToVarInLoopContinuing) {
-    auto* fn = b.Function("f", ty.i32());
-    b.Append(fn->Block(), [&] {
-        auto* var = b.Var(ty.ptr<function, i32>());
-        b.Store(var, 1_i);
-        auto* loop = b.Loop();
-        b.Append(loop->Body(), [&] {
-            auto* load = b.Load(var);
-            b.Continue(loop);
-
-            b.Append(loop->Continuing(), [&] {
-                b.Store(var, b.Add(ty.i32(), load, 1_i));
-                b.BreakIf(loop, true);
-            });
-        });
-        b.Return(fn, 3_i);
-    });
-
-    EXPECT_WGSL(R"(
-fn f() -> i32 {
-  var v : i32;
-  v = 1i;
-  loop {
-    let v_1 = v;
-
-    continuing {
-      v = (v_1 + 1i);
-      break if true;
-    }
-  }
-  return 3i;
-}
-)");
-}
-
-}  // namespace
-}  // namespace tint::wgsl::writer
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index 028fee4..c0ee5e3 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -177,9 +177,6 @@
     /// The current switch case block
     const core::ir::Block* current_switch_case_ = nullptr;
 
-    /// Values that can be inlined.
-    Hashset<const core::ir::Value*, 64> can_inline_;
-
     /// Set of enable directives emitted.
     Hashset<wgsl::Extension, 4> enables_;
 
@@ -333,7 +330,6 @@
     StatementList Statements(const core::ir::Block* block) {
         StatementList stmts;
         if (block) {
-            MarkInlinable(block);
             TINT_SCOPED_ASSIGNMENT(statements_, &stmts);
             for (auto* inst : *block) {
                 Instruction(inst);
@@ -342,73 +338,6 @@
         return stmts;
     }
 
-    void MarkInlinable(const core::ir::Block* block) {
-        // An ordered list of possibly-inlinable values returned by sequenced instructions that have
-        // not yet been marked-for or ruled-out-for inlining.
-        UniqueVector<const core::ir::Value*, 32> pending_resolution;
-
-        // Walk the instructions of the block starting with the first.
-        for (auto* inst : *block) {
-            // Is the instruction sequenced?
-            bool sequenced = inst->Sequenced();
-
-            // Walk the instruction's operands starting with the right-most.
-            auto operands = inst->Operands();
-            for (auto* operand : tint::Reverse(operands)) {
-                if (!pending_resolution.Contains(operand)) {
-                    continue;
-                }
-                // Operand is in 'pending_resolution'
-
-                if (pending_resolution.TryPop(operand)) {
-                    // Operand was the last sequenced value to be added to 'pending_resolution'
-                    // This operand can be inlined as it does not change the sequencing order.
-                    can_inline_.Add(operand);
-                    sequenced = true;  // Inherit the 'sequenced' flag from the inlined value
-                } else {
-                    // Operand was in 'pending_resolution', but was not the last sequenced value to
-                    // be added. Inlining this operand would break the sequencing order, so must be
-                    // emitted as a let. All preceding pending values must also be emitted as a
-                    // let to prevent them being inlined and breaking the sequencing order.
-                    // Remove all the values in pending upto and including 'operand'.
-                    for (size_t i = 0; i < pending_resolution.Length(); i++) {
-                        if (pending_resolution[i] == operand) {
-                            pending_resolution.Erase(0, i + 1);
-                            break;
-                        }
-                    }
-                }
-            }
-
-            if (inst->Results().Length() == 1) {
-                // Instruction has a single result value.
-                // Check to see if the result of this instruction is a candidate for inlining.
-                auto* result = inst->Result(0);
-                // Only values with a single usage can be inlined.
-                // Named values are not inlined, as we want to emit the name for a let.
-                if (result->NumUsages() == 1 && !mod.NameOf(result).IsValid()) {
-                    if (sequenced) {
-                        // The value comes from a sequenced instruction. We need to ensure
-                        // instruction ordering so add it to 'pending_resolution'.
-                        pending_resolution.Add(result);
-                    } else {
-                        // The value comes from an unsequenced instruction. Just inline.
-                        can_inline_.Add(result);
-                    }
-                    continue;
-                }
-            }
-
-            // At this point the value has been ruled out for inlining.
-
-            if (sequenced) {
-                // A sequenced instruction with zero or multiple return values cannot be inlined.
-                // All preceding sequenced instructions cannot be inlined past this point.
-                pending_resolution.Clear();
-            }
-        }
-    }
-
     void Append(const ast::Statement* inst) { statements_->Push(inst); }
 
     void Instruction(const core::ir::Instruction* inst) {
@@ -493,7 +422,6 @@
         const ast::Expression* cond = nullptr;
         StatementList body_stmts;
         {
-            MarkInlinable(l->Body());
             TINT_SCOPED_ASSIGNMENT(statements_, &body_stmts);
             for (auto* inst : *l->Body()) {
                 if (body_stmts.IsEmpty()) {
@@ -658,9 +586,14 @@
     }
 
     void Let(const core::ir::Let* let) {
-        Symbol name = NameFor(let->Result(0));
-        Append(b.Decl(b.Let(name, Expr(let->Value(), PtrKind::kPtr))));
-        Bind(let->Result(0), name, PtrKind::kPtr);
+        auto* result = let->Result(0);
+        if (mod.NameOf(result).IsValid() || result->NumUsages() > 0) {
+            Symbol name = NameFor(result);
+            Append(b.Decl(b.Let(name, Expr(let->Value(), PtrKind::kPtr))));
+            Bind(result, name, PtrKind::kPtr);
+        } else {
+            Append(b.Assign(b.Phony(), Expr(let->Value(), PtrKind::kPtr)));
+        }
     }
 
     void Store(const core::ir::Store* store) {
@@ -1142,30 +1075,10 @@
               const ast::Expression* expr,
               PtrKind ptr_kind = PtrKind::kRef) {
         TINT_ASSERT(value);
-        if (can_inline_.Remove(value)) {
-            // Value will be inlined at its place of usage.
-            if (TINT_LIKELY(bindings_.Add(value, InlinedValue{expr, ptr_kind}))) {
-                return;
-            }
-        } else {
-            if (value->Type()->Is<core::type::Pointer>()) {
-                expr = ToPtrKind(expr, ptr_kind, PtrKind::kPtr);
-            }
-            auto mod_name = mod.NameOf(value);
-            if (!value->IsUsed() && !mod_name.IsValid()) {
-                // Value has no usages and no name.
-                // Assign to a phony. These support more data types than a 'let', and avoids
-                // allocation of unused names.
-                Append(b.Assign(b.Phony(), expr));
-            } else {
-                Symbol name = NameFor(value, mod_name.NameView());
-                Append(b.Decl(b.Let(name, expr)));
-                Bind(value, name, PtrKind::kPtr);
-            }
-            return;
+        // Value will be inlined at its place of usage.
+        if (TINT_UNLIKELY(!bindings_.Add(value, InlinedValue{expr, ptr_kind}))) {
+            TINT_ICE() << "Bind(" << value->TypeInfo().name << ") called twice for same value";
         }
-
-        TINT_ICE() << "Bind(" << value->TypeInfo().name << ") called twice for same value";
     }
 
     /// Associates the IR value @p value with the AST 'var', 'let' or parameter with the name @p
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
index c2fff06..15395bb 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
@@ -1006,218 +1006,7 @@
 )");
 }
 
-TEST_F(IRToProgramTest, ShortCircuit_And_Let_2) {
-    auto* fn = b.Function("f", ty.bool_());
-    auto* pa = b.FunctionParam("a", ty.bool_());
-    auto* pb = b.FunctionParam("b", ty.bool_());
-    fn->SetParams({pa, pb});
-
-    b.Append(fn->Block(), [&] {
-        auto* if_ = b.If(pa);
-        if_->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if_->True(), [&] { b.ExitIf(if_, pb); });
-        b.Append(if_->False(), [&] { b.ExitIf(if_, false); });
-
-        mod.SetName(if_, "l");
-        b.Return(fn, if_);
-    });
-
-    EXPECT_WGSL(R"(
-fn f(a : bool, b : bool) -> bool {
-  let l = (a && b);
-  return l;
-}
-)");
-}
-
-TEST_F(IRToProgramTest, ShortCircuit_And_Let_3_ab_c) {
-    auto* fn = b.Function("f", ty.bool_());
-    auto* pa = b.FunctionParam("a", ty.bool_());
-    auto* pb = b.FunctionParam("b", ty.bool_());
-    auto* pc = b.FunctionParam("c", ty.bool_());
-    fn->SetParams({pa, pb, pc});
-
-    b.Append(fn->Block(), [&] {
-        auto* if1 = b.If(pa);
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, pb); });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
-
-        auto* if2 = b.If(if1);
-        if2->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if2->True(), [&] { b.ExitIf(if2, pc); });
-        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
-
-        mod.SetName(if2, "l");
-        b.Return(fn, if2);
-    });
-
-    EXPECT_WGSL(R"(
-fn f(a : bool, b : bool, c : bool) -> bool {
-  let l = ((a && b) && c);
-  return l;
-}
-)");
-}
-
-TEST_F(IRToProgramTest, ShortCircuit_And_Let_3_a_bc) {
-    auto* fn = b.Function("f", ty.bool_());
-    auto* pa = b.FunctionParam("a", ty.bool_());
-    auto* pb = b.FunctionParam("b", ty.bool_());
-    auto* pc = b.FunctionParam("c", ty.bool_());
-    fn->SetParams({pa, pb, pc});
-
-    b.Append(fn->Block(), [&] {
-        auto* if1 = b.If(pa);
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] {
-            auto* if2 = b.If(pb);
-            if2->SetResults(b.InstructionResult(ty.bool_()));
-            b.Append(if2->True(), [&] { b.ExitIf(if2, pc); });
-            b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
-
-            b.ExitIf(if1, if2);
-        });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
-
-        mod.SetName(if1, "l");
-        b.Return(fn, if1);
-    });
-
-    EXPECT_WGSL(R"(
-fn f(a : bool, b : bool, c : bool) -> bool {
-  let l = (a && (b && c));
-  return l;
-}
-)");
-}
-
-TEST_F(IRToProgramTest, ShortCircuit_And_Call_2) {
-    auto* fn_a = b.Function("a", ty.bool_());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
-
-    auto* fn_b = b.Function("b", ty.bool_());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
-
-    auto* fn = b.Function("f", ty.bool_());
-
-    b.Append(fn->Block(), [&] {
-        auto* if_ = b.If(b.Call(ty.bool_(), fn_a));
-        if_->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if_->True(), [&] { b.ExitIf(if_, b.Call(ty.bool_(), fn_b)); });
-        b.Append(if_->False(), [&] { b.ExitIf(if_, false); });
-
-        b.Return(fn, if_);
-    });
-
-    EXPECT_WGSL(R"(
-fn a() -> bool {
-  return true;
-}
-
-fn b() -> bool {
-  return true;
-}
-
-fn f() -> bool {
-  return (a() && b());
-}
-)");
-}
-
-TEST_F(IRToProgramTest, ShortCircuit_And_Call_3_ab_c) {
-    auto* fn_a = b.Function("a", ty.bool_());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
-
-    auto* fn_b = b.Function("b", ty.bool_());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
-
-    auto* fn_c = b.Function("c", ty.bool_());
-    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
-
-    auto* fn = b.Function("f", ty.bool_());
-
-    b.Append(fn->Block(), [&] {
-        auto* if1 = b.If(b.Call(ty.bool_(), fn_a));
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, b.Call(ty.bool_(), fn_b)); });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
-
-        auto* if2 = b.If(if1);
-        if2->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if2->True(), [&] { b.ExitIf(if2, b.Call(ty.bool_(), fn_c)); });
-        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
-
-        b.Return(fn, if2);
-    });
-
-    EXPECT_WGSL(R"(
-fn a() -> bool {
-  return true;
-}
-
-fn b() -> bool {
-  return true;
-}
-
-fn c() -> bool {
-  return true;
-}
-
-fn f() -> bool {
-  return ((a() && b()) && c());
-}
-)");
-}
-
-TEST_F(IRToProgramTest, ShortCircuit_And_Call_3_a_bc) {
-    auto* fn_a = b.Function("a", ty.bool_());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
-
-    auto* fn_b = b.Function("b", ty.bool_());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
-
-    auto* fn_c = b.Function("c", ty.bool_());
-    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
-
-    auto* fn = b.Function("f", ty.bool_());
-
-    b.Append(fn->Block(), [&] {
-        auto* if1 = b.If(b.Call(ty.bool_(), fn_a));
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] {
-            auto* if2 = b.If(b.Call(ty.bool_(), fn_b));
-            if2->SetResults(b.InstructionResult(ty.bool_()));
-            b.Append(if2->True(), [&] { b.ExitIf(if2, b.Call(ty.bool_(), fn_c)); });
-            b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
-
-            b.ExitIf(if1, if2);
-        });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
-
-        b.Return(fn, if1);
-    });
-
-    EXPECT_WGSL(R"(
-fn a() -> bool {
-  return true;
-}
-
-fn b() -> bool {
-  return true;
-}
-
-fn c() -> bool {
-  return true;
-}
-
-fn f() -> bool {
-  return (a() && (b() && c()));
-}
-)");
-}
-
-TEST_F(IRToProgramTest, ShortCircuit_Or_Param_2) {
+TEST_F(IRToProgramTest, ShortCircuit_Or_2) {
     auto* fn = b.Function("f", ty.bool_());
     auto* pa = b.FunctionParam("a", ty.bool_());
     auto* pb = b.FunctionParam("b", ty.bool_());
@@ -1239,7 +1028,7 @@
 )");
 }
 
-TEST_F(IRToProgramTest, ShortCircuit_Or_Param_3_ab_c) {
+TEST_F(IRToProgramTest, ShortCircuit_Or_3_ab_c) {
     auto* fn = b.Function("f", ty.bool_());
     auto* pa = b.FunctionParam("a", ty.bool_());
     auto* pb = b.FunctionParam("b", ty.bool_());
@@ -1267,7 +1056,7 @@
 )");
 }
 
-TEST_F(IRToProgramTest, ShortCircuit_Or_Param_3_a_bc) {
+TEST_F(IRToProgramTest, ShortCircuit_Or_3_a_bc) {
     auto* fn = b.Function("f", ty.bool_());
     auto* pa = b.FunctionParam("a", ty.bool_());
     auto* pb = b.FunctionParam("b", ty.bool_());
@@ -1297,217 +1086,6 @@
 )");
 }
 
-TEST_F(IRToProgramTest, ShortCircuit_Or_Let_2) {
-    auto* fn = b.Function("f", ty.bool_());
-    auto* pa = b.FunctionParam("a", ty.bool_());
-    auto* pb = b.FunctionParam("b", ty.bool_());
-    fn->SetParams({pa, pb});
-
-    b.Append(fn->Block(), [&] {
-        auto* if_ = b.If(pa);
-        if_->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if_->True(), [&] { b.ExitIf(if_, true); });
-        b.Append(if_->False(), [&] { b.ExitIf(if_, pb); });
-
-        mod.SetName(if_, "l");
-        b.Return(fn, if_);
-    });
-
-    EXPECT_WGSL(R"(
-fn f(a : bool, b : bool) -> bool {
-  let l = (a || b);
-  return l;
-}
-)");
-}
-
-TEST_F(IRToProgramTest, ShortCircuit_Or_Let_3_ab_c) {
-    auto* fn = b.Function("f", ty.bool_());
-    auto* pa = b.FunctionParam("a", ty.bool_());
-    auto* pb = b.FunctionParam("b", ty.bool_());
-    auto* pc = b.FunctionParam("c", ty.bool_());
-    fn->SetParams({pa, pb, pc});
-
-    b.Append(fn->Block(), [&] {
-        auto* if1 = b.If(pa);
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, pb); });
-
-        auto* if2 = b.If(if1);
-        if2->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
-        b.Append(if2->False(), [&] { b.ExitIf(if2, pc); });
-
-        mod.SetName(if2, "l");
-        b.Return(fn, if2);
-    });
-
-    EXPECT_WGSL(R"(
-fn f(a : bool, b : bool, c : bool) -> bool {
-  let l = ((a || b) || c);
-  return l;
-}
-)");
-}
-
-TEST_F(IRToProgramTest, ShortCircuit_Or_Let_3_a_bc) {
-    auto* fn = b.Function("f", ty.bool_());
-    auto* pa = b.FunctionParam("a", ty.bool_());
-    auto* pb = b.FunctionParam("b", ty.bool_());
-    auto* pc = b.FunctionParam("c", ty.bool_());
-    fn->SetParams({pa, pb, pc});
-
-    b.Append(fn->Block(), [&] {
-        auto* if1 = b.If(pa);
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
-        b.Append(if1->False(), [&] {
-            auto* if2 = b.If(pb);
-            if2->SetResults(b.InstructionResult(ty.bool_()));
-            b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
-            b.Append(if2->False(), [&] { b.ExitIf(if2, pc); });
-
-            b.ExitIf(if1, if2);
-        });
-
-        mod.SetName(if1, "l");
-        b.Return(fn, if1);
-    });
-
-    EXPECT_WGSL(R"(
-fn f(a : bool, b : bool, c : bool) -> bool {
-  let l = (a || (b || c));
-  return l;
-}
-)");
-}
-
-TEST_F(IRToProgramTest, ShortCircuit_Or_Call_2) {
-    auto* fn_a = b.Function("a", ty.bool_());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
-
-    auto* fn_b = b.Function("b", ty.bool_());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
-
-    auto* fn = b.Function("f", ty.bool_());
-
-    b.Append(fn->Block(), [&] {
-        auto* if_ = b.If(b.Call(ty.bool_(), fn_a));
-        if_->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if_->True(), [&] { b.ExitIf(if_, true); });
-        b.Append(if_->False(), [&] { b.ExitIf(if_, b.Call(ty.bool_(), fn_b)); });
-
-        b.Return(fn, if_);
-    });
-
-    EXPECT_WGSL(R"(
-fn a() -> bool {
-  return true;
-}
-
-fn b() -> bool {
-  return true;
-}
-
-fn f() -> bool {
-  return (a() || b());
-}
-)");
-}
-
-TEST_F(IRToProgramTest, ShortCircuit_Or_Call_3_ab_c) {
-    auto* fn_a = b.Function("a", ty.bool_());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
-
-    auto* fn_b = b.Function("b", ty.bool_());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
-
-    auto* fn_c = b.Function("c", ty.bool_());
-    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
-
-    auto* fn = b.Function("f", ty.bool_());
-
-    b.Append(fn->Block(), [&] {
-        auto* if1 = b.If(b.Call(ty.bool_(), fn_a));
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, b.Call(ty.bool_(), fn_b)); });
-
-        auto* if2 = b.If(if1);
-        if2->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
-        b.Append(if2->False(), [&] { b.ExitIf(if2, b.Call(ty.bool_(), fn_c)); });
-
-        b.Return(fn, if2);
-    });
-
-    EXPECT_WGSL(R"(
-fn a() -> bool {
-  return true;
-}
-
-fn b() -> bool {
-  return true;
-}
-
-fn c() -> bool {
-  return true;
-}
-
-fn f() -> bool {
-  return ((a() || b()) || c());
-}
-)");
-}
-
-TEST_F(IRToProgramTest, ShortCircuit_Or_Call_3_a_bc) {
-    auto* fn_a = b.Function("a", ty.bool_());
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
-
-    auto* fn_b = b.Function("b", ty.bool_());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
-
-    auto* fn_c = b.Function("c", ty.bool_());
-    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
-
-    auto* fn = b.Function("f", ty.bool_());
-
-    b.Append(fn->Block(), [&] {
-        auto* if1 = b.If(b.Call(ty.bool_(), fn_a));
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
-        b.Append(if1->False(), [&] {
-            auto* if2 = b.If(b.Call(ty.bool_(), fn_b));
-            if2->SetResults(b.InstructionResult(ty.bool_()));
-            b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
-            b.Append(if2->False(), [&] { b.ExitIf(if2, b.Call(ty.bool_(), fn_c)); });
-
-            b.ExitIf(if1, if2);
-        });
-
-        b.Return(fn, if1);
-    });
-
-    EXPECT_WGSL(R"(
-fn a() -> bool {
-  return true;
-}
-
-fn b() -> bool {
-  return true;
-}
-
-fn c() -> bool {
-  return true;
-}
-
-fn f() -> bool {
-  return (a() || (b() || c()));
-}
-)");
-}
-
 TEST_F(IRToProgramTest, ShortCircuit_Mixed) {
     auto* fn_b = b.Function("b", ty.bool_());
     b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
@@ -1552,257 +1130,7 @@
 }
 
 fn f(a : bool, c : bool) -> bool {
-  let l = ((a || b()) && (c || d()));
-  return l;
-}
-)");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Non short-circuiting binary ops
-// Similar to the above, but cannot be short-circuited as the RHS is evaluated
-// outside of the if block.
-////////////////////////////////////////////////////////////////////////////////
-TEST_F(IRToProgramTest, NonShortCircuit_And_ParamCallParam_a_bc) {
-    auto* fn_b = b.Function("b", ty.bool_());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
-
-    auto* fn = b.Function("f", ty.bool_());
-    auto* pa = b.FunctionParam(ty.bool_());
-    auto* pc = b.FunctionParam(ty.bool_());
-    mod.SetName(pa, "a");
-    mod.SetName(pc, "c");
-    fn->SetParams({pa, pc});
-
-    b.Append(fn->Block(), [&] {
-        // 'b() && c' is evaluated before 'a'.
-        auto* if1 = b.If(b.Call(ty.bool_(), fn_b));
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, pc); });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
-
-        auto* if2 = b.If(pa);
-        if2->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if2->True(), [&] { b.ExitIf(if2, if1); });
-        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
-        b.Return(fn, if2);
-    });
-
-    EXPECT_WGSL(R"(
-fn b() -> bool {
-  return true;
-}
-
-fn f(a : bool, c : bool) -> bool {
-  let v = (b() && c);
-  return (a && v);
-}
-)");
-}
-
-TEST_F(IRToProgramTest, NonShortCircuit_And_Call_3_a_bc) {
-    auto* fn_a = b.Function("a", ty.bool_());
-
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
-
-    auto* fn_b = b.Function("b", ty.bool_());
-
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
-
-    auto* fn_c = b.Function("c", ty.bool_());
-
-    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
-
-    auto* fn = b.Function("f", ty.bool_());
-
-    b.Append(fn->Block(), [&] {
-        // 'b() && c()' is evaluated before 'a()'.
-        auto* if1 = b.If(b.Call(ty.bool_(), fn_b));
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, b.Call(ty.bool_(), fn_c)); });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
-
-        auto* if2 = b.If(b.Call(ty.bool_(), fn_a));
-        if2->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if2->True(), [&] { b.ExitIf(if2, if1); });
-        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
-
-        b.Return(fn, if2);
-    });
-
-    EXPECT_WGSL(R"(
-fn a() -> bool {
-  return true;
-}
-
-fn b() -> bool {
-  return true;
-}
-
-fn c() -> bool {
-  return true;
-}
-
-fn f() -> bool {
-  let v = (b() && c());
-  return (a() && v);
-}
-)");
-}
-
-TEST_F(IRToProgramTest, NonShortCircuit_And_Param_3_a_bc_EarlyEval) {
-    auto* fn = b.Function("f", ty.bool_());
-    auto* pa = b.FunctionParam(ty.bool_());
-    auto* pb = b.FunctionParam(ty.bool_());
-    auto* pc = b.FunctionParam(ty.bool_());
-    mod.SetName(pa, "a");
-    mod.SetName(pb, "b");
-    mod.SetName(pc, "c");
-    fn->SetParams({pa, pb, pc});
-
-    b.Append(fn->Block(), [&] {
-        // 'b && c' is evaluated outside the true block of if2, but these can be moved to the RHS
-        // of the 'a &&' as the 'b && c' is not sequenced.
-        auto* if1 = b.If(pb);
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, pc); });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
-
-        auto* if2 = b.If(pa);
-        if2->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if2->True(), [&] { b.ExitIf(if2, if1); });
-        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
-
-        b.Return(fn, if2);
-    });
-
-    EXPECT_WGSL(R"(
-fn f(a : bool, b : bool, c : bool) -> bool {
-  let v = (b && c);
-  return (a && v);
-}
-)");
-}
-
-TEST_F(IRToProgramTest, NonShortCircuit_Or_ParamCallParam_a_bc) {
-    auto* fn_b = b.Function("b", ty.bool_());
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
-
-    auto* fn = b.Function("f", ty.bool_());
-    auto* pa = b.FunctionParam(ty.bool_());
-    auto* pc = b.FunctionParam(ty.bool_());
-    mod.SetName(pa, "a");
-    mod.SetName(pc, "c");
-    fn->SetParams({pa, pc});
-
-    b.Append(fn->Block(), [&] {
-        // 'b() && c' is evaluated before 'a'.
-        auto* if1 = b.If(b.Call(ty.bool_(), fn_b));
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, pc); });
-
-        auto* if2 = b.If(pa);
-        if2->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
-        b.Append(if2->False(), [&] { b.ExitIf(if2, if1); });
-
-        mod.SetName(if2, "l");
-        b.Return(fn, if2);
-    });
-
-    EXPECT_WGSL(R"(
-fn b() -> bool {
-  return true;
-}
-
-fn f(a : bool, c : bool) -> bool {
-  let v = (b() || c);
-  let l = (a || v);
-  return l;
-}
-)");
-}
-
-TEST_F(IRToProgramTest, NonShortCircuit_Or_Call_3_a_bc) {
-    auto* fn_a = b.Function("a", ty.bool_());
-
-    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
-
-    auto* fn_b = b.Function("b", ty.bool_());
-
-    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
-
-    auto* fn_c = b.Function("c", ty.bool_());
-
-    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
-
-    auto* fn = b.Function("f", ty.bool_());
-
-    b.Append(fn->Block(), [&] {
-        auto* if1 = b.If(b.Call(ty.bool_(), fn_b));
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, b.Call(ty.bool_(), fn_c)); });
-
-        auto* if2 = b.If(b.Call(ty.bool_(), fn_a));
-        if2->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
-        b.Append(if2->False(), [&] { b.ExitIf(if2, if1); });
-
-        b.Return(fn, if2);
-    });
-
-    EXPECT_WGSL(R"(
-fn a() -> bool {
-  return true;
-}
-
-fn b() -> bool {
-  return true;
-}
-
-fn c() -> bool {
-  return true;
-}
-
-fn f() -> bool {
-  let v = (b() || c());
-  return (a() || v);
-}
-)");
-}
-
-TEST_F(IRToProgramTest, NonShortCircuit_Or_Param_3_a_bc_EarlyEval) {
-    auto* fn = b.Function("f", ty.bool_());
-    auto* pa = b.FunctionParam(ty.bool_());
-    auto* pb = b.FunctionParam(ty.bool_());
-    auto* pc = b.FunctionParam(ty.bool_());
-    mod.SetName(pa, "a");
-    mod.SetName(pb, "b");
-    mod.SetName(pc, "c");
-    fn->SetParams({pa, pb, pc});
-
-    b.Append(fn->Block(), [&] {
-        // 'b || c' is evaluated outside the true block of if2, but these can be moved to the RHS
-        // of the 'a ||' as the 'b || c' is not sequenced.
-        auto* if1 = b.If(pb);
-        if1->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
-        b.Append(if1->False(), [&] { b.ExitIf(if1, pc); });
-
-        auto* if2 = b.If(pa);
-        if2->SetResults(b.InstructionResult(ty.bool_()));
-        b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
-        b.Append(if2->False(), [&] { b.ExitIf(if2, if1); });
-
-        b.Return(fn, if2);
-    });
-
-    EXPECT_WGSL(R"(
-fn f(a : bool, b : bool, c : bool) -> bool {
-  let v = (b || c);
-  return (a || v);
+  return ((a || b()) && (c || d()));
 }
 )");
 }
diff --git a/src/tint/lang/wgsl/writer/raise/BUILD.bazel b/src/tint/lang/wgsl/writer/raise/BUILD.bazel
index e403363..00fe151 100644
--- a/src/tint/lang/wgsl/writer/raise/BUILD.bazel
+++ b/src/tint/lang/wgsl/writer/raise/BUILD.bazel
@@ -41,10 +41,12 @@
   srcs = [
     "raise.cc",
     "rename_conflicts.cc",
+    "value_to_let.cc",
   ],
   hdrs = [
     "raise.h",
     "rename_conflicts.h",
+    "value_to_let.h",
   ],
   deps = [
     "//src/tint/api/common",
@@ -79,6 +81,7 @@
   srcs = [
     "raise_test.cc",
     "rename_conflicts_test.cc",
+    "value_to_let_test.cc",
   ],
   deps = [
     "//src/tint/api/common",
diff --git a/src/tint/lang/wgsl/writer/raise/BUILD.cmake b/src/tint/lang/wgsl/writer/raise/BUILD.cmake
index cf18c7f..6bc7469 100644
--- a/src/tint/lang/wgsl/writer/raise/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/raise/BUILD.cmake
@@ -43,6 +43,8 @@
   lang/wgsl/writer/raise/raise.h
   lang/wgsl/writer/raise/rename_conflicts.cc
   lang/wgsl/writer/raise/rename_conflicts.h
+  lang/wgsl/writer/raise/value_to_let.cc
+  lang/wgsl/writer/raise/value_to_let.h
 )
 
 tint_target_add_dependencies(tint_lang_wgsl_writer_raise lib
@@ -77,6 +79,7 @@
 tint_add_target(tint_lang_wgsl_writer_raise_test test
   lang/wgsl/writer/raise/raise_test.cc
   lang/wgsl/writer/raise/rename_conflicts_test.cc
+  lang/wgsl/writer/raise/value_to_let_test.cc
 )
 
 tint_target_add_dependencies(tint_lang_wgsl_writer_raise_test test
diff --git a/src/tint/lang/wgsl/writer/raise/BUILD.gn b/src/tint/lang/wgsl/writer/raise/BUILD.gn
index 53b013a..f873e62 100644
--- a/src/tint/lang/wgsl/writer/raise/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/raise/BUILD.gn
@@ -48,6 +48,8 @@
     "raise.h",
     "rename_conflicts.cc",
     "rename_conflicts.h",
+    "value_to_let.cc",
+    "value_to_let.h",
   ]
   deps = [
     "${tint_src_dir}/api/common",
@@ -79,6 +81,7 @@
     sources = [
       "raise_test.cc",
       "rename_conflicts_test.cc",
+      "value_to_let_test.cc",
     ]
     deps = [
       "${tint_src_dir}:gmock_and_gtest",
diff --git a/src/tint/lang/wgsl/writer/raise/raise.cc b/src/tint/lang/wgsl/writer/raise/raise.cc
index 9a64c26..e2c4f56 100644
--- a/src/tint/lang/wgsl/writer/raise/raise.cc
+++ b/src/tint/lang/wgsl/writer/raise/raise.cc
@@ -36,6 +36,7 @@
 #include "src/tint/lang/wgsl/builtin_fn.h"
 #include "src/tint/lang/wgsl/ir/builtin_call.h"
 #include "src/tint/lang/wgsl/writer/raise/rename_conflicts.h"
+#include "src/tint/lang/wgsl/writer/raise/value_to_let.h"
 
 namespace tint::wgsl::writer {
 namespace {
@@ -233,6 +234,9 @@
     if (auto result = raise::RenameConflicts(mod); result != Success) {
         return result.Failure();
     }
+    if (auto result = raise::ValueToLet(mod); result != Success) {
+        return result.Failure();
+    }
 
     return Success;
 }
diff --git a/src/tint/lang/wgsl/writer/raise/raise_test.cc b/src/tint/lang/wgsl/writer/raise/raise_test.cc
index 499d41b..fbdb64b 100644
--- a/src/tint/lang/wgsl/writer/raise/raise_test.cc
+++ b/src/tint/lang/wgsl/writer/raise/raise_test.cc
@@ -60,6 +60,7 @@
 %f = func():void -> %b1 {
   %b1 = block {
     %2:i32 = wgsl.max 1i, 2i
+    %3:i32 = let %2
     ret
   }
 }
@@ -154,8 +155,9 @@
     %3:void = wgsl.workgroupBarrier
     store %W, 42i
     %4:i32 = load %W
-    %5:void = wgsl.workgroupBarrier
-    ret %4
+    %5:i32 = let %4
+    %6:void = wgsl.workgroupBarrier
+    ret %5
   }
 }
 )";
diff --git a/src/tint/lang/wgsl/writer/raise/value_to_let.cc b/src/tint/lang/wgsl/writer/raise/value_to_let.cc
new file mode 100644
index 0000000..ea14ec2
--- /dev/null
+++ b/src/tint/lang/wgsl/writer/raise/value_to_let.cc
@@ -0,0 +1,199 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/wgsl/writer/raise/value_to_let.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "src/tint/lang/core/ir/builder.h"
+#include "src/tint/lang/core/ir/validator.h"
+#include "src/tint/utils/containers/reverse.h"
+
+namespace tint::wgsl::writer::raise {
+
+namespace {
+
+/// PIMPL state for the transform.
+struct State {
+    /// The IR module.
+    core::ir::Module& ir;
+
+    /// The IR builder.
+    core::ir::Builder b{ir};
+
+    /// The type manager.
+    core::type::Manager& ty{ir.Types()};
+
+    /// Process the module.
+    void Process() {
+        // Process each block.
+        for (auto* block : ir.blocks.Objects()) {
+            if (block != ir.root_block) {
+                Process(block);
+            }
+        }
+    }
+
+  private:
+    void Process(core::ir::Block* block) {
+        // An ordered list of possibly-inlinable values returned by sequenced instructions that have
+        // not yet been marked-for or ruled-out-for inlining.
+        UniqueVector<core::ir::InstructionResult*, 32> pending_resolution;
+
+        auto hoist_pending = [&](size_t count = std::numeric_limits<size_t>::max()) {
+            size_t n = std::min(count, pending_resolution.Length());
+            if (n > 0) {
+                for (size_t i = 0; i < n; i++) {
+                    MaybeReplaceWithLet(pending_resolution[i]);
+                }
+                pending_resolution.Erase(0, n);
+            }
+        };
+
+        // Walk the instructions of the block starting with the first.
+        for (auto* inst = block->Front(); inst;) {
+            auto next = inst->next;
+            TINT_DEFER(inst = next);
+
+            // Is the instruction sequenced?
+            bool sequenced = inst->Sequenced();
+
+            // Walk the instruction's operands starting with the right-most.
+            auto operands = inst->Operands();
+            for (auto* operand : tint::Reverse(operands)) {
+                if (!operand) {
+                    continue;
+                }
+
+                auto* value = operand->As<core::ir::InstructionResult>();
+                if (!pending_resolution.Contains(value)) {
+                    continue;
+                }
+                // Operand is in 'pending_resolution'
+
+                if (pending_resolution.TryPop(value)) {
+                    // Operand was the last sequenced value to be added to 'pending_resolution'
+                    // This operand can be inlined as it does not change the sequencing order.
+                    sequenced = true;  // Inherit the 'sequenced' flag from the inlined value
+                } else {
+                    // Operand was in 'pending_resolution', but was not the last sequenced value to
+                    // be added. Inlining this operand would break the sequencing order, so must be
+                    // emitted as a let. All preceding pending values must also be emitted as a
+                    // let to prevent them being inlined and breaking the sequencing order.
+                    // Remove all the values in pending up to and including 'operand'.
+                    for (size_t i = 0; i < pending_resolution.Length(); i++) {
+                        if (pending_resolution[i] == operand) {
+                            hoist_pending(i + 1);
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if (inst->Results().Length() == 1) {
+                // Instruction has a single result value.
+                // Check to see if the result of this instruction is a candidate for inlining.
+                auto* result = inst->Result(0);
+                // Only values with a single usage can be inlined.
+                // Named values are not inlined, as we want to emit the name for a let.
+                if (CanInline(result)) {
+                    if (sequenced) {
+                        // The value comes from a sequenced instruction. We need to ensure
+                        // instruction ordering so add it to 'pending_resolution'.
+                        pending_resolution.Add(result);
+                    }
+                    continue;
+                }
+
+                MaybeReplaceWithLet(result);
+            }
+
+            // At this point the value has been ruled out for inlining.
+
+            if (sequenced) {
+                // A sequenced instruction with zero or multiple return values cannot be inlined.
+                // All preceding sequenced instructions cannot be inlined past this point.
+                hoist_pending();
+            }
+        }
+
+        hoist_pending();
+    }
+
+    bool CanInline(core::ir::InstructionResult* value) {
+        if (ir.NameOf(value).IsValid()) {
+            // Named values should become lets
+            return false;
+        }
+
+        if (value->NumUsages() != 1) {
+            // Zero or multiple uses cannot be inlined
+            return false;
+        }
+
+        return true;
+    }
+
+    void MaybeReplaceWithLet(core::ir::InstructionResult* value) {
+        auto* inst = value->Instruction();
+        if (inst->IsAnyOf<core::ir::Var, core::ir::Let>()) {
+            return;
+        }
+        if (inst->Is<core::ir::Call>() && value->Usages().IsEmpty()) {
+            bool must_use =
+                inst->Is<core::ir::BuiltinCall>() && !value->Type()->Is<core::type::Void>();
+            if (!must_use) {
+                return;  // Call statement
+            }
+        }
+
+        auto* let = b.Let(value->Type());
+        value->ReplaceAllUsesWith(let->Result(0));
+        let->SetValue(value);
+        let->InsertAfter(inst);
+        if (auto name = ir.NameOf(value); name.IsValid()) {
+            ir.SetName(let, name.Name());
+            ir.ClearName(value);
+        }
+    }
+};
+
+}  // namespace
+
+Result<SuccessType> ValueToLet(core::ir::Module& ir) {
+    auto result = core::ir::ValidateAndDumpIfNeeded(ir, "ValueToLet transform");
+    if (result != Success) {
+        return result;
+    }
+
+    State{ir}.Process();
+
+    return Success;
+}
+
+}  // namespace tint::wgsl::writer::raise
diff --git a/src/tint/lang/wgsl/writer/raise/value_to_let.h b/src/tint/lang/wgsl/writer/raise/value_to_let.h
new file mode 100644
index 0000000..2a3b4c0
--- /dev/null
+++ b/src/tint/lang/wgsl/writer/raise/value_to_let.h
@@ -0,0 +1,54 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_WGSL_WRITER_RAISE_VALUE_TO_LET_H_
+#define SRC_TINT_LANG_WGSL_WRITER_RAISE_VALUE_TO_LET_H_
+
+#include "src/tint/utils/result/result.h"
+
+// Forward declarations.
+namespace tint::core::ir {
+class Module;
+}
+
+namespace tint::wgsl::writer::raise {
+
+/// ValueToLet is a transform that moves "non-inlinable" instruction values to let instructions.
+/// An expression is considered "non-inlinable" if any of the the following are true:
+/// * The value has multiple uses.
+/// * The value's instruction is a load that when inlined would cross a store instruction.
+/// * The value's instruction is a store instruction that when inlined would cross a load or store
+///   instruction.
+/// * The value is used in a block different to the value's instruction.
+///
+/// @param module the module to transform
+/// @returns error diagnostics on failure
+Result<SuccessType> ValueToLet(core::ir::Module& module);
+
+}  // namespace tint::wgsl::writer::raise
+
+#endif  // SRC_TINT_LANG_WGSL_WRITER_RAISE_VALUE_TO_LET_H_
diff --git a/src/tint/lang/wgsl/writer/raise/value_to_let_test.cc b/src/tint/lang/wgsl/writer/raise/value_to_let_test.cc
new file mode 100644
index 0000000..d9ac335
--- /dev/null
+++ b/src/tint/lang/wgsl/writer/raise/value_to_let_test.cc
@@ -0,0 +1,2693 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/wgsl/writer/raise/value_to_let.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/ir/transform/helper_test.h"
+
+namespace tint::wgsl::writer::raise {
+namespace {
+
+using namespace tint::core::fluent_types;     // NOLINT
+using namespace tint::core::number_suffixes;  // NOLINT
+
+using WgslWriter_ValueToLetTest = tint::core::ir::transform::TransformTest;
+
+TEST_F(WgslWriter_ValueToLetTest, Empty) {
+    auto* expect = R"(
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Load / Store
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenStoreVar_ThenUseLoad) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* load = b.Load(var);
+        b.Store(var, 2_i);
+        b.Return(fn, load);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    store %2, 2i
+    ret %3
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    %4:i32 = let %3
+    store %2, 2i
+    ret %4
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Binary op
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(WgslWriter_ValueToLetTest, BinaryOpUnsequencedLHSThenUnsequencedRHS) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] {
+        auto* lhs = b.Add(ty.i32(), 1_i, 2_i);
+        auto* rhs = b.Add(ty.i32(), 3_i, 4_i);
+        auto* bin = b.Add(ty.i32(), lhs, rhs);
+        b.Return(fn_b, bin);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func():i32 -> %b2 {
+  %b2 = block {
+    %4:i32 = add 1i, 2i
+    %5:i32 = add 3i, 4i
+    %6:i32 = add %4, %5
+    ret %6
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, BinaryOpSequencedLHSThenUnsequencedRHS) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] {
+        auto* lhs = b.Call(ty.i32(), fn_a, 1_i);
+        auto* rhs = b.Add(ty.i32(), 2_i, 3_i);
+        auto* bin = b.Add(ty.i32(), lhs, rhs);
+        b.Return(fn_b, bin);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func():i32 -> %b2 {
+  %b2 = block {
+    %4:i32 = call %a, 1i
+    %5:i32 = add 2i, 3i
+    %6:i32 = add %4, %5
+    ret %6
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, BinaryOpUnsequencedLHSThenSequencedRHS) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] {
+        auto* lhs = b.Add(ty.i32(), 1_i, 2_i);
+        auto* rhs = b.Call(ty.i32(), fn_a, 3_i);
+        auto* bin = b.Add(ty.i32(), lhs, rhs);
+        b.Return(fn_b, bin);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func():i32 -> %b2 {
+  %b2 = block {
+    %4:i32 = add 1i, 2i
+    %5:i32 = call %a, 3i
+    %6:i32 = add %4, %5
+    ret %6
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, BinaryOpSequencedLHSThenSequencedRHS) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] {
+        auto* lhs = b.Call(ty.i32(), fn_a, 1_i);
+        auto* rhs = b.Call(ty.i32(), fn_a, 2_i);
+        auto* bin = b.Add(ty.i32(), lhs, rhs);
+        b.Return(fn_b, bin);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func():i32 -> %b2 {
+  %b2 = block {
+    %4:i32 = call %a, 1i
+    %5:i32 = call %a, 2i
+    %6:i32 = add %4, %5
+    ret %6
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, BinaryOpUnsequencedRHSThenUnsequencedLHS) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] {
+        auto* rhs = b.Add(ty.i32(), 3_i, 4_i);
+        auto* lhs = b.Add(ty.i32(), 1_i, 2_i);
+        auto* bin = b.Add(ty.i32(), lhs, rhs);
+        b.Return(fn_b, bin);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func():i32 -> %b2 {
+  %b2 = block {
+    %4:i32 = add 3i, 4i
+    %5:i32 = add 1i, 2i
+    %6:i32 = add %5, %4
+    ret %6
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, BinaryOpUnsequencedRHSThenSequencedLHS) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] {
+        auto* rhs = b.Add(ty.i32(), 2_i, 3_i);
+        auto* lhs = b.Call(ty.i32(), fn_a, 1_i);
+        auto* bin = b.Add(ty.i32(), lhs, rhs);
+        b.Return(fn_b, bin);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func():i32 -> %b2 {
+  %b2 = block {
+    %4:i32 = add 2i, 3i
+    %5:i32 = call %a, 1i
+    %6:i32 = add %5, %4
+    ret %6
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, BinaryOpSequencedRHSThenUnsequencedLHS) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] {
+        auto* rhs = b.Call(ty.i32(), fn_a, 3_i);
+        auto* lhs = b.Add(ty.i32(), 1_i, 2_i);
+        auto* bin = b.Add(ty.i32(), lhs, rhs);
+        b.Return(fn_b, bin);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func():i32 -> %b2 {
+  %b2 = block {
+    %4:i32 = call %a, 3i
+    %5:i32 = add 1i, 2i
+    %6:i32 = add %5, %4
+    ret %6
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, BinaryOpSequencedRHSThenSequencedLHS) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] {
+        auto* rhs = b.Call(ty.i32(), fn_a, 2_i);
+        auto* lhs = b.Call(ty.i32(), fn_a, 1_i);
+        auto* bin = b.Add(ty.i32(), lhs, rhs);
+        b.Return(fn_b, bin);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func():i32 -> %b2 {
+  %b2 = block {
+    %4:i32 = call %a, 2i
+    %5:i32 = call %a, 1i
+    %6:i32 = add %5, %4
+    ret %6
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func():i32 -> %b2 {
+  %b2 = block {
+    %4:i32 = call %a, 2i
+    %5:i32 = let %4
+    %6:i32 = call %a, 1i
+    %7:i32 = add %6, %5
+    ret %7
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Call
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(WgslWriter_ValueToLetTest, CallSequencedXYZ) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
+    fn_b->SetParams(
+        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
+
+    auto* fn_c = b.Function("c", ty.i32());
+    b.Append(fn_c->Block(), [&] {
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
+        b.Return(fn_c, call);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 {
+  %b2 = block {
+    ret 0i
+  }
+}
+%c = func():i32 -> %b3 {
+  %b3 = block {
+    %8:i32 = call %a, 1i
+    %9:i32 = call %a, 2i
+    %10:i32 = call %a, 3i
+    %11:i32 = call %b, %8, %9, %10
+    ret %11
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, CallSequencedYXZ) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
+    fn_b->SetParams(
+        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
+
+    auto* fn_c = b.Function("c", ty.i32());
+    b.Append(fn_c->Block(), [&] {
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
+        b.Return(fn_c, call);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 {
+  %b2 = block {
+    ret 0i
+  }
+}
+%c = func():i32 -> %b3 {
+  %b3 = block {
+    %8:i32 = call %a, 2i
+    %9:i32 = call %a, 1i
+    %10:i32 = call %a, 3i
+    %11:i32 = call %b, %9, %8, %10
+    ret %11
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 {
+  %b2 = block {
+    ret 0i
+  }
+}
+%c = func():i32 -> %b3 {
+  %b3 = block {
+    %8:i32 = call %a, 2i
+    %9:i32 = let %8
+    %10:i32 = call %a, 1i
+    %11:i32 = call %a, 3i
+    %12:i32 = call %b, %10, %9, %11
+    ret %12
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, CallSequencedXZY) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
+    fn_b->SetParams(
+        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
+
+    auto* fn_c = b.Function("c", ty.i32());
+    b.Append(fn_c->Block(), [&] {
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
+        b.Return(fn_c, call);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 {
+  %b2 = block {
+    ret 0i
+  }
+}
+%c = func():i32 -> %b3 {
+  %b3 = block {
+    %8:i32 = call %a, 1i
+    %9:i32 = call %a, 3i
+    %10:i32 = call %a, 2i
+    %11:i32 = call %b, %8, %10, %9
+    ret %11
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 {
+  %b2 = block {
+    ret 0i
+  }
+}
+%c = func():i32 -> %b3 {
+  %b3 = block {
+    %8:i32 = call %a, 1i
+    %9:i32 = let %8
+    %10:i32 = call %a, 3i
+    %11:i32 = let %10
+    %12:i32 = call %a, 2i
+    %13:i32 = call %b, %9, %12, %11
+    ret %13
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, CallSequencedZXY) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
+    fn_b->SetParams(
+        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
+
+    auto* fn_c = b.Function("c", ty.i32());
+    b.Append(fn_c->Block(), [&] {
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
+        b.Return(fn_c, call);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 {
+  %b2 = block {
+    ret 0i
+  }
+}
+%c = func():i32 -> %b3 {
+  %b3 = block {
+    %8:i32 = call %a, 3i
+    %9:i32 = call %a, 1i
+    %10:i32 = call %a, 2i
+    %11:i32 = call %b, %9, %10, %8
+    ret %11
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 {
+  %b2 = block {
+    ret 0i
+  }
+}
+%c = func():i32 -> %b3 {
+  %b3 = block {
+    %8:i32 = call %a, 3i
+    %9:i32 = let %8
+    %10:i32 = call %a, 1i
+    %11:i32 = call %a, 2i
+    %12:i32 = call %b, %10, %11, %9
+    ret %12
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, CallSequencedYZX) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
+    fn_b->SetParams(
+        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
+
+    auto* fn_c = b.Function("c", ty.i32());
+    b.Append(fn_c->Block(), [&] {
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
+        b.Return(fn_c, call);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 {
+  %b2 = block {
+    ret 0i
+  }
+}
+%c = func():i32 -> %b3 {
+  %b3 = block {
+    %8:i32 = call %a, 2i
+    %9:i32 = call %a, 3i
+    %10:i32 = call %a, 1i
+    %11:i32 = call %b, %10, %8, %9
+    ret %11
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 {
+  %b2 = block {
+    ret 0i
+  }
+}
+%c = func():i32 -> %b3 {
+  %b3 = block {
+    %8:i32 = call %a, 2i
+    %9:i32 = let %8
+    %10:i32 = call %a, 3i
+    %11:i32 = let %10
+    %12:i32 = call %a, 1i
+    %13:i32 = call %b, %12, %9, %11
+    ret %13
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, CallSequencedZYX) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 0_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn_b = b.Function("b", ty.i32());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, 0_i); });
+    fn_b->SetParams(
+        {b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32()), b.FunctionParam(ty.i32())});
+
+    auto* fn_c = b.Function("c", ty.i32());
+    b.Append(fn_c->Block(), [&] {
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* call = b.Call(ty.i32(), fn_b, x, y, z);
+        b.Return(fn_c, call);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 {
+  %b2 = block {
+    ret 0i
+  }
+}
+%c = func():i32 -> %b3 {
+  %b3 = block {
+    %8:i32 = call %a, 3i
+    %9:i32 = call %a, 2i
+    %10:i32 = call %a, 1i
+    %11:i32 = call %b, %10, %9, %8
+    ret %11
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 0i
+  }
+}
+%b = func(%4:i32, %5:i32, %6:i32):i32 -> %b2 {
+  %b2 = block {
+    ret 0i
+  }
+}
+%c = func():i32 -> %b3 {
+  %b3 = block {
+    %8:i32 = call %a, 3i
+    %9:i32 = let %8
+    %10:i32 = call %a, 2i
+    %11:i32 = let %10
+    %12:i32 = call %a, 1i
+    %13:i32 = call %b, %12, %11, %9
+    ret %13
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenCallVoidFn_ThenUseLoad) {
+    auto* fn_a = b.Function("a", ty.void_());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a); });
+
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* load = b.Load(var);
+        b.Call(ty.void_(), fn_a);
+        b.Return(fn, load);
+    });
+
+    auto* src = R"(
+%a = func():void -> %b1 {
+  %b1 = block {
+    ret
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %3:ptr<function, i32, read_write> = var
+    store %3, 1i
+    %4:i32 = load %3
+    %5:void = call %a
+    ret %4
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func():void -> %b1 {
+  %b1 = block {
+    ret
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %3:ptr<function, i32, read_write> = var
+    store %3, 1i
+    %4:i32 = load %3
+    %5:i32 = let %4
+    %6:void = call %a
+    ret %5
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenCallUnusedi32Fn_ThenUseLoad) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
+
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* load = b.Load(var);
+        b.Call(ty.i32(), fn_a);
+        b.Return(fn, load);
+    });
+
+    auto* src = R"(
+%a = func():i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %3:ptr<function, i32, read_write> = var
+    store %3, 1i
+    %4:i32 = load %3
+    %5:i32 = call %a
+    ret %4
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func():i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %3:ptr<function, i32, read_write> = var
+    store %3, 1i
+    %4:i32 = load %3
+    %5:i32 = let %4
+    %6:i32 = call %a
+    ret %5
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenCalli32Fn_ThenUseLoadBeforeCall) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
+
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* load = b.Load(var);
+        auto* call = b.Call(ty.i32(), fn_a);
+        b.Return(fn, b.Add(ty.i32(), load, call));
+    });
+
+    auto* src = R"(
+%a = func():i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %3:ptr<function, i32, read_write> = var
+    store %3, 1i
+    %4:i32 = load %3
+    %5:i32 = call %a
+    %6:i32 = add %4, %5
+    ret %6
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func():i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %3:ptr<function, i32, read_write> = var
+    store %3, 1i
+    %4:i32 = load %3
+    %5:i32 = call %a
+    %6:i32 = add %4, %5
+    ret %6
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenCalli32Fn_ThenUseCallBeforeLoad) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
+
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* load = b.Load(var);
+        auto* call = b.Call(ty.i32(), fn_a);
+        b.Return(fn, b.Add(ty.i32(), call, load));
+    });
+
+    auto* src = R"(
+%a = func():i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %3:ptr<function, i32, read_write> = var
+    store %3, 1i
+    %4:i32 = load %3
+    %5:i32 = call %a
+    %6:i32 = add %5, %4
+    ret %6
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func():i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %3:ptr<function, i32, read_write> = var
+    store %3, 1i
+    %4:i32 = load %3
+    %5:i32 = let %4
+    %6:i32 = call %a
+    %7:i32 = add %6, %5
+    ret %7
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Access
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfArrayOfArray_XYZ) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* arr = b.Var<function, array<array<array<i32, 3>, 4>, 5>>();
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z);
+        b.Return(fn, b.Load(access));
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var
+    %5:i32 = call %a, 1i
+    %6:i32 = call %a, 2i
+    %7:i32 = call %a, 3i
+    %8:ptr<function, i32, read_write> = access %4, %5, %6, %7
+    %9:i32 = load %8
+    ret %9
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var
+    %5:i32 = call %a, 1i
+    %6:i32 = call %a, 2i
+    %7:i32 = call %a, 3i
+    %8:ptr<function, i32, read_write> = access %4, %5, %6, %7
+    %9:i32 = load %8
+    ret %9
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfArrayOfArray_YXZ) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* arr = b.Var<function, array<array<array<i32, 3>, 4>, 5>>();
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z);
+        b.Return(fn, b.Load(access));
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var
+    %5:i32 = call %a, 2i
+    %6:i32 = call %a, 1i
+    %7:i32 = call %a, 3i
+    %8:ptr<function, i32, read_write> = access %4, %6, %5, %7
+    %9:i32 = load %8
+    ret %9
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var
+    %5:i32 = call %a, 2i
+    %6:i32 = let %5
+    %7:i32 = call %a, 1i
+    %8:i32 = call %a, 3i
+    %9:ptr<function, i32, read_write> = access %4, %7, %6, %8
+    %10:i32 = load %9
+    ret %10
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfArrayOfArray_ZXY) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* arr = b.Var<function, array<array<array<i32, 3>, 4>, 5>>();
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z);
+        b.Return(fn, b.Load(access));
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var
+    %5:i32 = call %a, 3i
+    %6:i32 = call %a, 1i
+    %7:i32 = call %a, 2i
+    %8:ptr<function, i32, read_write> = access %4, %6, %7, %5
+    %9:i32 = load %8
+    ret %9
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var
+    %5:i32 = call %a, 3i
+    %6:i32 = let %5
+    %7:i32 = call %a, 1i
+    %8:i32 = call %a, 2i
+    %9:ptr<function, i32, read_write> = access %4, %7, %8, %6
+    %10:i32 = load %9
+    ret %10
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfArrayOfArray_ZYX) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* arr = b.Var<function, array<array<array<i32, 3>, 4>, 5>>();
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* access = b.Access(ty.ptr<function, i32>(), arr, x, y, z);
+        b.Return(fn, b.Load(access));
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var
+    %5:i32 = call %a, 3i
+    %6:i32 = call %a, 2i
+    %7:i32 = call %a, 1i
+    %8:ptr<function, i32, read_write> = access %4, %7, %6, %5
+    %9:i32 = load %8
+    ret %9
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():i32 -> %b2 {
+  %b2 = block {
+    %4:ptr<function, array<array<array<i32, 3>, 4>, 5>, read_write> = var
+    %5:i32 = call %a, 3i
+    %6:i32 = let %5
+    %7:i32 = call %a, 2i
+    %8:i32 = let %7
+    %9:i32 = call %a, 1i
+    %10:ptr<function, i32, read_write> = access %4, %9, %8, %6
+    %11:i32 = load %10
+    ret %11
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfMat3x4f_XYZ) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn = b.Function("f", ty.f32());
+    b.Append(fn->Block(), [&] {
+        auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>());
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* access = b.Access(ty.f32(), arr, x, y, z);
+        b.Return(fn, access);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():f32 -> %b2 {
+  %b2 = block {
+    %4:array<mat3x4<f32>, 5> = construct
+    %5:i32 = call %a, 1i
+    %6:i32 = call %a, 2i
+    %7:i32 = call %a, 3i
+    %8:f32 = access %4, %5, %6, %7
+    ret %8
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():f32 -> %b2 {
+  %b2 = block {
+    %4:array<mat3x4<f32>, 5> = construct
+    %5:i32 = call %a, 1i
+    %6:i32 = call %a, 2i
+    %7:i32 = call %a, 3i
+    %8:f32 = access %4, %5, %6, %7
+    ret %8
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfMat3x4f_YXZ) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn = b.Function("f", ty.f32());
+    b.Append(fn->Block(), [&] {
+        auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>());
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* access = b.Access(ty.f32(), arr, x, y, z);
+        b.Return(fn, access);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():f32 -> %b2 {
+  %b2 = block {
+    %4:array<mat3x4<f32>, 5> = construct
+    %5:i32 = call %a, 2i
+    %6:i32 = call %a, 1i
+    %7:i32 = call %a, 3i
+    %8:f32 = access %4, %6, %5, %7
+    ret %8
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():f32 -> %b2 {
+  %b2 = block {
+    %4:array<mat3x4<f32>, 5> = construct
+    %5:i32 = call %a, 2i
+    %6:i32 = let %5
+    %7:i32 = call %a, 1i
+    %8:i32 = call %a, 3i
+    %9:f32 = access %4, %7, %6, %8
+    ret %9
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfMat3x4f_ZXY) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn = b.Function("f", ty.f32());
+    b.Append(fn->Block(), [&] {
+        auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>());
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* access = b.Access(ty.f32(), arr, x, y, z);
+        b.Return(fn, access);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():f32 -> %b2 {
+  %b2 = block {
+    %4:array<mat3x4<f32>, 5> = construct
+    %5:i32 = call %a, 3i
+    %6:i32 = call %a, 1i
+    %7:i32 = call %a, 2i
+    %8:f32 = access %4, %6, %7, %5
+    ret %8
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():f32 -> %b2 {
+  %b2 = block {
+    %4:array<mat3x4<f32>, 5> = construct
+    %5:i32 = call %a, 3i
+    %6:i32 = let %5
+    %7:i32 = call %a, 1i
+    %8:i32 = call %a, 2i
+    %9:f32 = access %4, %7, %8, %6
+    ret %9
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, Access_ArrayOfMat3x4f_ZYX) {
+    auto* fn_a = b.Function("a", ty.i32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 1_i); });
+    fn_a->SetParams({b.FunctionParam(ty.i32())});
+
+    auto* fn = b.Function("f", ty.f32());
+    b.Append(fn->Block(), [&] {
+        auto* arr = b.Construct(ty.array<mat3x4<f32>, 5>());
+        auto* z = b.Call(ty.i32(), fn_a, 3_i);
+        auto* y = b.Call(ty.i32(), fn_a, 2_i);
+        auto* x = b.Call(ty.i32(), fn_a, 1_i);
+        auto* access = b.Access(ty.f32(), arr, x, y, z);
+        b.Return(fn, access);
+    });
+
+    auto* src = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():f32 -> %b2 {
+  %b2 = block {
+    %4:array<mat3x4<f32>, 5> = construct
+    %5:i32 = call %a, 3i
+    %6:i32 = call %a, 2i
+    %7:i32 = call %a, 1i
+    %8:f32 = access %4, %7, %6, %5
+    ret %8
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%a = func(%2:i32):i32 -> %b1 {
+  %b1 = block {
+    ret 1i
+  }
+}
+%f = func():f32 -> %b2 {
+  %b2 = block {
+    %4:array<mat3x4<f32>, 5> = construct
+    %5:i32 = call %a, 3i
+    %6:i32 = let %5
+    %7:i32 = call %a, 2i
+    %8:i32 = let %7
+    %9:i32 = call %a, 1i
+    %10:f32 = access %4, %9, %8, %6
+    ret %10
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// If
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(WgslWriter_ValueToLetTest, UnsequencedOutsideIf) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* v = b.Add(ty.i32(), 1_i, 2_i);
+        auto* if_ = b.If(true);
+        b.Append(if_->True(), [&] { b.Return(fn, v); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:i32 = add 1i, 2i
+    if true [t: %b2] {  # if_1
+      %b2 = block {  # true
+        ret %2
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, SequencedOutsideIf) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        var->SetInitializer(b.Constant(1_i));
+        auto* v_1 = b.Load(var);
+        auto* v_2 = b.Add(ty.i32(), v_1, 2_i);
+        auto* if_ = b.If(true);
+        b.Append(if_->True(), [&] { b.Return(fn, v_2); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var, 1i
+    %3:i32 = load %2
+    %4:i32 = add %3, 2i
+    if true [t: %b2] {  # if_1
+      %b2 = block {  # true
+        ret %4
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var, 1i
+    %3:i32 = load %2
+    %4:i32 = add %3, 2i
+    %5:i32 = let %4
+    if true [t: %b2] {  # if_1
+      %b2 = block {  # true
+        ret %5
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, UnsequencedUsedByIfCondition) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* v = b.Equal(ty.bool_(), 1_i, 2_i);
+        auto* if_ = b.If(v);
+        b.Append(if_->True(), [&] { b.Return(fn, 3_i); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:bool = eq 1i, 2i
+    if %2 [t: %b2] {  # if_1
+      %b2 = block {  # true
+        ret 3i
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:bool = eq 1i, 2i
+    if %2 [t: %b2] {  # if_1
+      %b2 = block {  # true
+        ret 3i
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, SequencedUsedByIfCondition) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        var->SetInitializer(b.Constant(1_i));
+        auto* v_1 = b.Load(var);
+        auto* v_2 = b.Equal(ty.bool_(), v_1, 2_i);
+        auto* if_ = b.If(v_2);
+        b.Append(if_->True(), [&] { b.Return(fn, 3_i); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var, 1i
+    %3:i32 = load %2
+    %4:bool = eq %3, 2i
+    if %4 [t: %b2] {  # if_1
+      %b2 = block {  # true
+        ret 3i
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var, 1i
+    %3:i32 = load %2
+    %4:bool = eq %3, 2i
+    if %4 [t: %b2] {  # if_1
+      %b2 = block {  # true
+        ret 3i
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenWriteToVarInIf_ThenUseLoad) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* load = b.Load(var);
+        auto* if_ = b.If(true);
+        b.Append(if_->True(), [&] {
+            b.Store(var, 2_i);
+            b.ExitIf(if_);
+        });
+        b.Return(fn, load);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    if true [t: %b2] {  # if_1
+      %b2 = block {  # true
+        store %2, 2i
+        exit_if  # if_1
+      }
+    }
+    ret %3
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    %4:i32 = let %3
+    if true [t: %b2] {  # if_1
+      %b2 = block {  # true
+        store %2, 2i
+        exit_if  # if_1
+      }
+    }
+    ret %4
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Switch
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(WgslWriter_ValueToLetTest, UnsequencedOutsideSwitch) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* v = b.Add(ty.i32(), 1_i, 2_i);
+        auto* switch_ = b.Switch(3_i);
+        auto* case_ = b.DefaultCase(switch_);
+        b.Append(case_, [&] { b.Return(fn, v); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:i32 = add 1i, 2i
+    switch 3i [c: (default, %b2)] {  # switch_1
+      %b2 = block {  # case
+        ret %2
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, SequencedOutsideSwitch) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        var->SetInitializer(b.Constant(1_i));
+        auto* v_1 = b.Load(var);
+        auto* v_2 = b.Add(ty.i32(), v_1, 2_i);
+        auto* switch_ = b.Switch(3_i);
+        auto* case_ = b.DefaultCase(switch_);
+        b.Append(case_, [&] { b.Return(fn, v_2); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var, 1i
+    %3:i32 = load %2
+    %4:i32 = add %3, 2i
+    switch 3i [c: (default, %b2)] {  # switch_1
+      %b2 = block {  # case
+        ret %4
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var, 1i
+    %3:i32 = load %2
+    %4:i32 = add %3, 2i
+    %5:i32 = let %4
+    switch 3i [c: (default, %b2)] {  # switch_1
+      %b2 = block {  # case
+        ret %5
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, UnsequencedUsedBySwitchCondition) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* v = b.Add(ty.i32(), 1_i, 2_i);
+        auto* switch_ = b.Switch(v);
+        auto* case_ = b.DefaultCase(switch_);
+        b.Append(case_, [&] { b.Return(fn, 3_i); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:i32 = add 1i, 2i
+    switch %2 [c: (default, %b2)] {  # switch_1
+      %b2 = block {  # case
+        ret 3i
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:i32 = add 1i, 2i
+    switch %2 [c: (default, %b2)] {  # switch_1
+      %b2 = block {  # case
+        ret 3i
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, SequencedUsedBySwitchCondition) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        var->SetInitializer(b.Constant(1_i));
+        auto* v_1 = b.Load(var);
+        auto* switch_ = b.Switch(v_1);
+        auto* case_ = b.DefaultCase(switch_);
+        b.Append(case_, [&] { b.Return(fn, 3_i); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var, 1i
+    %3:i32 = load %2
+    switch %3 [c: (default, %b2)] {  # switch_1
+      %b2 = block {  # case
+        ret 3i
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var, 1i
+    %3:i32 = load %2
+    switch %3 [c: (default, %b2)] {  # switch_1
+      %b2 = block {  # case
+        ret 3i
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenWriteToVarInSwitch_ThenUseLoad) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* load = b.Load(var);
+        auto* switch_ = b.Switch(1_i);
+        auto* case_ = b.DefaultCase(switch_);
+        b.Append(case_, [&] {
+            b.Store(var, 2_i);
+            b.ExitSwitch(switch_);
+        });
+        b.Return(fn, load);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    switch 1i [c: (default, %b2)] {  # switch_1
+      %b2 = block {  # case
+        store %2, 2i
+        exit_switch  # switch_1
+      }
+    }
+    ret %3
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    %4:i32 = let %3
+    switch 1i [c: (default, %b2)] {  # switch_1
+      %b2 = block {  # case
+        store %2, 2i
+        exit_switch  # switch_1
+      }
+    }
+    ret %4
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Loop
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(WgslWriter_ValueToLetTest, UnsequencedOutsideLoopInitializer) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        auto* v = b.Add(ty.i32(), 1_i, 2_i);
+        auto* loop = b.Loop();
+        b.Append(loop->Initializer(), [&] {
+            b.Store(var, v);
+            b.NextIteration(loop);
+        });
+        b.Append(loop->Body(), [&] { b.ExitLoop(loop); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    %3:i32 = add 1i, 2i
+    loop [i: %b2, b: %b3] {  # loop_1
+      %b2 = block {  # initializer
+        store %2, %3
+        next_iteration %b3
+      }
+      %b3 = block {  # body
+        exit_loop  # loop_1
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, SequencedOutsideLoopInitializer) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        auto* v_1 = b.Load(var);
+        auto* v_2 = b.Add(ty.i32(), v_1, 2_i);
+        auto* loop = b.Loop();
+        b.Append(loop->Initializer(), [&] {
+            b.Store(var, v_2);
+            b.NextIteration(loop);
+        });
+        b.Append(loop->Body(), [&] { b.ExitLoop(loop); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    %3:i32 = load %2
+    %4:i32 = add %3, 2i
+    loop [i: %b2, b: %b3] {  # loop_1
+      %b2 = block {  # initializer
+        store %2, %4
+        next_iteration %b3
+      }
+      %b3 = block {  # body
+        exit_loop  # loop_1
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    %3:i32 = load %2
+    %4:i32 = add %3, 2i
+    %5:i32 = let %4
+    loop [i: %b2, b: %b3] {  # loop_1
+      %b2 = block {  # initializer
+        store %2, %5
+        next_iteration %b3
+      }
+      %b3 = block {  # body
+        exit_loop  # loop_1
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenWriteToVarInLoopInitializer_ThenUseLoad) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* load = b.Load(var);
+        auto* loop = b.Loop();
+        b.Append(loop->Initializer(), [&] {
+            b.Store(var, 2_i);
+            b.NextIteration(loop);
+        });
+        b.Append(loop->Body(), [&] { b.ExitLoop(loop); });
+        b.Return(fn, load);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    loop [i: %b2, b: %b3] {  # loop_1
+      %b2 = block {  # initializer
+        store %2, 2i
+        next_iteration %b3
+      }
+      %b3 = block {  # body
+        exit_loop  # loop_1
+      }
+    }
+    ret %3
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    %4:i32 = let %3
+    loop [i: %b2, b: %b3] {  # loop_1
+      %b2 = block {  # initializer
+        store %2, 2i
+        next_iteration %b3
+      }
+      %b3 = block {  # body
+        exit_loop  # loop_1
+      }
+    }
+    ret %4
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, UnsequencedOutsideLoopBody) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* v = b.Add(ty.i32(), 1_i, 2_i);
+        auto* loop = b.Loop();
+        b.Append(loop->Body(), [&] { b.Return(fn, v); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:i32 = add 1i, 2i
+    loop [b: %b2] {  # loop_1
+      %b2 = block {  # body
+        ret %2
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, SequencedOutsideLoopBody) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        auto* v_1 = b.Load(var);
+        auto* v_2 = b.Add(ty.i32(), v_1, 2_i);
+        auto* loop = b.Loop();
+        b.Append(loop->Body(), [&] { b.Return(fn, v_2); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    %3:i32 = load %2
+    %4:i32 = add %3, 2i
+    loop [b: %b2] {  # loop_1
+      %b2 = block {  # body
+        ret %4
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    %3:i32 = load %2
+    %4:i32 = add %3, 2i
+    %5:i32 = let %4
+    loop [b: %b2] {  # loop_1
+      %b2 = block {  # body
+        ret %5
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenWriteToVarInLoopBody_ThenUseLoad) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* load = b.Load(var);
+        auto* loop = b.Loop();
+        b.Append(loop->Body(), [&] {
+            b.Store(var, 2_i);
+            b.ExitLoop(loop);
+        });
+        b.Return(fn, load);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    loop [b: %b2] {  # loop_1
+      %b2 = block {  # body
+        store %2, 2i
+        exit_loop  # loop_1
+      }
+    }
+    ret %3
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    %4:i32 = let %3
+    loop [b: %b2] {  # loop_1
+      %b2 = block {  # body
+        store %2, 2i
+        exit_loop  # loop_1
+      }
+    }
+    ret %4
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, UnsequencedOutsideLoopContinuing) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* v = b.Add(ty.i32(), 1_i, 2_i);
+        auto* loop = b.Loop();
+        b.Append(loop->Body(), [&] { b.Continue(loop); });
+        b.Append(loop->Continuing(), [&] { b.BreakIf(loop, b.Equal(ty.bool_(), v, 3_i)); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:i32 = add 1i, 2i
+    loop [b: %b2, c: %b3] {  # loop_1
+      %b2 = block {  # body
+        continue %b3
+      }
+      %b3 = block {  # continuing
+        %3:bool = eq %2, 3i
+        break_if %3 %b2
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, SequencedOutsideLoopContinuing) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        auto* v_1 = b.Load(var);
+        auto* v_2 = b.Add(ty.i32(), v_1, 2_i);
+        auto* loop = b.Loop();
+        b.Append(loop->Body(), [&] { b.Continue(loop); });
+        b.Append(loop->Continuing(), [&] { b.BreakIf(loop, b.Equal(ty.bool_(), v_2, 3_i)); });
+        b.Return(fn, 0_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    %3:i32 = load %2
+    %4:i32 = add %3, 2i
+    loop [b: %b2, c: %b3] {  # loop_1
+      %b2 = block {  # body
+        continue %b3
+      }
+      %b3 = block {  # continuing
+        %5:bool = eq %4, 3i
+        break_if %5 %b2
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    Run(ValueToLet);
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    %3:i32 = load %2
+    %4:i32 = add %3, 2i
+    %5:i32 = let %4
+    loop [b: %b2, c: %b3] {  # loop_1
+      %b2 = block {  # body
+        continue %b3
+      }
+      %b3 = block {  # continuing
+        %6:bool = eq %5, 3i
+        break_if %6 %b2
+      }
+    }
+    ret 0i
+  }
+}
+)";
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVar_ThenWriteToVarInLoopContinuing_ThenUseLoad) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* load = b.Load(var);
+        auto* loop = b.Loop();
+        b.Append(loop->Body(), [&] { b.Continue(loop); });
+        b.Append(loop->Continuing(), [&] {
+            b.Store(var, 2_i);
+            b.BreakIf(loop, true);
+        });
+        b.Return(fn, load);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    loop [b: %b2, c: %b3] {  # loop_1
+      %b2 = block {  # body
+        continue %b3
+      }
+      %b3 = block {  # continuing
+        store %2, 2i
+        break_if true %b2
+      }
+    }
+    ret %3
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    %3:i32 = load %2
+    %4:i32 = let %3
+    loop [b: %b2, c: %b3] {  # loop_1
+      %b2 = block {  # body
+        continue %b3
+      }
+      %b3 = block {  # continuing
+        store %2, 2i
+        break_if true %b2
+      }
+    }
+    ret %4
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVarInLoopInitializer_ThenReadAndWriteToVarInLoopBody) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* loop = b.Loop();
+        b.Append(loop->Initializer(), [&] {
+            auto* load = b.Load(var);
+            b.NextIteration(loop);
+            b.Append(loop->Body(), [&] {
+                b.Store(var, b.Add(ty.i32(), load, 1_i));
+                b.ExitLoop(loop);
+            });
+        });
+        b.Return(fn, 3_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    loop [i: %b2, b: %b3] {  # loop_1
+      %b2 = block {  # initializer
+        %3:i32 = load %2
+        next_iteration %b3
+      }
+      %b3 = block {  # body
+        %4:i32 = add %3, 1i
+        store %2, %4
+        exit_loop  # loop_1
+      }
+    }
+    ret 3i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    loop [i: %b2, b: %b3] {  # loop_1
+      %b2 = block {  # initializer
+        %3:i32 = load %2
+        %4:i32 = let %3
+        next_iteration %b3
+      }
+      %b3 = block {  # body
+        %5:i32 = add %4, 1i
+        store %2, %5
+        exit_loop  # loop_1
+      }
+    }
+    ret 3i
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVarInLoopInitializer_ThenReadAndWriteToVarInLoopContinuing) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* loop = b.Loop();
+        b.Append(loop->Initializer(), [&] {
+            auto* load = b.Load(var);
+            b.NextIteration(loop);
+            b.Append(loop->Body(), [&] { b.Continue(loop); });
+            b.Append(loop->Continuing(), [&] {
+                b.Store(var, b.Add(ty.i32(), load, 1_i));
+                b.BreakIf(loop, true);
+            });
+        });
+        b.Return(fn, 3_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    loop [i: %b2, b: %b3, c: %b4] {  # loop_1
+      %b2 = block {  # initializer
+        %3:i32 = load %2
+        next_iteration %b3
+      }
+      %b3 = block {  # body
+        continue %b4
+      }
+      %b4 = block {  # continuing
+        %4:i32 = add %3, 1i
+        store %2, %4
+        break_if true %b3
+      }
+    }
+    ret 3i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    loop [i: %b2, b: %b3, c: %b4] {  # loop_1
+      %b2 = block {  # initializer
+        %3:i32 = load %2
+        %4:i32 = let %3
+        next_iteration %b3
+      }
+      %b3 = block {  # body
+        continue %b4
+      }
+      %b4 = block {  # continuing
+        %5:i32 = add %4, 1i
+        store %2, %5
+        break_if true %b3
+      }
+    }
+    ret 3i
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(WgslWriter_ValueToLetTest, LoadVarInLoopBody_ThenReadAndWriteToVarInLoopContinuing) {
+    auto* fn = b.Function("f", ty.i32());
+    b.Append(fn->Block(), [&] {
+        auto* var = b.Var<function, i32>();
+        b.Store(var, 1_i);
+        auto* loop = b.Loop();
+        b.Append(loop->Body(), [&] {
+            auto* load = b.Load(var);
+            b.Continue(loop);
+
+            b.Append(loop->Continuing(), [&] {
+                b.Store(var, b.Add(ty.i32(), load, 1_i));
+                b.BreakIf(loop, true);
+            });
+        });
+        b.Return(fn, 3_i);
+    });
+
+    auto* src = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    loop [b: %b2, c: %b3] {  # loop_1
+      %b2 = block {  # body
+        %3:i32 = load %2
+        continue %b3
+      }
+      %b3 = block {  # continuing
+        %4:i32 = add %3, 1i
+        store %2, %4
+        break_if true %b2
+      }
+    }
+    ret 3i
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():i32 -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    store %2, 1i
+    loop [b: %b2, c: %b3] {  # loop_1
+      %b2 = block {  # body
+        %3:i32 = load %2
+        %4:i32 = let %3
+        continue %b3
+      }
+      %b3 = block {  # continuing
+        %5:i32 = add %4, 1i
+        store %2, %5
+        break_if true %b2
+      }
+    }
+    ret 3i
+  }
+}
+)";
+
+    Run(ValueToLet);
+
+    EXPECT_EQ(expect, str());
+}
+
+}  // namespace
+}  // namespace tint::wgsl::writer::raise
diff --git a/src/tint/lang/wgsl/writer/writer_test.cc b/src/tint/lang/wgsl/writer/writer_test.cc
new file mode 100644
index 0000000..d01d1df
--- /dev/null
+++ b/src/tint/lang/wgsl/writer/writer_test.cc
@@ -0,0 +1,1023 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/wgsl/writer/writer.h"
+
+#include <ostream>
+#include <string>
+#include <string_view>
+
+#include "gtest/gtest.h"
+#include "src/tint/lang/core/ir/disassembler.h"
+#include "src/tint/lang/core/ir/ir_helper_test.h"
+#include "src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h"
+#include "src/tint/lang/wgsl/writer/ir_to_program/program_options.h"
+#include "src/tint/lang/wgsl/writer/raise/raise.h"
+#include "src/tint/utils/result/result.h"
+#include "src/tint/utils/text/string.h"
+
+namespace tint::wgsl::writer {
+namespace {
+
+/// Class used for IR to Program tests
+class WgslIRWriterTest : public core::ir::IRTestHelper {
+  public:
+    struct Result {
+        /// The resulting WGSL
+        std::string wgsl;
+        /// The resulting AST
+        std::string ast;
+        /// The resulting IR before raising
+        std::string ir_pre_raise;
+        /// The resulting IR after raising
+        std::string ir_post_raise;
+        /// The resulting error
+        std::string err;
+        /// The expected WGSL
+        std::string expected;
+    };
+
+    /// @returns the WGSL generated from the IR
+    Result Run(std::string_view expected_wgsl) {
+        Result result;
+
+        result.ir_pre_raise = core::ir::Disassemble(mod);
+
+        if (auto res = tint::wgsl::writer::Raise(mod); res != Success) {
+            result.err = res.Failure().reason.Str();
+            return result;
+        }
+
+        result.ir_post_raise = core::ir::Disassemble(mod);
+
+        writer::ProgramOptions program_options;
+        program_options.allowed_features = AllowedFeatures::Everything();
+        auto output_program = wgsl::writer::IRToProgram(mod, program_options);
+        if (!output_program.IsValid()) {
+            result.err = output_program.Diagnostics().Str();
+            result.ast = Program::printer(output_program);
+            return result;
+        }
+
+        auto output = wgsl::writer::Generate(output_program, {});
+        if (output != Success) {
+            std::stringstream ss;
+            ss << "wgsl::Generate() errored: " << output.Failure();
+            result.err = ss.str();
+            result.ast = Program::printer(output_program);
+            return result;
+        }
+
+        result.expected = tint::TrimSpace(expected_wgsl);
+        if (!result.expected.empty()) {
+            result.expected = "\n" + result.expected + "\n";
+        }
+
+        result.wgsl = std::string(tint::TrimSpace(output->wgsl));
+        if (!result.wgsl.empty()) {
+            result.wgsl = "\n" + result.wgsl + "\n";
+        }
+
+        return result;
+    }
+};
+
+std::ostream& operator<<(std::ostream& o, const WgslIRWriterTest::Result& res) {
+    if (!res.err.empty()) {
+        o << "============================" << std::endl
+          << "== Error                  ==" << std::endl
+          << "============================" << std::endl
+          << res.err << std::endl
+          << std::endl;
+    }
+    if (!res.ir_pre_raise.empty()) {
+        o << "============================" << std::endl
+          << "== IR (pre-raise)         ==" << std::endl
+          << "============================" << std::endl
+          << res.ir_pre_raise << std::endl
+          << std::endl;
+    }
+    if (!res.ir_post_raise.empty()) {
+        o << "============================" << std::endl
+          << "== IR (post-raise)        ==" << std::endl
+          << "============================" << std::endl
+          << res.ir_post_raise << std::endl
+          << std::endl;
+    }
+    if (!res.ast.empty()) {
+        o << "============================" << std::endl
+          << "== AST                    ==" << std::endl
+          << "============================" << std::endl
+          << res.ast << std::endl
+          << std::endl;
+    }
+    return o;
+}
+
+#define RUN_TEST(EXPECTED)                               \
+    do {                                                 \
+        if (auto res = Run(EXPECTED); res.err.empty()) { \
+            EXPECT_EQ(res.expected, res.wgsl) << res;    \
+        } else {                                         \
+            FAIL() << res;                               \
+        }                                                \
+    } while (false)
+
+////////////////////////////////////////////////////////////////////////////////
+// Short-circuiting binary ops
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(WgslIRWriterTest, ShortCircuit_And_Param_2) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    fn->SetParams({pa, pb});
+
+    b.Append(fn->Block(), [&] {
+        auto* if_ = b.If(pa);
+        if_->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if_->True(), [&] { b.ExitIf(if_, pb); });
+        b.Append(if_->False(), [&] { b.ExitIf(if_, false); });
+
+        b.Return(fn, if_);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool) -> bool {
+  return (a && b);
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_And_Param_3_ab_c) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    auto* pc = b.FunctionParam("c", ty.bool_());
+    fn->SetParams({pa, pb, pc});
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(pa);
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, pb); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
+
+        auto* if2 = b.If(if1);
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, pc); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
+
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool, c : bool) -> bool {
+  return ((a && b) && c);
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_And_Param_3_a_bc) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    auto* pc = b.FunctionParam("c", ty.bool_());
+    fn->SetParams({pa, pb, pc});
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(pa);
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] {
+            auto* if2 = b.If(pb);
+            if2->SetResults(b.InstructionResult(ty.bool_()));
+            b.Append(if2->True(), [&] { b.ExitIf(if2, pc); });
+            b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
+
+            b.ExitIf(if1, if2);
+        });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
+        b.Return(fn, if1);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool, c : bool) -> bool {
+  return (a && (b && c));
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_And_Let_2) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    fn->SetParams({pa, pb});
+
+    b.Append(fn->Block(), [&] {
+        auto* if_ = b.If(pa);
+        if_->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if_->True(), [&] { b.ExitIf(if_, pb); });
+        b.Append(if_->False(), [&] { b.ExitIf(if_, false); });
+
+        mod.SetName(if_, "l");
+        b.Return(fn, if_);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool) -> bool {
+  let l = (a && b);
+  return l;
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_And_Let_3_ab_c) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    auto* pc = b.FunctionParam("c", ty.bool_());
+    fn->SetParams({pa, pb, pc});
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(pa);
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, pb); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
+
+        auto* if2 = b.If(if1);
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, pc); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
+
+        mod.SetName(if2, "l");
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool, c : bool) -> bool {
+  let l = ((a && b) && c);
+  return l;
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_And_Let_3_a_bc) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    auto* pc = b.FunctionParam("c", ty.bool_());
+    fn->SetParams({pa, pb, pc});
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(pa);
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] {
+            auto* if2 = b.If(pb);
+            if2->SetResults(b.InstructionResult(ty.bool_()));
+            b.Append(if2->True(), [&] { b.ExitIf(if2, pc); });
+            b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
+
+            b.ExitIf(if1, if2);
+        });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
+
+        mod.SetName(if1, "l");
+        b.Return(fn, if1);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool, c : bool) -> bool {
+  let l = (a && (b && c));
+  return l;
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_And_Call_2) {
+    auto* fn_a = b.Function("a", ty.bool_());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
+
+    auto* fn_b = b.Function("b", ty.bool_());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
+
+    auto* fn = b.Function("f", ty.bool_());
+
+    b.Append(fn->Block(), [&] {
+        auto* if_ = b.If(b.Call(ty.bool_(), fn_a));
+        if_->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if_->True(), [&] { b.ExitIf(if_, b.Call(ty.bool_(), fn_b)); });
+        b.Append(if_->False(), [&] { b.ExitIf(if_, false); });
+
+        b.Return(fn, if_);
+    });
+
+    RUN_TEST(R"(
+fn a() -> bool {
+  return true;
+}
+
+fn b() -> bool {
+  return true;
+}
+
+fn f() -> bool {
+  return (a() && b());
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_And_Call_3_ab_c) {
+    auto* fn_a = b.Function("a", ty.bool_());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
+
+    auto* fn_b = b.Function("b", ty.bool_());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
+
+    auto* fn_c = b.Function("c", ty.bool_());
+    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
+
+    auto* fn = b.Function("f", ty.bool_());
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(b.Call(ty.bool_(), fn_a));
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, b.Call(ty.bool_(), fn_b)); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
+
+        auto* if2 = b.If(if1);
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, b.Call(ty.bool_(), fn_c)); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
+
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn a() -> bool {
+  return true;
+}
+
+fn b() -> bool {
+  return true;
+}
+
+fn c() -> bool {
+  return true;
+}
+
+fn f() -> bool {
+  return ((a() && b()) && c());
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_And_Call_3_a_bc) {
+    auto* fn_a = b.Function("a", ty.bool_());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
+
+    auto* fn_b = b.Function("b", ty.bool_());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
+
+    auto* fn_c = b.Function("c", ty.bool_());
+    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
+
+    auto* fn = b.Function("f", ty.bool_());
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(b.Call(ty.bool_(), fn_a));
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] {
+            auto* if2 = b.If(b.Call(ty.bool_(), fn_b));
+            if2->SetResults(b.InstructionResult(ty.bool_()));
+            b.Append(if2->True(), [&] { b.ExitIf(if2, b.Call(ty.bool_(), fn_c)); });
+            b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
+
+            b.ExitIf(if1, if2);
+        });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
+
+        b.Return(fn, if1);
+    });
+
+    RUN_TEST(R"(
+fn a() -> bool {
+  return true;
+}
+
+fn b() -> bool {
+  return true;
+}
+
+fn c() -> bool {
+  return true;
+}
+
+fn f() -> bool {
+  return (a() && (b() && c()));
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_Param_2) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    fn->SetParams({pa, pb});
+
+    b.Append(fn->Block(), [&] {
+        auto* if_ = b.If(pa);
+        if_->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if_->True(), [&] { b.ExitIf(if_, true); });
+        b.Append(if_->False(), [&] { b.ExitIf(if_, pb); });
+
+        b.Return(fn, if_);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool) -> bool {
+  return (a || b);
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_Param_3_ab_c) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    auto* pc = b.FunctionParam("c", ty.bool_());
+    fn->SetParams({pa, pb, pc});
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(pa);
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, pb); });
+
+        auto* if2 = b.If(if1);
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, pc); });
+
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool, c : bool) -> bool {
+  return ((a || b) || c);
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_Param_3_a_bc) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    auto* pc = b.FunctionParam("c", ty.bool_());
+    fn->SetParams({pa, pb, pc});
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(pa);
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
+        b.Append(if1->False(), [&] {
+            auto* if2 = b.If(pb);
+            if2->SetResults(b.InstructionResult(ty.bool_()));
+            b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
+            b.Append(if2->False(), [&] { b.ExitIf(if2, pc); });
+
+            b.ExitIf(if1, if2);
+        });
+
+        b.Return(fn, if1);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool, c : bool) -> bool {
+  return (a || (b || c));
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_Let_2) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    fn->SetParams({pa, pb});
+
+    b.Append(fn->Block(), [&] {
+        auto* if_ = b.If(pa);
+        if_->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if_->True(), [&] { b.ExitIf(if_, true); });
+        b.Append(if_->False(), [&] { b.ExitIf(if_, pb); });
+
+        mod.SetName(if_, "l");
+        b.Return(fn, if_);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool) -> bool {
+  let l = (a || b);
+  return l;
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_Let_3_ab_c) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    auto* pc = b.FunctionParam("c", ty.bool_());
+    fn->SetParams({pa, pb, pc});
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(pa);
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, pb); });
+
+        auto* if2 = b.If(if1);
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, pc); });
+
+        mod.SetName(if2, "l");
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool, c : bool) -> bool {
+  let l = ((a || b) || c);
+  return l;
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_Let_3_a_bc) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pb = b.FunctionParam("b", ty.bool_());
+    auto* pc = b.FunctionParam("c", ty.bool_());
+    fn->SetParams({pa, pb, pc});
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(pa);
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
+        b.Append(if1->False(), [&] {
+            auto* if2 = b.If(pb);
+            if2->SetResults(b.InstructionResult(ty.bool_()));
+            b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
+            b.Append(if2->False(), [&] { b.ExitIf(if2, pc); });
+
+            b.ExitIf(if1, if2);
+        });
+
+        mod.SetName(if1, "l");
+        b.Return(fn, if1);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool, c : bool) -> bool {
+  let l = (a || (b || c));
+  return l;
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_Call_2) {
+    auto* fn_a = b.Function("a", ty.bool_());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
+
+    auto* fn_b = b.Function("b", ty.bool_());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
+
+    auto* fn = b.Function("f", ty.bool_());
+
+    b.Append(fn->Block(), [&] {
+        auto* if_ = b.If(b.Call(ty.bool_(), fn_a));
+        if_->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if_->True(), [&] { b.ExitIf(if_, true); });
+        b.Append(if_->False(), [&] { b.ExitIf(if_, b.Call(ty.bool_(), fn_b)); });
+
+        b.Return(fn, if_);
+    });
+
+    RUN_TEST(R"(
+fn a() -> bool {
+  return true;
+}
+
+fn b() -> bool {
+  return true;
+}
+
+fn f() -> bool {
+  return (a() || b());
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_Call_3_ab_c) {
+    auto* fn_a = b.Function("a", ty.bool_());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
+
+    auto* fn_b = b.Function("b", ty.bool_());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
+
+    auto* fn_c = b.Function("c", ty.bool_());
+    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
+
+    auto* fn = b.Function("f", ty.bool_());
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(b.Call(ty.bool_(), fn_a));
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, b.Call(ty.bool_(), fn_b)); });
+
+        auto* if2 = b.If(if1);
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, b.Call(ty.bool_(), fn_c)); });
+
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn a() -> bool {
+  return true;
+}
+
+fn b() -> bool {
+  return true;
+}
+
+fn c() -> bool {
+  return true;
+}
+
+fn f() -> bool {
+  return ((a() || b()) || c());
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_Call_3_a_bc) {
+    auto* fn_a = b.Function("a", ty.bool_());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
+
+    auto* fn_b = b.Function("b", ty.bool_());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
+
+    auto* fn_c = b.Function("c", ty.bool_());
+    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
+
+    auto* fn = b.Function("f", ty.bool_());
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(b.Call(ty.bool_(), fn_a));
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
+        b.Append(if1->False(), [&] {
+            auto* if2 = b.If(b.Call(ty.bool_(), fn_b));
+            if2->SetResults(b.InstructionResult(ty.bool_()));
+            b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
+            b.Append(if2->False(), [&] { b.ExitIf(if2, b.Call(ty.bool_(), fn_c)); });
+
+            b.ExitIf(if1, if2);
+        });
+
+        b.Return(fn, if1);
+    });
+
+    RUN_TEST(R"(
+fn a() -> bool {
+  return true;
+}
+
+fn b() -> bool {
+  return true;
+}
+
+fn c() -> bool {
+  return true;
+}
+
+fn f() -> bool {
+  return (a() || (b() || c()));
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Mixed) {
+    auto* fn_b = b.Function("b", ty.bool_());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
+
+    auto* fn_d = b.Function("d", ty.bool_());
+    b.Append(fn_d->Block(), [&] { b.Return(fn_d, true); });
+
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam("a", ty.bool_());
+    auto* pc = b.FunctionParam("c", ty.bool_());
+    fn->SetParams({pa, pc});
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(pa);
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, b.Call(ty.bool_(), fn_b)); });
+
+        auto* if2 = b.If(if1);
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] {
+            auto* if3 = b.If(pc);
+            if3->SetResults(b.InstructionResult(ty.bool_()));
+            b.Append(if3->True(), [&] { b.ExitIf(if3, true); });
+            b.Append(if3->False(), [&] { b.ExitIf(if3, b.Call(ty.bool_(), fn_d)); });
+
+            b.ExitIf(if2, if3);
+        });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
+
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn b() -> bool {
+  return true;
+}
+
+fn d() -> bool {
+  return true;
+}
+
+fn f(a : bool, c : bool) -> bool {
+  return ((a || b()) && (c || d()));
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_And_ParamCallParam_a_bc_EarlyEval) {
+    auto* fn_b = b.Function("b", ty.bool_());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
+
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam(ty.bool_());
+    auto* pc = b.FunctionParam(ty.bool_());
+    mod.SetName(pa, "a");
+    mod.SetName(pc, "c");
+    fn->SetParams({pa, pc});
+
+    b.Append(fn->Block(), [&] {
+        // 'b() && c' is evaluated before 'a'.
+        auto* if1 = b.If(b.Call(ty.bool_(), fn_b));
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, pc); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
+
+        auto* if2 = b.If(pa);
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, if1); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn b() -> bool {
+  return true;
+}
+
+fn f(a : bool, c : bool) -> bool {
+  let v = (b() && c);
+  return (a && v);
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_And_Call_3_a_bc_EarlyEval) {
+    auto* fn_a = b.Function("a", ty.bool_());
+
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
+
+    auto* fn_b = b.Function("b", ty.bool_());
+
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
+
+    auto* fn_c = b.Function("c", ty.bool_());
+
+    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
+
+    auto* fn = b.Function("f", ty.bool_());
+
+    b.Append(fn->Block(), [&] {
+        // 'b() && c()' is evaluated before 'a()'.
+        auto* if1 = b.If(b.Call(ty.bool_(), fn_b));
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, b.Call(ty.bool_(), fn_c)); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
+
+        auto* if2 = b.If(b.Call(ty.bool_(), fn_a));
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, if1); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
+
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn a() -> bool {
+  return true;
+}
+
+fn b() -> bool {
+  return true;
+}
+
+fn c() -> bool {
+  return true;
+}
+
+fn f() -> bool {
+  let v = (b() && c());
+  return (a() && v);
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_And_Param_3_a_bc_EarlyEval) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam(ty.bool_());
+    auto* pb = b.FunctionParam(ty.bool_());
+    auto* pc = b.FunctionParam(ty.bool_());
+    mod.SetName(pa, "a");
+    mod.SetName(pb, "b");
+    mod.SetName(pc, "c");
+    fn->SetParams({pa, pb, pc});
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(pb);
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, pc); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, false); });
+
+        auto* if2 = b.If(pa);
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, if1); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, false); });
+
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool, c : bool) -> bool {
+  let v = (b && c);
+  return (a && v);
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_ParamCallParam_a_bc_EarlyEval) {
+    auto* fn_b = b.Function("b", ty.bool_());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
+
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam(ty.bool_());
+    auto* pc = b.FunctionParam(ty.bool_());
+    mod.SetName(pa, "a");
+    mod.SetName(pc, "c");
+    fn->SetParams({pa, pc});
+
+    b.Append(fn->Block(), [&] {
+        // 'b() && c' is evaluated before 'a'.
+        auto* if1 = b.If(b.Call(ty.bool_(), fn_b));
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, pc); });
+        auto* v = b.Let("v", if1);
+
+        auto* if2 = b.If(pa);
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, v); });
+
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn b() -> bool {
+  return true;
+}
+
+fn f(a : bool, c : bool) -> bool {
+  let v = (b() || c);
+  return (a || v);
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_Call_3_a_bc_EarlyEval) {
+    auto* fn_a = b.Function("a", ty.bool_());
+
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, true); });
+
+    auto* fn_b = b.Function("b", ty.bool_());
+
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, true); });
+
+    auto* fn_c = b.Function("c", ty.bool_());
+
+    b.Append(fn_c->Block(), [&] { b.Return(fn_c, true); });
+
+    auto* fn = b.Function("f", ty.bool_());
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(b.Call(ty.bool_(), fn_b));
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, b.Call(ty.bool_(), fn_c)); });
+        auto* v = b.Let("v", if1);
+
+        auto* if2 = b.If(b.Call(ty.bool_(), fn_a));
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, v); });
+
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn a() -> bool {
+  return true;
+}
+
+fn b() -> bool {
+  return true;
+}
+
+fn c() -> bool {
+  return true;
+}
+
+fn f() -> bool {
+  let v = (b() || c());
+  return (a() || v);
+}
+)");
+}
+
+TEST_F(WgslIRWriterTest, ShortCircuit_Or_Param_3_a_bc_EarlyEval) {
+    auto* fn = b.Function("f", ty.bool_());
+    auto* pa = b.FunctionParam(ty.bool_());
+    auto* pb = b.FunctionParam(ty.bool_());
+    auto* pc = b.FunctionParam(ty.bool_());
+    mod.SetName(pa, "a");
+    mod.SetName(pb, "b");
+    mod.SetName(pc, "c");
+    fn->SetParams({pa, pb, pc});
+
+    b.Append(fn->Block(), [&] {
+        auto* if1 = b.If(pb);
+        if1->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if1->True(), [&] { b.ExitIf(if1, true); });
+        b.Append(if1->False(), [&] { b.ExitIf(if1, pc); });
+
+        auto* if2 = b.If(pa);
+        if2->SetResults(b.InstructionResult(ty.bool_()));
+        b.Append(if2->True(), [&] { b.ExitIf(if2, true); });
+        b.Append(if2->False(), [&] { b.ExitIf(if2, if1); });
+
+        b.Return(fn, if2);
+    });
+
+    RUN_TEST(R"(
+fn f(a : bool, b : bool, c : bool) -> bool {
+  let v = (b || c);
+  return (a || v);
+}
+)");
+}
+
+}  // namespace
+}  // namespace tint::wgsl::writer
diff --git a/src/tint/utils/diagnostic/source_test.cc b/src/tint/utils/diagnostic/source_test.cc
index 42b4e01..b15eafb 100644
--- a/src/tint/utils/diagnostic/source_test.cc
+++ b/src/tint/utils/diagnostic/source_test.cc
@@ -27,6 +27,7 @@
 
 #include "src/tint/utils/diagnostic/source.h"
 
+#include <cstddef>
 #include <memory>
 #include <string_view>
 #include <utility>