[tint][spirv] Inline image_from_texture in builtin_polyfill

The helper function in this file is only used for builtin_polyfill now
so it can be merged in this file.

Also reworks how the computation of replacement types is done in
builtin_polyfill to make it easier to extend in the future.

Bug: 411573958
Change-Id: Id79bdd433c1f43f40e390ba737599e56e85bca50
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/237916
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/tint/lang/spirv/ir/BUILD.bazel b/src/tint/lang/spirv/ir/BUILD.bazel
index 1926b21..f71d6a4 100644
--- a/src/tint/lang/spirv/ir/BUILD.bazel
+++ b/src/tint/lang/spirv/ir/BUILD.bazel
@@ -40,12 +40,10 @@
   name = "ir",
   srcs = [
     "builtin_call.cc",
-    "image_from_texture.cc",
     "literal_operand.cc",
   ],
   hdrs = [
     "builtin_call.h",
-    "image_from_texture.h",
     "literal_operand.h",
   ],
   deps = [
@@ -57,7 +55,6 @@
     "//src/tint/lang/core/type",
     "//src/tint/lang/spirv",
     "//src/tint/lang/spirv/intrinsic",
-    "//src/tint/lang/spirv/type",
     "//src/tint/utils",
     "//src/tint/utils/containers",
     "//src/tint/utils/diagnostic",
diff --git a/src/tint/lang/spirv/ir/BUILD.cmake b/src/tint/lang/spirv/ir/BUILD.cmake
index 20f8765..d4abd09 100644
--- a/src/tint/lang/spirv/ir/BUILD.cmake
+++ b/src/tint/lang/spirv/ir/BUILD.cmake
@@ -41,8 +41,6 @@
 tint_add_target(tint_lang_spirv_ir lib
   lang/spirv/ir/builtin_call.cc
   lang/spirv/ir/builtin_call.h
-  lang/spirv/ir/image_from_texture.cc
-  lang/spirv/ir/image_from_texture.h
   lang/spirv/ir/literal_operand.cc
   lang/spirv/ir/literal_operand.h
 )
@@ -56,7 +54,6 @@
   tint_lang_core_type
   tint_lang_spirv
   tint_lang_spirv_intrinsic
-  tint_lang_spirv_type
   tint_utils
   tint_utils_containers
   tint_utils_diagnostic
diff --git a/src/tint/lang/spirv/ir/BUILD.gn b/src/tint/lang/spirv/ir/BUILD.gn
index 3498df0..c06651b 100644
--- a/src/tint/lang/spirv/ir/BUILD.gn
+++ b/src/tint/lang/spirv/ir/BUILD.gn
@@ -47,8 +47,6 @@
   sources = [
     "builtin_call.cc",
     "builtin_call.h",
-    "image_from_texture.cc",
-    "image_from_texture.h",
     "literal_operand.cc",
     "literal_operand.h",
   ]
@@ -62,7 +60,6 @@
     "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/lang/spirv",
     "${tint_src_dir}/lang/spirv/intrinsic",
-    "${tint_src_dir}/lang/spirv/type",
     "${tint_src_dir}/utils",
     "${tint_src_dir}/utils/containers",
     "${tint_src_dir}/utils/diagnostic",
diff --git a/src/tint/lang/spirv/ir/image_from_texture.cc b/src/tint/lang/spirv/ir/image_from_texture.cc
deleted file mode 100644
index 806647e..0000000
--- a/src/tint/lang/spirv/ir/image_from_texture.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2025 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/spirv/ir/image_from_texture.h"
-#include "src/tint/lang/core/type/f32.h"
-#include "src/tint/lang/core/type/i32.h"
-#include "src/tint/lang/core/type/input_attachment.h"
-#include "src/tint/lang/core/type/sampled_texture.h"
-#include "src/tint/lang/core/type/storage_texture.h"
-#include "src/tint/lang/core/type/u32.h"
-#include "src/tint/utils/rtti/switch.h"
-
-namespace tint::spirv::ir {
-
-const spirv::type::Image* ImageFromTexture(core::type::Manager& ty,
-                                           const core::type::Texture* tex_ty) {
-    auto dim = type::Dim::kD1;
-    auto depth = type::Depth::kNotDepth;
-    auto arrayed = type::Arrayed::kNonArrayed;
-    auto ms = type::Multisampled::kSingleSampled;
-    auto sampled = type::Sampled::kSamplingCompatible;
-    auto fmt = core::TexelFormat::kUndefined;
-    auto access = core::Access::kReadWrite;
-    const core::type::Type* sample_ty = ty.f32();
-
-    switch (tex_ty->Dim()) {
-        case core::type::TextureDimension::k1d:
-            dim = type::Dim::kD1;
-            break;
-        case core::type::TextureDimension::k2d:
-            dim = type::Dim::kD2;
-            break;
-        case core::type::TextureDimension::k2dArray:
-            dim = type::Dim::kD2;
-            arrayed = type::Arrayed::kArrayed;
-            break;
-        case core::type::TextureDimension::k3d:
-            dim = type::Dim::kD3;
-            break;
-        case core::type::TextureDimension::kCube:
-            dim = type::Dim::kCube;
-            break;
-        case core::type::TextureDimension::kCubeArray:
-            dim = type::Dim::kCube;
-            arrayed = type::Arrayed::kArrayed;
-            break;
-        default:
-            TINT_ICE() << "Invalid texture dimension: " << tex_ty->Dim();
-    }
-
-    tint::Switch(
-        tex_ty,                                 //
-        [&](const core::type::DepthTexture*) {  //
-            depth = type::Depth::kDepth;
-        },
-        [&](const core::type::DepthMultisampledTexture*) {
-            depth = type::Depth::kDepth;
-            ms = type::Multisampled::kMultisampled;
-        },
-        [&](const core::type::MultisampledTexture* mt) {
-            ms = type::Multisampled::kMultisampled;
-            sample_ty = mt->Type();
-        },
-        [&](const core::type::SampledTexture* st) {
-            sampled = type::Sampled::kSamplingCompatible;
-            sample_ty = st->Type();
-        },
-        [&](const core::type::StorageTexture* st) {
-            sampled = type::Sampled::kReadWriteOpCompatible;
-            fmt = st->TexelFormat();
-            sample_ty = st->Type();
-            access = st->Access();
-        },
-        [&](const core::type::InputAttachment* ia) {
-            dim = type::Dim::kSubpassData;
-            sampled = type::Sampled::kReadWriteOpCompatible;
-            sample_ty = ia->Type();
-        },
-        TINT_ICE_ON_NO_MATCH);
-
-    return ty.Get<type::Image>(sample_ty, dim, depth, arrayed, ms, sampled, fmt, access);
-}
-
-}  // namespace tint::spirv::ir
diff --git a/src/tint/lang/spirv/ir/image_from_texture.h b/src/tint/lang/spirv/ir/image_from_texture.h
deleted file mode 100644
index f95a787..0000000
--- a/src/tint/lang/spirv/ir/image_from_texture.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2025 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_SPIRV_IR_IMAGE_FROM_TEXTURE_H_
-#define SRC_TINT_LANG_SPIRV_IR_IMAGE_FROM_TEXTURE_H_
-
-#include "src/tint/lang/core/type/manager.h"
-#include "src/tint/lang/core/type/texture.h"
-#include "src/tint/lang/spirv/type/image.h"
-
-namespace tint::spirv::ir {
-
-const spirv::type::Image* ImageFromTexture(core::type::Manager& ty,
-                                           const core::type::Texture* tex_ty);
-
-}
-
-#endif  // SRC_TINT_LANG_SPIRV_IR_IMAGE_FROM_TEXTURE_H_
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index 75895cf..a9889bd 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -90,7 +90,6 @@
 #include "src/tint/lang/core/type/vector.h"
 #include "src/tint/lang/core/type/void.h"
 #include "src/tint/lang/spirv/ir/builtin_call.h"
-#include "src/tint/lang/spirv/ir/image_from_texture.h"
 #include "src/tint/lang/spirv/ir/literal_operand.h"
 #include "src/tint/lang/spirv/type/explicit_layout_array.h"
 #include "src/tint/lang/spirv/type/sampled_image.h"
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
index 0b9a7ef..6db6703 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
@@ -43,7 +43,6 @@
 #include "src/tint/lang/core/type/storage_texture.h"
 #include "src/tint/lang/core/type/texture.h"
 #include "src/tint/lang/spirv/ir/builtin_call.h"
-#include "src/tint/lang/spirv/ir/image_from_texture.h"
 #include "src/tint/lang/spirv/ir/literal_operand.h"
 #include "src/tint/lang/spirv/type/sampled_image.h"
 #include "src/tint/utils/ice/ice.h"
@@ -55,6 +54,92 @@
 
 namespace {
 
+const spirv::type::Image* ImageFromTexture(core::type::Manager& ty,
+                                           const core::type::Texture* tex_ty) {
+    auto dim = type::Dim::kD1;
+    auto depth = type::Depth::kNotDepth;
+    auto arrayed = type::Arrayed::kNonArrayed;
+    auto ms = type::Multisampled::kSingleSampled;
+    auto sampled = type::Sampled::kSamplingCompatible;
+    auto fmt = core::TexelFormat::kUndefined;
+    auto access = core::Access::kReadWrite;
+    const core::type::Type* sample_ty = ty.f32();
+
+    switch (tex_ty->Dim()) {
+        case core::type::TextureDimension::k1d:
+            dim = type::Dim::kD1;
+            break;
+        case core::type::TextureDimension::k2d:
+            dim = type::Dim::kD2;
+            break;
+        case core::type::TextureDimension::k2dArray:
+            dim = type::Dim::kD2;
+            arrayed = type::Arrayed::kArrayed;
+            break;
+        case core::type::TextureDimension::k3d:
+            dim = type::Dim::kD3;
+            break;
+        case core::type::TextureDimension::kCube:
+            dim = type::Dim::kCube;
+            break;
+        case core::type::TextureDimension::kCubeArray:
+            dim = type::Dim::kCube;
+            arrayed = type::Arrayed::kArrayed;
+            break;
+        default:
+            TINT_ICE() << "Invalid texture dimension: " << tex_ty->Dim();
+    }
+
+    tint::Switch(
+        tex_ty,                                 //
+        [&](const core::type::DepthTexture*) {  //
+            depth = type::Depth::kDepth;
+        },
+        [&](const core::type::DepthMultisampledTexture*) {
+            depth = type::Depth::kDepth;
+            ms = type::Multisampled::kMultisampled;
+        },
+        [&](const core::type::MultisampledTexture* mt) {
+            ms = type::Multisampled::kMultisampled;
+            sample_ty = mt->Type();
+        },
+        [&](const core::type::SampledTexture* st) {
+            sampled = type::Sampled::kSamplingCompatible;
+            sample_ty = st->Type();
+        },
+        [&](const core::type::StorageTexture* st) {
+            sampled = type::Sampled::kReadWriteOpCompatible;
+            fmt = st->TexelFormat();
+            sample_ty = st->Type();
+            access = st->Access();
+        },
+        [&](const core::type::InputAttachment* ia) {
+            dim = type::Dim::kSubpassData;
+            sampled = type::Sampled::kReadWriteOpCompatible;
+            sample_ty = ia->Type();
+        },
+        TINT_ICE_ON_NO_MATCH);
+
+    return ty.Get<type::Image>(sample_ty, dim, depth, arrayed, ms, sampled, fmt, access);
+}
+
+/// Returns a replacement type if type replacement is necessary.
+/// @param ty the type manager
+/// @param type the type to replace
+/// @returns the replacement type if replacement needs to happen
+const core::type::Type* ReplacementType(core::type::Manager& ty, const core::type::Type* type) {
+    return Switch(
+        type,
+        [&](const core::type::Pointer* ptr) -> const core::type::Type* {
+            if (auto* replacement = ReplacementType(ty, ptr->StoreType())) {
+                return ty.ptr(ptr->AddressSpace(), replacement, ptr->Access());
+            }
+            return nullptr;
+        },
+        [&](const core::type::Texture* tex) { return ImageFromTexture(ty, tex); },
+        [&](Default) { return nullptr; });
+}
+
 /// PIMPL state for the transform.
 struct State {
     /// The IR module.
@@ -74,28 +159,20 @@
         // Find the builtins that need replacing.
         Vector<core::ir::CoreBuiltinCall*, 4> worklist;
 
-        // Convert function parameters to `spirv::type::Image` if necessary
+        // Replace types for function parameters if necessary
         for (auto fn : ir.functions) {
             for (auto* param : fn->Params()) {
-                if (auto* tex = param->Type()->As<core::type::Texture>()) {
-                    param->SetType(ir::ImageFromTexture(ty, tex));
+                if (auto* replacement = ReplacementType(ty, param->Type())) {
+                    param->SetType(replacement);
                 }
             }
         }
 
         for (auto* inst : ir.Instructions()) {
-            // Convert instruction results to `spirv::type::Image` if necessary
-            if (!inst->Results().IsEmpty()) {
-                if (auto* res = inst->Result(0)->As<core::ir::InstructionResult>()) {
-                    // Watch for pointers, which would be wrapping any texture on a `var`
-                    if (auto* tex = res->Type()->UnwrapPtr()->As<core::type::Texture>()) {
-                        auto* tex_ty = ir::ImageFromTexture(ty, tex);
-                        const core::type::Type* res_ty = tex_ty;
-                        if (auto* orig_ptr = res->Type()->As<core::type::Pointer>()) {
-                            res_ty = ty.ptr(orig_ptr->AddressSpace(), res_ty, orig_ptr->Access());
-                        }
-                        res->SetType(res_ty);
-                    }
+            // Replace types for instruction results if necessary
+            for (auto* result : inst->Results()) {
+                if (auto* replacement = ReplacementType(ty, result->Type())) {
+                    result->SetType(replacement);
                 }
             }
 
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.h b/src/tint/lang/spirv/writer/raise/builtin_polyfill.h
index 8fff29e..79459db 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.h
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.h
@@ -39,7 +39,8 @@
 namespace tint::spirv::writer::raise {
 
 /// BuiltinPolyfill is a transform that replaces calls to builtins with polyfills and calls to
-/// SPIR-V backend intrinsic functions.
+/// SPIR-V backend intrinsic functions. It replaces core types with SPIR-V specific types at the
+/// same time to produce valid IR (e.g. texture types to spirv.image).
 /// @param module the module to transform
 /// @param use_vulkan_memory_model set `true` to use the vulkan memory model
 /// @returns success or failure