[hlsl] Fold PixelLocal options into HLSL options

This Cl moves the PixelLocal options directly into the HLSL options
struct as the only user. The API PixelLocal struct is removed.

Change-Id: I651e34fc2d178685801fe6c76c195457cbf84781
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/192080
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/include/tint/tint.h b/include/tint/tint.h
index e252a1e..b168265 100644
--- a/include/tint/tint.h
+++ b/include/tint/tint.h
@@ -35,7 +35,6 @@
 //                headers will need to be moved to include/tint/.
 
 #include "src/tint/api/common/binding_point.h"
-#include "src/tint/api/options/pixel_local.h"
 #include "src/tint/api/options/texture_builtins_from_uniform.h"
 #include "src/tint/api/tint.h"
 #include "src/tint/lang/core/type/manager.h"
diff --git a/src/dawn/native/d3d11/RenderPipelineD3D11.cpp b/src/dawn/native/d3d11/RenderPipelineD3D11.cpp
index 03cc7be..91fc841 100644
--- a/src/dawn/native/d3d11/RenderPipelineD3D11.cpp
+++ b/src/dawn/native/d3d11/RenderPipelineD3D11.cpp
@@ -475,11 +475,11 @@
         mUsesInstanceIndex = compiledShader[SingleShaderStage::Vertex].usesInstanceIndex;
     }
 
-    std::optional<tint::PixelLocalOptions> pixelLocalOptions;
+    std::optional<tint::hlsl::writer::PixelLocalOptions> pixelLocalOptions;
     if (GetStageMask() & wgpu::ShaderStage::Fragment) {
-        pixelLocalOptions = tint::PixelLocalOptions();
+        pixelLocalOptions = tint::hlsl::writer::PixelLocalOptions();
         // HLSL SM5.0 doesn't support groups, so we set group index to 0.
-        pixelLocalOptions->pixel_local_group_index = 0;
+        pixelLocalOptions->group_index = 0;
 
         if (GetAttachmentState()->HasPixelLocalStorage()) {
             const std::vector<wgpu::TextureFormat>& storageAttachmentSlots =
@@ -503,15 +503,15 @@
                     case wgpu::TextureFormat::Undefined:
                     case wgpu::TextureFormat::R32Uint:
                         pixelLocalOptions->attachment_formats[i] =
-                            tint::PixelLocalOptions::TexelFormat::kR32Uint;
+                            tint::hlsl::writer::PixelLocalOptions::TexelFormat::kR32Uint;
                         break;
                     case wgpu::TextureFormat::R32Sint:
                         pixelLocalOptions->attachment_formats[i] =
-                            tint::PixelLocalOptions::TexelFormat::kR32Sint;
+                            tint::hlsl::writer::PixelLocalOptions::TexelFormat::kR32Sint;
                         break;
                     case wgpu::TextureFormat::R32Float:
                         pixelLocalOptions->attachment_formats[i] =
-                            tint::PixelLocalOptions::TexelFormat::kR32Float;
+                            tint::hlsl::writer::PixelLocalOptions::TexelFormat::kR32Float;
                         break;
                     default:
                         DAWN_UNREACHABLE();
diff --git a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
index 6d4ee66..c5469c5 100644
--- a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
+++ b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
@@ -78,7 +78,7 @@
     const PipelineLayout* layout,
     uint32_t compileFlags,
     const std::optional<dawn::native::d3d::InterStageShaderVariablesMask>& usedInterstageVariables,
-    const std::optional<tint::PixelLocalOptions>& pixelLocalOptions) {
+    const std::optional<tint::hlsl::writer::PixelLocalOptions>& pixelLocalOptions) {
     Device* device = ToBackend(GetDevice());
     TRACE_EVENT0(device->GetPlatform(), General, "ShaderModuleD3D11::Compile");
     DAWN_ASSERT(!IsError());
@@ -233,7 +233,7 @@
         req.hlsl.tintOptions.truncate_interstage_variables = true;
     } else if (stage == SingleShaderStage::Fragment) {
         if (pixelLocalOptions.has_value()) {
-            req.hlsl.tintOptions.pixel_local_options = *pixelLocalOptions;
+            req.hlsl.tintOptions.pixel_local = *pixelLocalOptions;
         }
     }
 
diff --git a/src/dawn/native/d3d11/ShaderModuleD3D11.h b/src/dawn/native/d3d11/ShaderModuleD3D11.h
index f1688fe..b436aee 100644
--- a/src/dawn/native/d3d11/ShaderModuleD3D11.h
+++ b/src/dawn/native/d3d11/ShaderModuleD3D11.h
@@ -61,7 +61,7 @@
         uint32_t compileFlags,
         const std::optional<dawn::native::d3d::InterStageShaderVariablesMask>&
             usedInterstageVariables = {},
-        const std::optional<tint::PixelLocalOptions>& pixelLocalOptions = {});
+        const std::optional<tint::hlsl::writer::PixelLocalOptions>& pixelLocalOptions = {});
 
   private:
     ShaderModule(Device* device, const UnpackedPtr<ShaderModuleDescriptor>& descriptor);
diff --git a/src/tint/api/options/BUILD.bazel b/src/tint/api/options/BUILD.bazel
index 5d312a2..47bebba 100644
--- a/src/tint/api/options/BUILD.bazel
+++ b/src/tint/api/options/BUILD.bazel
@@ -42,7 +42,6 @@
     "options.cc",
   ],
   hdrs = [
-    "pixel_local.h",
     "texture_builtins_from_uniform.h",
   ],
   deps = [
@@ -66,7 +65,6 @@
   name = "test",
   alwayslink = True,
   srcs = [
-    "pixel_local_test.cc",
     "texture_builtins_from_uniform_test.cc",
   ],
   deps = [
diff --git a/src/tint/api/options/BUILD.cmake b/src/tint/api/options/BUILD.cmake
index 1789ace..e6ef899 100644
--- a/src/tint/api/options/BUILD.cmake
+++ b/src/tint/api/options/BUILD.cmake
@@ -40,7 +40,6 @@
 ################################################################################
 tint_add_target(tint_api_options lib
   api/options/options.cc
-  api/options/pixel_local.h
   api/options/texture_builtins_from_uniform.h
 )
 
@@ -64,7 +63,6 @@
 # Kind:      test
 ################################################################################
 tint_add_target(tint_api_options_test test
-  api/options/pixel_local_test.cc
   api/options/texture_builtins_from_uniform_test.cc
 )
 
diff --git a/src/tint/api/options/BUILD.gn b/src/tint/api/options/BUILD.gn
index 378e54b..abb0c19 100644
--- a/src/tint/api/options/BUILD.gn
+++ b/src/tint/api/options/BUILD.gn
@@ -45,7 +45,6 @@
 libtint_source_set("options") {
   sources = [
     "options.cc",
-    "pixel_local.h",
     "texture_builtins_from_uniform.h",
   ]
   deps = [
@@ -65,10 +64,7 @@
 }
 if (tint_build_unittests) {
   tint_unittests_source_set("unittests") {
-    sources = [
-      "pixel_local_test.cc",
-      "texture_builtins_from_uniform_test.cc",
-    ]
+    sources = [ "texture_builtins_from_uniform_test.cc" ]
     deps = [
       "${tint_src_dir}:gmock_and_gtest",
       "${tint_src_dir}/api/common",
diff --git a/src/tint/api/options/pixel_local.h b/src/tint/api/options/pixel_local.h
deleted file mode 100644
index 90b1912..0000000
--- a/src/tint/api/options/pixel_local.h
+++ /dev/null
@@ -1,65 +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.
-
-#ifndef SRC_TINT_API_OPTIONS_PIXEL_LOCAL_H_
-#define SRC_TINT_API_OPTIONS_PIXEL_LOCAL_H_
-
-#include <cstdint>
-#include <unordered_map>
-
-#include "src/tint/utils/reflection/reflection.h"
-
-namespace tint {
-
-/// Options used to specify pixel local mappings
-struct PixelLocalOptions {
-    /// Index of pixel_local structure member index to attachment index
-    std::unordered_map<uint32_t, uint32_t> attachments;
-
-    /// The supported pixel local storage attachment format
-    enum class TexelFormat : uint8_t {
-        kR32Sint,
-        kR32Uint,
-        kR32Float,
-        kUndefined,
-    };
-    /// Index of pixel_local structure member index to pixel local storage attachment format
-    std::unordered_map<uint32_t, TexelFormat> attachment_formats;
-
-    /// The bind group index of all pixel local storage attachments
-    uint32_t pixel_local_group_index = 0;
-
-    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(PixelLocalOptions, attachments, attachment_formats, pixel_local_group_index);
-};
-
-/// Reflect valid value ranges for the PixelLocalOptions::TexelFormat enum.
-TINT_REFLECT_ENUM_RANGE(PixelLocalOptions::TexelFormat, kR32Sint, kR32Float);
-
-}  // namespace tint
-
-#endif  // SRC_TINT_API_OPTIONS_PIXEL_LOCAL_H_
diff --git a/src/tint/api/options/pixel_local_test.cc b/src/tint/api/options/pixel_local_test.cc
deleted file mode 100644
index d0f9ade..0000000
--- a/src/tint/api/options/pixel_local_test.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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/api/options/pixel_local.h"
-
-#include <gtest/gtest.h>
-
-namespace tint {
-namespace {
-
-TEST(TintCheckAllFieldsReflected, ApiOptionsPixelLocalTest) {
-    TINT_ASSERT_ALL_FIELDS_REFLECTED(tint::PixelLocalOptions);
-}
-
-}  // namespace
-}  // namespace tint
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index 074ec29..be8f4ce 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -39,7 +39,6 @@
 #include "spirv-tools/libspirv.hpp"
 #endif  // TINT_BUILD_SPV_READER || TINT_BUILD_SPV_WRITER
 
-#include "src/tint/api/options/pixel_local.h"
 #include "src/tint/api/tint.h"
 #include "src/tint/cmd/common/helper.h"
 #include "src/tint/lang/core/ir/disassembly.h"
@@ -178,59 +177,33 @@
 #endif  // TINT_BUILD_HLSL_WRITER
 
 /// An enumerator of color-output modes
-enum class ColorMode { kPlain, kDark, kLight };
+enum class ColorMode : uint8_t { kPlain, kDark, kLight };
 
 struct Options {
-    bool verbose = false;
-
     std::unique_ptr<tint::StyledTextPrinter> printer;
 
     std::string input_filename;
     std::string output_file = "-";  // Default to stdout
 
+    std::unordered_set<uint32_t> skip_hash;
+    tint::Vector<std::string, 4> transforms;
+    tint::Hashmap<std::string, double, 8> overrides;
+
+    std::string ep_name;
+
+    Format format = Format::kUnknown;
+
+    bool verbose = false;
     bool parse_only = false;
     bool disable_workgroup_init = false;
     bool validate = false;
     bool print_hash = false;
     bool dump_inspector_bindings = false;
     bool enable_robustness = false;
-
-    std::unordered_set<uint32_t> skip_hash;
-
-    Format format = Format::kUnknown;
-
     bool emit_single_entry_point = false;
-    std::string ep_name;
 
     bool rename_all = false;
 
-#if TINT_BUILD_SPV_READER
-    tint::spirv::reader::Options spirv_reader_options;
-#endif  // TINT_BUILD_SPV_READER
-
-    tint::Vector<std::string, 4> transforms;
-
-#if TINT_BUILD_SPV_WRITER
-    bool use_storage_input_output_16 = true;
-#endif  // TINT_BULD_SPV_WRITER
-
-#if TINT_BUILD_HLSL_WRITER
-    std::string fxc_path;
-    std::string dxc_path;
-#endif  // TINT_BULD_HLSL_WRITER
-
-#if TINT_BUILD_MSL_WRITER
-    std::string xcrun_path;
-#endif  // TINT_BULD_MSL_WRITER
-
-    tint::Hashmap<std::string, double, 8> overrides;
-    tint::PixelLocalOptions pixel_local_options;
-
-#if TINT_BUILD_HLSL_WRITER
-    std::optional<tint::BindingPoint> hlsl_root_constant_binding_point;
-    uint32_t hlsl_shader_model = kMinShaderModelForDXC;
-#endif  // TINT_BUILD_HLSL_WRITER
-
     bool dump_ir = false;
     bool dump_ir_bin = false;
     bool use_ir = false;
@@ -239,6 +212,32 @@
 #if TINT_BUILD_SYNTAX_TREE_WRITER
     bool dump_ast = false;
 #endif  // TINT_BUILD_SYNTAX_TREE_WRITER
+
+#if TINT_BUILD_SPV_READER
+    tint::spirv::reader::Options spirv_reader_options;
+#endif  // TINT_BUILD_SPV_READER
+
+#if TINT_BUILD_SPV_WRITER
+    bool use_storage_input_output_16 = true;
+#endif  // TINT_BULD_SPV_WRITER
+
+#if TINT_BUILD_HLSL_WRITER || TINT_BUILD_MSL_WRITER
+    std::unordered_map<uint32_t, uint32_t> pixel_local_attachments;
+#endif
+
+#if TINT_BUILD_HLSL_WRITER
+    std::string fxc_path;
+    std::string dxc_path;
+
+    std::optional<tint::BindingPoint> hlsl_root_constant_binding_point;
+    uint32_t hlsl_shader_model = kMinShaderModelForDXC;
+
+    tint::hlsl::writer::PixelLocalOptions pixel_local_options;
+#endif  // TINT_BUILD_HLSL_WRITER
+
+#if TINT_BUILD_MSL_WRITER
+    std::string xcrun_path;
+#endif  // TINT_BULD_MSL_WRITER
 };
 
 /// @returns the default ColorMode when no `--color` flag is specified.
@@ -485,6 +484,8 @@
 or group 0 if no resource bound)");
 #endif  // TINT_BUILD_HLSL_WRITER
 
+#if TINT_BUILD_HLSL_WRITER || TINT_BUILD_MSL_WRITER
+
     auto& pixel_local_attachments =
         options.Add<StringOption>("pixel_local_attachments",
                                   R"(Pixel local storage attachment bindings, comma-separated
@@ -494,6 +495,9 @@
 attachment.
 )");
 
+#endif
+
+#if TINT_BUILD_HLSL_WRITER
     auto& pixel_local_attachment_formats =
         options.Add<StringOption>("pixel_local_attachment_formats",
                                   R"(Pixel local storage attachment formats, comma-separated
@@ -508,6 +512,17 @@
         "pixel_local_group_index", "The bind group index of the pixel local attachments.",
         Default{0});
 
+    std::stringstream hlslShaderModelStream;
+    hlslShaderModelStream << R"(
+An integer value to set the HLSL shader model for the generated HLSL
+shader, which will only be used with option `--dxc`. Now only integers
+in the range [)" << kMinShaderModelForDXC
+                          << ", " << kMaxSupportedShaderModelForDXC
+                          << "] are accepted. The integer \"6x\" represents shader model 6.x.";
+    auto& hlsl_shader_model = options.Add<ValueOption<uint32_t>>(
+        "hlsl_shader_model", hlslShaderModelStream.str(), Default{kMinShaderModelForDXC});
+#endif  // TINT_BUILD_HLSL_WRITER
+
     auto& skip_hash = options.Add<StringOption>(
         "skip-hash", R"(Skips validation if the hash of the output is equal to any
 of the hash codes in the comma separated list of hashes)");
@@ -526,18 +541,6 @@
         }
     });
 
-#if TINT_BUILD_HLSL_WRITER
-    std::stringstream hlslShaderModelStream;
-    hlslShaderModelStream << R"(
-An integer value to set the HLSL shader model for the generated HLSL
-shader, which will only be used with option `--dxc`. Now only integers
-in the range [)" << kMinShaderModelForDXC
-                          << ", " << kMaxSupportedShaderModelForDXC
-                          << "] are accepted. The integer \"6x\" represents shader model 6.x.";
-    auto& hlsl_shader_model = options.Add<ValueOption<uint32_t>>(
-        "hlsl_shader_model", hlslShaderModelStream.str(), Default{kMinShaderModelForDXC});
-#endif  // TINT_BUILD_HLSL_WRITER
-
     auto& overrides = options.Add<StringOption>(
         "overrides", "Override values as IDENTIFIER=VALUE, comma-separated");
 
@@ -600,8 +603,55 @@
         }
         opts->hlsl_root_constant_binding_point = tint::BindingPoint{group.Get(), binding.Get()};
     }
+
+    if (pixel_local_group_index.value.has_value()) {
+        opts->pixel_local_options.group_index = *pixel_local_group_index.value;
+    }
+
+    if (pixel_local_attachment_formats.value.has_value()) {
+        auto binding_formats = tint::Split(*pixel_local_attachment_formats.value, ",");
+        for (auto& binding_format : binding_formats) {
+            auto values = tint::Split(binding_format, "=");
+            if (values.Length() != 2) {
+                std::cerr << "Invalid binding format " << pixel_local_attachment_formats.name
+                          << ": " << binding_format << "\n";
+                return false;
+            }
+            auto member_index = tint::strconv::ParseUint32(values[0]);
+            if (member_index != tint::Success) {
+                std::cerr << "Invalid member index for " << pixel_local_attachment_formats.name
+                          << ": " << values[0] << "\n";
+                return false;
+            }
+            auto format = values[1];
+            tint::hlsl::writer::PixelLocalOptions::TexelFormat texel_format =
+                tint::hlsl::writer::PixelLocalOptions::TexelFormat::kUndefined;
+            if (format == "R32Sint") {
+                texel_format = tint::hlsl::writer::PixelLocalOptions::TexelFormat::kR32Sint;
+            } else if (format == "R32Uint") {
+                texel_format = tint::hlsl::writer::PixelLocalOptions::TexelFormat::kR32Uint;
+            } else if (format == "R32Float") {
+                texel_format = tint::hlsl::writer::PixelLocalOptions::TexelFormat::kR32Float;
+            } else {
+                std::cerr << "Invalid texel format for " << pixel_local_attachments.name << ": "
+                          << format << "\n";
+                return false;
+            }
+            opts->pixel_local_options.attachment_formats.emplace(member_index.Get(), texel_format);
+        }
+    }
+
+    if (hlsl_shader_model.value.has_value()) {
+        const uint32_t shader_model = *hlsl_shader_model.value;
+        if (shader_model < kMinShaderModelForDXC || shader_model > kMaxSupportedShaderModelForDXC) {
+            std::cerr << "Invalid HLSL shader model: " << shader_model << "\n";
+            return false;
+        }
+        opts->hlsl_shader_model = shader_model;
+    }
 #endif  // TINT_BUILD_HLSL_WRITER
 
+#if TINT_BUILD_HLSL_WRITER || TINT_BUILD_MSL_WRITER
     if (pixel_local_attachments.value.has_value()) {
         auto bindings = tint::Split(*pixel_local_attachments.value, ",");
         for (auto& binding : bindings) {
@@ -623,58 +673,14 @@
                           << values[1] << "\n";
                 return false;
             }
-            opts->pixel_local_options.attachments.emplace(member_index.Get(),
-                                                          attachment_index.Get());
+            opts->pixel_local_attachments.emplace(member_index.Get(), attachment_index.Get());
         }
     }
-
-    if (pixel_local_group_index.value.has_value()) {
-        opts->pixel_local_options.pixel_local_group_index = *pixel_local_group_index.value;
-    }
-
-    if (pixel_local_attachment_formats.value.has_value()) {
-        auto binding_formats = tint::Split(*pixel_local_attachment_formats.value, ",");
-        for (auto& binding_format : binding_formats) {
-            auto values = tint::Split(binding_format, "=");
-            if (values.Length() != 2) {
-                std::cerr << "Invalid binding format " << pixel_local_attachment_formats.name
-                          << ": " << binding_format << "\n";
-                return false;
-            }
-            auto member_index = tint::strconv::ParseUint32(values[0]);
-            if (member_index != tint::Success) {
-                std::cerr << "Invalid member index for " << pixel_local_attachment_formats.name
-                          << ": " << values[0] << "\n";
-                return false;
-            }
-            auto format = values[1];
-            tint::PixelLocalOptions::TexelFormat texel_format =
-                tint::PixelLocalOptions::TexelFormat::kUndefined;
-            if (format == "R32Sint") {
-                texel_format = tint::PixelLocalOptions::TexelFormat::kR32Sint;
-            } else if (format == "R32Uint") {
-                texel_format = tint::PixelLocalOptions::TexelFormat::kR32Uint;
-            } else if (format == "R32Float") {
-                texel_format = tint::PixelLocalOptions::TexelFormat::kR32Float;
-            } else {
-                std::cerr << "Invalid texel format for " << pixel_local_attachments.name << ": "
-                          << format << "\n";
-                return false;
-            }
-            opts->pixel_local_options.attachment_formats.emplace(member_index.Get(), texel_format);
-        }
-    }
-
 #if TINT_BUILD_HLSL_WRITER
-    if (hlsl_shader_model.value.has_value()) {
-        uint32_t shader_model = *hlsl_shader_model.value;
-        if (shader_model < kMinShaderModelForDXC || shader_model > kMaxSupportedShaderModelForDXC) {
-            std::cerr << "Invalid HLSL shader model: " << shader_model << "\n";
-            return false;
-        }
-        opts->hlsl_shader_model = shader_model;
-    }
-#endif  // TINT_BUILD_HLSL_WRITER
+    opts->pixel_local_options.attachments = opts->pixel_local_attachments;
+#endif
+
+#endif
 
     auto files = result.Get();
     if (files.Length() > 1) {
@@ -909,7 +915,7 @@
     tint::msl::writer::Options gen_options;
     gen_options.disable_robustness = !options.enable_robustness;
     gen_options.disable_workgroup_init = options.disable_workgroup_init;
-    gen_options.pixel_local_attachments = options.pixel_local_options.attachments;
+    gen_options.pixel_local_attachments = options.pixel_local_attachments;
     gen_options.bindings = tint::msl::writer::GenerateBindings(*input_program);
     gen_options.array_length_from_uniform.ubo_binding = 30;
 
@@ -1013,7 +1019,7 @@
     gen_options.disable_workgroup_init = options.disable_workgroup_init;
     gen_options.bindings = tint::hlsl::writer::GenerateBindings(program);
     gen_options.root_constant_binding_point = options.hlsl_root_constant_binding_point;
-    gen_options.pixel_local_options = options.pixel_local_options;
+    gen_options.pixel_local = options.pixel_local_options;
     gen_options.polyfill_dot_4x8_packed = options.hlsl_shader_model < kMinShaderModelForDP4aInHLSL;
     gen_options.polyfill_pack_unpack_4x8 =
         options.hlsl_shader_model < kMinShaderModelForPackUnpack4x8InHLSL;
diff --git a/src/tint/lang/hlsl/writer/BUILD.bazel b/src/tint/lang/hlsl/writer/BUILD.bazel
index affbe22..3e6d067 100644
--- a/src/tint/lang/hlsl/writer/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/BUILD.bazel
@@ -48,7 +48,6 @@
   ],
   deps = [
     "//src/tint/api/common",
-    "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/type",
@@ -91,7 +90,6 @@
   ],
   deps = [
     "//src/tint/api/common",
-    "//src/tint/api/options",
     "//src/tint/cmd/bench:bench",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
diff --git a/src/tint/lang/hlsl/writer/BUILD.cmake b/src/tint/lang/hlsl/writer/BUILD.cmake
index 5c44e5f..a5d0ca1 100644
--- a/src/tint/lang/hlsl/writer/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/BUILD.cmake
@@ -54,7 +54,6 @@
 
 tint_target_add_dependencies(tint_lang_hlsl_writer lib
   tint_api_common
-  tint_api_options
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_type
@@ -101,7 +100,6 @@
 
 tint_target_add_dependencies(tint_lang_hlsl_writer_bench bench
   tint_api_common
-  tint_api_options
   tint_cmd_bench_bench
   tint_lang_core
   tint_lang_core_constant
@@ -148,7 +146,6 @@
 
 tint_target_add_dependencies(tint_lang_hlsl_writer_fuzz fuzz
   tint_api_common
-  tint_api_options
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_type
diff --git a/src/tint/lang/hlsl/writer/BUILD.gn b/src/tint/lang/hlsl/writer/BUILD.gn
index 263c7f2..1007bd9 100644
--- a/src/tint/lang/hlsl/writer/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/BUILD.gn
@@ -51,7 +51,6 @@
     ]
     deps = [
       "${tint_src_dir}/api/common",
-      "${tint_src_dir}/api/options",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/lang/core/constant",
       "${tint_src_dir}/lang/core/type",
@@ -93,7 +92,6 @@
       deps = [
         "${tint_src_dir}:google_benchmark",
         "${tint_src_dir}/api/common",
-        "${tint_src_dir}/api/options",
         "${tint_src_dir}/cmd/bench:bench",
         "${tint_src_dir}/lang/core",
         "${tint_src_dir}/lang/core/constant",
@@ -129,7 +127,6 @@
     sources = []
     deps = [
       "${tint_src_dir}/api/common",
-      "${tint_src_dir}/api/options",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/lang/core/constant",
       "${tint_src_dir}/lang/core/type",
diff --git a/src/tint/lang/hlsl/writer/ast_printer/BUILD.bazel b/src/tint/lang/hlsl/writer/ast_printer/BUILD.bazel
index 1fabb37..34380c5 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/ast_printer/BUILD.bazel
@@ -46,7 +46,6 @@
   ],
   deps = [
     "//src/tint/api/common",
-    "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/core/common",
     "//src/tint/lang/core/constant",
@@ -121,7 +120,6 @@
   ],
   deps = [
     "//src/tint/api/common",
-    "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/type",
diff --git a/src/tint/lang/hlsl/writer/ast_printer/BUILD.cmake b/src/tint/lang/hlsl/writer/ast_printer/BUILD.cmake
index 287ed13..63f4fd9 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/ast_printer/BUILD.cmake
@@ -47,7 +47,6 @@
 
 tint_target_add_dependencies(tint_lang_hlsl_writer_ast_printer lib
   tint_api_common
-  tint_api_options
   tint_lang_core
   tint_lang_core_common
   tint_lang_core_constant
@@ -126,7 +125,6 @@
 
 tint_target_add_dependencies(tint_lang_hlsl_writer_ast_printer_test test
   tint_api_common
-  tint_api_options
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_type
diff --git a/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn b/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn
index e11ef65..fc69397 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn
@@ -49,7 +49,6 @@
     ]
     deps = [
       "${tint_src_dir}/api/common",
-      "${tint_src_dir}/api/options",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/lang/core/common",
       "${tint_src_dir}/lang/core/constant",
@@ -123,7 +122,6 @@
       deps = [
         "${tint_src_dir}:gmock_and_gtest",
         "${tint_src_dir}/api/common",
-        "${tint_src_dir}/api/options",
         "${tint_src_dir}/lang/core",
         "${tint_src_dir}/lang/core/constant",
         "${tint_src_dir}/lang/core/type",
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
index 26efc27..4ff4f22 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
@@ -285,10 +285,10 @@
 
     {
         PixelLocal::Config cfg;
-        for (auto it : options.pixel_local_options.attachments) {
+        for (auto it : options.pixel_local.attachments) {
             cfg.pls_member_to_rov_reg.Add(it.first, it.second);
         }
-        for (auto it : options.pixel_local_options.attachment_formats) {
+        for (auto it : options.pixel_local.attachment_formats) {
             core::TexelFormat format = core::TexelFormat::kUndefined;
             switch (it.second) {
                 case PixelLocalOptions::TexelFormat::kR32Sint:
@@ -305,7 +305,7 @@
             }
             cfg.pls_member_to_rov_format.Add(it.first, format);
         }
-        cfg.rov_group_index = options.pixel_local_options.pixel_local_group_index;
+        cfg.rov_group_index = options.pixel_local.group_index;
         data.Add<PixelLocal::Config>(cfg);
         manager.Add<PixelLocal>();
     }
@@ -2366,7 +2366,7 @@
     if (auto* vec = builtin->ReturnType()->As<core::type::Vector>()) {
         width = std::to_string(vec->Width());
     }
-    out << "f16tof32(f32tof16" << "(";
+    out << "f16tof32(f32tof16(";
     if (!EmitExpression(out, expr->args[0])) {
         return false;
     }
diff --git a/src/tint/lang/hlsl/writer/common/BUILD.bazel b/src/tint/lang/hlsl/writer/common/BUILD.bazel
index f03f44a..92cdcb5 100644
--- a/src/tint/lang/hlsl/writer/common/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/common/BUILD.bazel
@@ -48,7 +48,6 @@
   ],
   deps = [
     "//src/tint/api/common",
-    "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/core/common",
     "//src/tint/utils/containers",
@@ -74,7 +73,6 @@
   ],
   deps = [
     "//src/tint/api/common",
-    "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/hlsl/writer/common",
     "//src/tint/utils/containers",
diff --git a/src/tint/lang/hlsl/writer/common/BUILD.cmake b/src/tint/lang/hlsl/writer/common/BUILD.cmake
index 626259d..4f2b0ab 100644
--- a/src/tint/lang/hlsl/writer/common/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/common/BUILD.cmake
@@ -47,7 +47,6 @@
 
 tint_target_add_dependencies(tint_lang_hlsl_writer_common lib
   tint_api_common
-  tint_api_options
   tint_lang_core
   tint_lang_core_common
   tint_utils_containers
@@ -73,7 +72,6 @@
 
 tint_target_add_dependencies(tint_lang_hlsl_writer_common_test test
   tint_api_common
-  tint_api_options
   tint_lang_core
   tint_lang_hlsl_writer_common
   tint_utils_containers
diff --git a/src/tint/lang/hlsl/writer/common/BUILD.gn b/src/tint/lang/hlsl/writer/common/BUILD.gn
index f2c5a09..1e6a5a7 100644
--- a/src/tint/lang/hlsl/writer/common/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/common/BUILD.gn
@@ -51,7 +51,6 @@
   ]
   deps = [
     "${tint_src_dir}/api/common",
-    "${tint_src_dir}/api/options",
     "${tint_src_dir}/lang/core",
     "${tint_src_dir}/lang/core/common",
     "${tint_src_dir}/utils/containers",
@@ -73,7 +72,6 @@
     deps = [
       "${tint_src_dir}:gmock_and_gtest",
       "${tint_src_dir}/api/common",
-      "${tint_src_dir}/api/options",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/lang/hlsl/writer/common",
       "${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/hlsl/writer/common/options.h b/src/tint/lang/hlsl/writer/common/options.h
index d2e9878..b0a072c 100644
--- a/src/tint/lang/hlsl/writer/common/options.h
+++ b/src/tint/lang/hlsl/writer/common/options.h
@@ -34,7 +34,6 @@
 #include <vector>
 
 #include "src/tint/api/common/binding_point.h"
-#include "src/tint/api/options/pixel_local.h"
 #include "src/tint/lang/core/access.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/reflection/reflection.h"
@@ -150,6 +149,28 @@
     TINT_REFLECT(ArrayLengthFromUniformOptions, ubo_binding, bindpoint_to_size_index);
 };
 
+/// Data used to specify pixel local mappings
+struct PixelLocalOptions {
+    /// Index of pixel_local structure member index to attachment index
+    std::unordered_map<uint32_t, uint32_t> attachments;
+
+    /// The supported pixel local storage attachment format
+    enum class TexelFormat : uint8_t {
+        kR32Sint,
+        kR32Uint,
+        kR32Float,
+        kUndefined,
+    };
+    /// Index of pixel_local structure member index to pixel local storage attachment format
+    std::unordered_map<uint32_t, TexelFormat> attachment_formats;
+
+    /// The bind group index of all pixel local storage attachments
+    uint32_t group_index = 0;
+
+    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
+    TINT_REFLECT(PixelLocalOptions, attachments, attachment_formats, group_index);
+};
+
 /// Configuration options used for generating HLSL.
 struct Options {
     /// Constructor
@@ -198,8 +219,8 @@
     /// The bindings
     Bindings bindings;
 
-    /// Options used to deal with pixel local storage variables
-    PixelLocalOptions pixel_local_options = {};
+    /// Pixel local configuration
+    PixelLocalOptions pixel_local;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
     TINT_REFLECT(Options,
@@ -214,9 +235,16 @@
                  interstage_locations,
                  root_constant_binding_point,
                  bindings,
-                 pixel_local_options);
+                 pixel_local);
 };
 
 }  // namespace tint::hlsl::writer
 
+namespace tint {
+
+/// Reflect valid value ranges for the PixelLocalOptions::TexelFormat enum.
+TINT_REFLECT_ENUM_RANGE(hlsl::writer::PixelLocalOptions::TexelFormat, kR32Sint, kR32Float);
+
+}  // namespace tint
+
 #endif  // SRC_TINT_LANG_HLSL_WRITER_COMMON_OPTIONS_H_
diff --git a/src/tint/lang/hlsl/writer/helpers/BUILD.bazel b/src/tint/lang/hlsl/writer/helpers/BUILD.bazel
index 24a3b69..0e475a8 100644
--- a/src/tint/lang/hlsl/writer/helpers/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/helpers/BUILD.bazel
@@ -46,7 +46,6 @@
   ],
   deps = [
     "//src/tint/api/common",
-    "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/type",
diff --git a/src/tint/lang/hlsl/writer/helpers/BUILD.cmake b/src/tint/lang/hlsl/writer/helpers/BUILD.cmake
index 6332974..cd3371f 100644
--- a/src/tint/lang/hlsl/writer/helpers/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/helpers/BUILD.cmake
@@ -45,7 +45,6 @@
 
 tint_target_add_dependencies(tint_lang_hlsl_writer_helpers lib
   tint_api_common
-  tint_api_options
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_type
diff --git a/src/tint/lang/hlsl/writer/helpers/BUILD.gn b/src/tint/lang/hlsl/writer/helpers/BUILD.gn
index 8583f77..dc28b49 100644
--- a/src/tint/lang/hlsl/writer/helpers/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/helpers/BUILD.gn
@@ -45,7 +45,6 @@
   ]
   deps = [
     "${tint_src_dir}/api/common",
-    "${tint_src_dir}/api/options",
     "${tint_src_dir}/lang/core",
     "${tint_src_dir}/lang/core/constant",
     "${tint_src_dir}/lang/core/type",