[tint][ir] Various fixes to IR -> Program

Fix replacement of instructions in Raise.
Emit required experimental extensions.

Change-Id: Ie4008aa81a8a01846f41e829a9782b1239219e8b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/154401
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/core/type/storage_texture.cc b/src/tint/lang/core/type/storage_texture.cc
index f1d7204..07ca8a0 100644
--- a/src/tint/lang/core/type/storage_texture.cc
+++ b/src/tint/lang/core/type/storage_texture.cc
@@ -28,7 +28,7 @@
 StorageTexture::StorageTexture(TextureDimension dim,
                                core::TexelFormat format,
                                core::Access access,
-                               Type* subtype)
+                               const Type* subtype)
     : Base(Hash(tint::TypeInfo::Of<StorageTexture>().full_hashcode, dim, format, access), dim),
       texel_format_(format),
       access_(access),
diff --git a/src/tint/lang/core/type/storage_texture.h b/src/tint/lang/core/type/storage_texture.h
index 491e7fa..7abcab14e 100644
--- a/src/tint/lang/core/type/storage_texture.h
+++ b/src/tint/lang/core/type/storage_texture.h
@@ -40,7 +40,7 @@
     StorageTexture(TextureDimension dim,
                    core::TexelFormat format,
                    core::Access access,
-                   Type* subtype);
+                   const Type* subtype);
 
     /// Destructor
     ~StorageTexture() override;
@@ -50,7 +50,7 @@
     bool Equals(const UniqueNode& other) const override;
 
     /// @returns the storage subtype
-    Type* type() const { return subtype_; }
+    const Type* type() const { return subtype_; }
 
     /// @returns the texel format
     core::TexelFormat texel_format() const { return texel_format_; }
@@ -74,7 +74,7 @@
   private:
     core::TexelFormat const texel_format_;
     core::Access const access_;
-    Type* const subtype_;
+    const Type* const subtype_;
 };
 
 }  // namespace tint::core::type
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 c67c82f..7246e49 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel
@@ -83,6 +83,8 @@
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
+    "//src/tint/lang/wgsl/intrinsic",
+    "//src/tint/lang/wgsl/ir",
     "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/sem",
     "//src/tint/lang/wgsl/writer",
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 1fa4481..c639f7c 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake
@@ -82,6 +82,8 @@
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
+  tint_lang_wgsl_intrinsic
+  tint_lang_wgsl_ir
   tint_lang_wgsl_program
   tint_lang_wgsl_sem
   tint_lang_wgsl_writer
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 a225f3f..587dd65 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
@@ -84,6 +84,8 @@
       "${tint_src_dir}/lang/core/type",
       "${tint_src_dir}/lang/wgsl",
       "${tint_src_dir}/lang/wgsl/ast",
+      "${tint_src_dir}/lang/wgsl/intrinsic",
+      "${tint_src_dir}/lang/wgsl/ir",
       "${tint_src_dir}/lang/wgsl/program",
       "${tint_src_dir}/lang/wgsl/sem",
       "${tint_src_dir}/lang/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 faaacf4..43d5ce7 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
@@ -596,6 +596,18 @@
                     disabled_derivative_uniformity_ = true;
                 }
 
+                switch (c->Func()) {
+                    case wgsl::BuiltinFn::kTextureBarrier:
+                        Enable(wgsl::Extension::kChromiumExperimentalReadWriteStorageTexture);
+                        break;
+                    case wgsl::BuiltinFn::kSubgroupBallot:
+                    case wgsl::BuiltinFn::kSubgroupBroadcast:
+                        Enable(wgsl::Extension::kChromiumExperimentalSubgroups);
+                        break;
+                    default:
+                        break;
+                }
+
                 auto* expr = b.Call(c->Func(), std::move(args));
                 if (!call->HasResults() || call->Result()->Type()->Is<core::type::Void>()) {
                     Append(b.CallStmt(expr));
@@ -925,6 +937,9 @@
                 return b.ty.sampled_texture(t->dim(), el);
             },
             [&](const core::type::StorageTexture* t) {
+                if (t->access() == core::Access::kRead || t->access() == core::Access::kReadWrite) {
+                    Enable(wgsl::Extension::kChromiumExperimentalReadWriteStorageTexture);
+                }
                 return b.ty.storage_texture(t->dim(), t->texel_format(), t->access());
             },
             [&](const core::type::Sampler* s) { return b.ty.sampler(s->kind()); },
@@ -968,6 +983,9 @@
                     ast_attrs.Push(b.Index(u32(*index)));
                 }
                 if (auto builtin = ir_attrs.builtin) {
+                    if (RequiresSubgroups(*builtin)) {
+                        Enable(wgsl::Extension::kChromiumExperimentalSubgroups);
+                    }
                     ast_attrs.Push(b.Builtin(*builtin));
                 }
                 if (auto interpolation = ir_attrs.interpolation) {
@@ -1171,6 +1189,18 @@
         }
     }
 
+    /// @returns true if the builtin value requires the kChromiumExperimentalSubgroups extension to
+    /// be enabled.
+    bool RequiresSubgroups(core::BuiltinValue builtin) {
+        switch (builtin) {
+            case core::BuiltinValue::kSubgroupInvocationId:
+            case core::BuiltinValue::kSubgroupSize:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     /// @returns true if a parameter of the type @p ty requires the
     /// kChromiumExperimentalFullPtrParameters extension to be enabled.
     bool ParamRequiresFullPtrParameters(const core::type::Type* ty) {
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 537c11a..4b0d122 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
@@ -16,6 +16,8 @@
 #include <string>
 
 #include "src/tint/lang/core/ir/disassembler.h"
+#include "src/tint/lang/core/type/storage_texture.h"
+#include "src/tint/lang/wgsl/ir/builtin_call.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"
@@ -3195,5 +3197,142 @@
 )");
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// chromium_experimental_read_write_storage_texture
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(IRToProgramTest, Enable_ChromiumExperimentalReadWriteStorageTexture_TextureBarrier) {
+    auto* fn = b.Function("f", ty.void_());
+    b.Append(fn->Block(), [&] {
+        b.Append(mod.instructions.Create<wgsl::ir::BuiltinCall>(
+            b.InstructionResult(ty.void_()), wgsl::BuiltinFn::kTextureBarrier, Empty));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+enable chromium_experimental_read_write_storage_texture;
+
+fn f() {
+  textureBarrier();
+}
+)");
+}
+
+TEST_F(IRToProgramTest, Enable_ChromiumExperimentalReadWriteStorageTexture_ReadOnlyStorageTexture) {
+    auto* T = b.Var("T", ty.ptr<handle>(ty.Get<core::type::StorageTexture>(
+                             core::type::TextureDimension::k2d, core::TexelFormat::kR32Float,
+                             core::Access::kRead, ty.f32())));
+    T->SetBindingPoint(0, 0);
+    b.ir.root_block->Append(T);
+
+    EXPECT_WGSL(R"(
+enable chromium_experimental_read_write_storage_texture;
+
+@group(0) @binding(0) var T : texture_storage_2d<r32float, read>;
+)");
+}
+
+TEST_F(IRToProgramTest,
+       Enable_ChromiumExperimentalReadWriteStorageTexture_ReadWriteOnlyStorageTexture) {
+    auto* T = b.Var("T", ty.ptr<handle>(ty.Get<core::type::StorageTexture>(
+                             core::type::TextureDimension::k2d, core::TexelFormat::kR32Float,
+                             core::Access::kReadWrite, ty.f32())));
+    T->SetBindingPoint(0, 0);
+    b.ir.root_block->Append(T);
+
+    EXPECT_WGSL(R"(
+enable chromium_experimental_read_write_storage_texture;
+
+@group(0) @binding(0) var T : texture_storage_2d<r32float, read_write>;
+)");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// chromium_experimental_subgroups
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(IRToProgramTest, Enable_ChromiumExperimentalSubgroups_SubgroupBallot) {
+    auto* fn = b.Function("f", ty.void_());
+    b.Append(fn->Block(), [&] {
+        b.Append(mod.instructions.Create<wgsl::ir::BuiltinCall>(
+            b.InstructionResult(ty.vec4<u32>()), wgsl::BuiltinFn::kSubgroupBallot, Empty));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+enable chromium_experimental_subgroups;
+
+fn f() {
+  _ = subgroupBallot();
+}
+)");
+}
+
+TEST_F(IRToProgramTest, Enable_ChromiumExperimentalSubgroups_SubgroupBroadcast) {
+    auto* fn = b.Function("f", ty.void_());
+    b.Append(fn->Block(), [&] {
+        auto* one = b.Value(1_u);
+        b.Append(mod.instructions.Create<wgsl::ir::BuiltinCall>(
+            b.InstructionResult(ty.u32()), wgsl::BuiltinFn::kSubgroupBroadcast, Vector{one, one}));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+enable chromium_experimental_subgroups;
+
+fn f() {
+  _ = subgroupBroadcast(1u, 1u);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, Enable_ChromiumExperimentalSubgroups_StructBuiltin_SubgroupInvocationId) {
+    core::type::Manager::StructMemberDesc member;
+    member.name = mod.symbols.New("a");
+    member.type = ty.u32();
+    member.attributes.builtin = core::BuiltinValue::kSubgroupInvocationId;
+
+    auto* S = ty.Struct(mod.symbols.New("S"), {member});
+
+    auto* fn = b.Function("f", ty.void_());
+    fn->SetParams({b.FunctionParam(S)});
+    b.Append(fn->Block(), [&] { b.Return(fn); });
+
+    EXPECT_WGSL(R"(
+enable chromium_experimental_subgroups;
+
+struct S {
+  @builtin(subgroup_invocation_id)
+  a : u32,
+}
+
+fn f(v : S) {
+}
+)");
+}
+
+TEST_F(IRToProgramTest, Enable_ChromiumExperimentalSubgroups_StructBuiltin_SubgroupSize) {
+    core::type::Manager::StructMemberDesc member;
+    member.name = mod.symbols.New("a");
+    member.type = ty.u32();
+    member.attributes.builtin = core::BuiltinValue::kSubgroupSize;
+
+    auto* S = ty.Struct(mod.symbols.New("S"), {member});
+
+    auto* fn = b.Function("f", ty.void_());
+    fn->SetParams({b.FunctionParam(S)});
+    b.Append(fn->Block(), [&] { b.Return(fn); });
+
+    EXPECT_WGSL(R"(
+enable chromium_experimental_subgroups;
+
+struct S {
+  @builtin(subgroup_size)
+  a : u32,
+}
+
+fn f(v : S) {
+}
+)");
+}
+
 }  // namespace
 }  // namespace tint::wgsl::writer
diff --git a/src/tint/lang/wgsl/writer/raise/raise.cc b/src/tint/lang/wgsl/writer/raise/raise.cc
index 88cccdf..d0ab5da 100644
--- a/src/tint/lang/wgsl/writer/raise/raise.cc
+++ b/src/tint/lang/wgsl/writer/raise/raise.cc
@@ -160,6 +160,8 @@
             auto* replacement = mod.instructions.Create<wgsl::ir::BuiltinCall>(
                 call->Result(), Convert(call->Func()), std::move(args));
             call->ReplaceWith(replacement);
+            call->ClearResults();
+            call->Destroy();
         }
     }
     return Success;