Rename builtin(sample_mask_{in,out}) to builtin(sample_mask)

Removes the need to pass the storage class to the SPIR-V reader
builtin mapping function.

Added a deprecation warning for sample_mask_{in,out}.

Bug: tint:715
Change-Id: I948ff2de2d5de7bd05e1c6ff45bd721c856900e3
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/47743
Commit-Queue: James Price <jrprice@google.com>
Auto-Submit: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/ast/builtin.cc b/src/ast/builtin.cc
index 03a689e..3dac5cd 100644
--- a/src/ast/builtin.cc
+++ b/src/ast/builtin.cc
@@ -63,6 +63,10 @@
       out << "sample_index";
       break;
     }
+    case Builtin::kSampleMask: {
+      out << "sample_mask";
+      break;
+    }
     case Builtin::kSampleMaskIn: {
       out << "sample_mask_in";
       break;
diff --git a/src/ast/builtin.h b/src/ast/builtin.h
index 3806e44..e065d69 100644
--- a/src/ast/builtin.h
+++ b/src/ast/builtin.h
@@ -33,8 +33,9 @@
   kLocalInvocationIndex,
   kGlobalInvocationId,
   kSampleIndex,
-  kSampleMaskIn,
-  kSampleMaskOut,
+  kSampleMask,
+  kSampleMaskIn,   // TODO(crbug.com/tint/715): Remove this
+  kSampleMaskOut,  // TODO(crbug.com/tint/715): Remove this
 
   // Below are not currently WGSL builtins, but are included in this enum as
   // they are used by certain backends.
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index e88edbc..2155563 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -1041,7 +1041,7 @@
   auto* in_var1 = Param("in_var1", ty.u32(), {Location(0u)});
   Func("foo", {in_var0, in_var1}, ty.u32(), {Return(Expr("in_var1"))},
        {Stage(ast::PipelineStage::kFragment)},
-       {Builtin(ast::Builtin::kSampleMaskOut)});
+       {Builtin(ast::Builtin::kSampleMask)});
   Inspector& inspector = Build();
 
   auto result = inspector.GetEntryPoints();
diff --git a/src/reader/spirv/enum_converter.cc b/src/reader/spirv/enum_converter.cc
index 15491eb..364b596 100644
--- a/src/reader/spirv/enum_converter.cc
+++ b/src/reader/spirv/enum_converter.cc
@@ -66,7 +66,7 @@
   return ast::StorageClass::kNone;
 }
 
-ast::Builtin EnumConverter::ToBuiltin(SpvBuiltIn b, ast::StorageClass sc) {
+ast::Builtin EnumConverter::ToBuiltin(SpvBuiltIn b) {
   switch (b) {
     case SpvBuiltInPosition:
       return ast::Builtin::kPosition;
@@ -89,8 +89,7 @@
     case SpvBuiltInSampleId:
       return ast::Builtin::kSampleIndex;
     case SpvBuiltInSampleMask:
-      return sc == ast::StorageClass::kInput ? ast::Builtin::kSampleMaskIn
-                                             : ast::Builtin::kSampleMaskOut;
+      return ast::Builtin::kSampleMask;
     default:
       break;
   }
diff --git a/src/reader/spirv/enum_converter.h b/src/reader/spirv/enum_converter.h
index 7c9d4f7..5831a88 100644
--- a/src/reader/spirv/enum_converter.h
+++ b/src/reader/spirv/enum_converter.h
@@ -50,9 +50,8 @@
   /// Converts a SPIR-V Builtin value a Tint Builtin.
   /// On failure, logs an error and returns kNone
   /// @param b the SPIR-V builtin
-  /// @param sc the Tint storage class
   /// @returns a Tint AST builtin
-  ast::Builtin ToBuiltin(SpvBuiltIn b, ast::StorageClass sc);
+  ast::Builtin ToBuiltin(SpvBuiltIn b);
 
   /// Converts a possibly arrayed SPIR-V Dim to a Tint texture dimension.
   /// On failure, logs an error and returns kNone
diff --git a/src/reader/spirv/enum_converter_test.cc b/src/reader/spirv/enum_converter_test.cc
index 7011216..58e6924 100644
--- a/src/reader/spirv/enum_converter_test.cc
+++ b/src/reader/spirv/enum_converter_test.cc
@@ -162,12 +162,11 @@
 
 struct BuiltinCase {
   SpvBuiltIn builtin;
-  ast::StorageClass sc;
   bool expect_success;
   ast::Builtin expected;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinCase bc) {
-  out << "BuiltinCase{ SpvBuiltIn:" << int(bc.builtin) << " sc:" << int(bc.sc)
+  out << "BuiltinCase{ SpvBuiltIn:" << int(bc.builtin)
       << " expect_success?:" << int(bc.expect_success)
       << " expected:" << int(bc.expected) << "}";
   return out;
@@ -192,7 +191,7 @@
 TEST_P(SpvBuiltinTest, Samples) {
   const auto params = GetParam();
 
-  const auto result = converter_.ToBuiltin(params.builtin, params.sc);
+  const auto result = converter_.ToBuiltin(params.builtin);
   EXPECT_EQ(success_, params.expect_success);
   if (params.expect_success) {
     EXPECT_EQ(result, params.expected);
@@ -207,46 +206,35 @@
     EnumConverterGood_Input,
     SpvBuiltinTest,
     testing::Values(
-        BuiltinCase{SpvBuiltInPosition, ast::StorageClass::kInput, true,
-                    ast::Builtin::kPosition},
-        BuiltinCase{SpvBuiltInInstanceIndex, ast::StorageClass::kInput, true,
+        BuiltinCase{SpvBuiltInPosition, true, ast::Builtin::kPosition},
+        BuiltinCase{SpvBuiltInInstanceIndex, true,
                     ast::Builtin::kInstanceIndex},
-        BuiltinCase{SpvBuiltInFrontFacing, ast::StorageClass::kInput, true,
-                    ast::Builtin::kFrontFacing},
-        BuiltinCase{SpvBuiltInFragCoord, ast::StorageClass::kInput, true,
-                    ast::Builtin::kPosition},
-        BuiltinCase{SpvBuiltInLocalInvocationId, ast::StorageClass::kInput,
-                    true, ast::Builtin::kLocalInvocationId},
-        BuiltinCase{SpvBuiltInLocalInvocationIndex, ast::StorageClass::kInput,
-                    true, ast::Builtin::kLocalInvocationIndex},
-        BuiltinCase{SpvBuiltInGlobalInvocationId, ast::StorageClass::kInput,
-                    true, ast::Builtin::kGlobalInvocationId},
-        BuiltinCase{SpvBuiltInSampleId, ast::StorageClass::kInput, true,
-                    ast::Builtin::kSampleIndex},
-        BuiltinCase{SpvBuiltInSampleMask, ast::StorageClass::kInput, true,
-                    ast::Builtin::kSampleMaskIn}));
+        BuiltinCase{SpvBuiltInFrontFacing, true, ast::Builtin::kFrontFacing},
+        BuiltinCase{SpvBuiltInFragCoord, true, ast::Builtin::kPosition},
+        BuiltinCase{SpvBuiltInLocalInvocationId, true,
+                    ast::Builtin::kLocalInvocationId},
+        BuiltinCase{SpvBuiltInLocalInvocationIndex, true,
+                    ast::Builtin::kLocalInvocationIndex},
+        BuiltinCase{SpvBuiltInGlobalInvocationId, true,
+                    ast::Builtin::kGlobalInvocationId},
+        BuiltinCase{SpvBuiltInSampleId, true, ast::Builtin::kSampleIndex},
+        BuiltinCase{SpvBuiltInSampleMask, true, ast::Builtin::kSampleMask}));
 
 INSTANTIATE_TEST_SUITE_P(
     EnumConverterGood_Output,
     SpvBuiltinTest,
-    testing::Values(BuiltinCase{SpvBuiltInPosition, ast::StorageClass::kOutput,
-                                true, ast::Builtin::kPosition},
-                    BuiltinCase{SpvBuiltInFragDepth, ast::StorageClass::kOutput,
-                                true, ast::Builtin::kFragDepth},
-                    BuiltinCase{SpvBuiltInSampleMask,
-                                ast::StorageClass::kOutput, true,
-                                ast::Builtin::kSampleMaskOut}));
+    testing::Values(
+        BuiltinCase{SpvBuiltInPosition, true, ast::Builtin::kPosition},
+        BuiltinCase{SpvBuiltInFragDepth, true, ast::Builtin::kFragDepth},
+        BuiltinCase{SpvBuiltInSampleMask, true, ast::Builtin::kSampleMask}));
 
 INSTANTIATE_TEST_SUITE_P(
     EnumConverterBad,
     SpvBuiltinTest,
     testing::Values(
-        BuiltinCase{static_cast<SpvBuiltIn>(9999), ast::StorageClass::kInput,
-                    false, ast::Builtin::kNone},
-        BuiltinCase{static_cast<SpvBuiltIn>(9999), ast::StorageClass::kOutput,
-                    false, ast::Builtin::kNone},
-        BuiltinCase{SpvBuiltInNumWorkgroups, ast::StorageClass::kInput, false,
-                    ast::Builtin::kNone}));
+        BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::Builtin::kNone},
+        BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::Builtin::kNone},
+        BuiltinCase{SpvBuiltInNumWorkgroups, false, ast::Builtin::kNone}));
 
 // Dim
 
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index b5c6eab..fd3ada4 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -1304,7 +1304,7 @@
         default:
           break;
       }
-      auto ast_builtin = enum_converter_.ToBuiltin(spv_builtin, sc);
+      auto ast_builtin = enum_converter_.ToBuiltin(spv_builtin);
       if (ast_builtin == ast::Builtin::kNone) {
         return nullptr;
       }
diff --git a/src/reader/spirv/parser_impl_module_var_test.cc b/src/reader/spirv/parser_impl_module_var_test.cc
index 3af4662..b70bdef 100644
--- a/src/reader/spirv/parser_impl_module_var_test.cc
+++ b/src/reader/spirv/parser_impl_module_var_test.cc
@@ -2473,7 +2473,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_in}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     in
@@ -2515,7 +2515,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_in}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     in
@@ -2557,7 +2557,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_in}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     in
@@ -2598,7 +2598,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_in}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     in
@@ -2643,7 +2643,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_in}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     in
@@ -2688,7 +2688,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_in}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     in
@@ -2751,7 +2751,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_out}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     out
@@ -2787,7 +2787,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_out}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     out
@@ -2823,7 +2823,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_out}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     out
@@ -2858,7 +2858,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_out}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     out
@@ -2900,7 +2900,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_out}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     out
@@ -2942,7 +2942,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(
   Variable{
     Decorations{
-      BuiltinDecoration{sample_mask_out}
+      BuiltinDecoration{sample_mask}
     }
     x_1
     out
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 923053c..dd0b884 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -88,6 +88,9 @@
   if (str == "sample_index") {
     return ast::Builtin::kSampleIndex;
   }
+  if (str == "sample_mask") {
+    return ast::Builtin::kSampleMask;
+  }
   if (str == "sample_mask_in") {
     return ast::Builtin::kSampleMaskIn;
   }
@@ -1382,6 +1385,12 @@
   if (builtin == ast::Builtin::kFragCoord) {
     deprecated(ident.source, "use 'position' instead of 'frag_coord'");
   }
+  if (builtin == ast::Builtin::kSampleMaskIn) {
+    deprecated(ident.source, "use 'sample_mask' instead of 'sample_mask_in'");
+  }
+  if (builtin == ast::Builtin::kSampleMaskOut) {
+    deprecated(ident.source, "use 'sample_mask' instead of 'sample_mask_out'");
+  }
 
   return {builtin, ident.source};
 }
diff --git a/src/reader/wgsl/parser_impl_variable_decoration_test.cc b/src/reader/wgsl/parser_impl_variable_decoration_test.cc
index ea44069..9430cf1 100644
--- a/src/reader/wgsl/parser_impl_variable_decoration_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_decoration_test.cc
@@ -122,6 +122,7 @@
                     ast::Builtin::kLocalInvocationIndex},
         BuiltinData{"global_invocation_id", ast::Builtin::kGlobalInvocationId},
         BuiltinData{"sample_index", ast::Builtin::kSampleIndex},
+        BuiltinData{"sample_mask", ast::Builtin::kSampleMask},
         BuiltinData{"sample_mask_in", ast::Builtin::kSampleMaskIn},
         BuiltinData{"sample_mask_out", ast::Builtin::kSampleMaskOut}));
 
@@ -327,6 +328,50 @@
 )");
 }
 
+TEST_F(ParserImplTest, Decoration_SampleMaskIn_Deprecated) {
+  auto p = parser("builtin(sample_mask_in)");
+  auto deco = p->decoration();
+  EXPECT_TRUE(deco.matched);
+  EXPECT_FALSE(deco.errored);
+  ASSERT_NE(deco.value, nullptr);
+  auto* var_deco = deco.value->As<ast::Decoration>();
+  ASSERT_NE(var_deco, nullptr);
+  ASSERT_FALSE(p->has_error());
+  ASSERT_TRUE(var_deco->Is<ast::BuiltinDecoration>());
+
+  auto* builtin = var_deco->As<ast::BuiltinDecoration>();
+  EXPECT_EQ(builtin->value(), ast::Builtin::kSampleMaskIn);
+
+  EXPECT_EQ(
+      p->builder().Diagnostics().str(),
+      R"(test.wgsl:1:9 warning: use of deprecated language feature: use 'sample_mask' instead of 'sample_mask_in'
+builtin(sample_mask_in)
+        ^^^^^^^^^^^^^^
+)");
+}
+
+TEST_F(ParserImplTest, Decoration_SampleMaskOut_Deprecated) {
+  auto p = parser("builtin(sample_mask_out)");
+  auto deco = p->decoration();
+  EXPECT_TRUE(deco.matched);
+  EXPECT_FALSE(deco.errored);
+  ASSERT_NE(deco.value, nullptr);
+  auto* var_deco = deco.value->As<ast::Decoration>();
+  ASSERT_NE(var_deco, nullptr);
+  ASSERT_FALSE(p->has_error());
+  ASSERT_TRUE(var_deco->Is<ast::BuiltinDecoration>());
+
+  auto* builtin = var_deco->As<ast::BuiltinDecoration>();
+  EXPECT_EQ(builtin->value(), ast::Builtin::kSampleMaskOut);
+
+  EXPECT_EQ(
+      p->builder().Diagnostics().str(),
+      R"(test.wgsl:1:9 warning: use of deprecated language feature: use 'sample_mask' instead of 'sample_mask_out'
+builtin(sample_mask_out)
+        ^^^^^^^^^^^^^^^
+)");
+}
+
 }  // namespace
 }  // namespace wgsl
 }  // namespace reader
diff --git a/src/transform/canonicalize_entry_point_io_test.cc b/src/transform/canonicalize_entry_point_io_test.cc
index 923a06f..a7e4bf7 100644
--- a/src/transform/canonicalize_entry_point_io_test.cc
+++ b/src/transform/canonicalize_entry_point_io_test.cc
@@ -197,7 +197,7 @@
   auto* src = R"(
 struct FragOutput {
   [[builtin(frag_depth)]] depth : f32;
-  [[builtin(sample_mask_out)]] mask : u32;
+  [[builtin(sample_mask)]] mask : u32;
   [[location(0)]] color : vec4<f32>;
 };
 
@@ -221,7 +221,7 @@
 struct tint_symbol {
   [[builtin(frag_depth)]]
   depth : f32;
-  [[builtin(sample_mask_out)]]
+  [[builtin(sample_mask)]]
   mask : u32;
   [[location(0)]]
   color : vec4<f32>;
diff --git a/src/transform/spirv.cc b/src/transform/spirv.cc
index 4e0bed9..2d651e1 100644
--- a/src/transform/spirv.cc
+++ b/src/transform/spirv.cc
@@ -59,11 +59,11 @@
   // ```
   // struct FragmentInput {
   //   [[builtin(sample_index)]] sample_index : u32;
-  //   [[builtin(sample_mask_in)]] sample_mask_in : u32;
+  //   [[builtin(sample_mask)]] sample_mask : u32;
   // };
   // struct FragmentOutput {
   //   [[builtin(frag_depth)]] depth: f32;
-  //   [[builtin(sample_mask_out)]] mask_out : u32;
+  //   [[builtin(sample_mask)]] mask_out : u32;
   // };
   //
   // [[stage(fragment)]]
@@ -72,7 +72,7 @@
   //   samples : FragmentInput
   // ) -> FragmentOutput {
   //   var output : FragmentOutput = FragmentOutput(1.0,
-  //                                                samples.sample_mask_in);
+  //                                                samples.sample_mask);
   //   return output;
   // }
   // ```
@@ -81,7 +81,7 @@
   // ```
   // struct FragmentInput {
   //   sample_index : u32;
-  //   sample_mask_in : u32;
+  //   sample_mask : u32;
   // };
   // struct FragmentOutput {
   //   depth: f32;
@@ -90,9 +90,9 @@
   //
   // [[builtin(position)]] var<in> coord : vec4<f32>,
   // [[builtin(sample_index)]] var<in> sample_index : u32,
-  // [[builtin(sample_mask_in)]] var<in> sample_mask_in : u32,
+  // [[builtin(sample_mask)]] var<in> sample_mask : u32,
   // [[builtin(frag_depth)]] var<out> depth: f32;
-  // [[builtin(sample_mask_out)]] var<out> mask_out : u32;
+  // [[builtin(sample_mask)]] var<out> mask_out : u32;
   //
   // fn frag_main_ret(retval : FragmentOutput) {
   //   depth = reval.depth;
@@ -101,9 +101,9 @@
   //
   // [[stage(fragment)]]
   // fn frag_main() {
-  //   let samples : FragmentInput(sample_index, sample_mask_in);
+  //   let samples : FragmentInput(sample_index, sample_mask);
   //   var output : FragmentOutput = FragmentOutput(1.0,
-  //                                                samples.sample_mask_in);
+  //                                                samples.sample_mask);
   //   frag_main_ret(output);
   //   return;
   // }
@@ -189,19 +189,19 @@
 }
 
 void Spirv::HandleSampleMaskBuiltins(CloneContext& ctx) const {
-  // Find global variables decorated with [[builtin(sample_mask_{in,out})]] and
+  // Find global variables decorated with [[builtin(sample_mask)]] and
   // change their type from `u32` to `array<u32, 1>`, as required by Vulkan.
   //
   // Before:
   // ```
-  // [[builtin(sample_mask_out)]] var<out> mask_out : u32;
+  // [[builtin(sample_mask)]] var<out> mask_out : u32;
   // fn main() {
   //   mask_out = 1u;
   // }
   // ```
   // After:
   // ```
-  // [[builtin(sample_mask_out)]] var<out> mask_out : array<u32, 1>;
+  // [[builtin(sample_mask)]] var<out> mask_out : array<u32, 1>;
   // fn main() {
   //   mask_out[0] = 1u;
   // }
@@ -210,7 +210,8 @@
   for (auto* var : ctx.src->AST().GlobalVariables()) {
     for (auto* deco : var->decorations()) {
       if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
-        if (builtin->value() != ast::Builtin::kSampleMaskIn &&
+        if (builtin->value() != ast::Builtin::kSampleMask &&
+            builtin->value() != ast::Builtin::kSampleMaskIn &&
             builtin->value() != ast::Builtin::kSampleMaskOut) {
           continue;
         }
diff --git a/src/transform/spirv_test.cc b/src/transform/spirv_test.cc
index 45e0128..240fae3 100644
--- a/src/transform/spirv_test.cc
+++ b/src/transform/spirv_test.cc
@@ -487,9 +487,9 @@
   auto* src = R"(
 [[builtin(sample_index)]] var<in> sample_index : u32;
 
-[[builtin(sample_mask_in)]] var<in> mask_in : u32;
+[[builtin(sample_mask)]] var<in> mask_in : u32;
 
-[[builtin(sample_mask_out)]] var<out> mask_out : u32;
+[[builtin(sample_mask)]] var<out> mask_out : u32;
 
 [[stage(fragment)]]
 fn main() {
@@ -500,9 +500,9 @@
   auto* expect = R"(
 [[builtin(sample_index)]] var<in> sample_index : u32;
 
-[[builtin(sample_mask_in)]] var<in> mask_in : array<u32, 1>;
+[[builtin(sample_mask)]] var<in> mask_in : array<u32, 1>;
 
-[[builtin(sample_mask_out)]] var<out> mask_out : array<u32, 1>;
+[[builtin(sample_mask)]] var<out> mask_out : array<u32, 1>;
 
 [[stage(fragment)]]
 fn main() {
@@ -517,9 +517,9 @@
 
 TEST_F(SpirvTest, HandleSampleMaskBuiltins_FunctionArg) {
   auto* src = R"(
-[[builtin(sample_mask_in)]] var<in> mask_in : u32;
+[[builtin(sample_mask)]] var<in> mask_in : u32;
 
-[[builtin(sample_mask_out)]] var<out> mask_out : u32;
+[[builtin(sample_mask)]] var<out> mask_out : u32;
 
 fn filter(mask: u32) -> u32 {
   return (mask & 3u);
@@ -536,9 +536,9 @@
 )";
 
   auto* expect = R"(
-[[builtin(sample_mask_in)]] var<in> mask_in : array<u32, 1>;
+[[builtin(sample_mask)]] var<in> mask_in : array<u32, 1>;
 
-[[builtin(sample_mask_out)]] var<out> mask_out : array<u32, 1>;
+[[builtin(sample_mask)]] var<out> mask_out : array<u32, 1>;
 
 fn filter(mask : u32) -> u32 {
   return (mask & 3u);
@@ -578,8 +578,8 @@
   auto* src = R"(
 [[stage(fragment)]]
 fn main([[builtin(sample_index)]] sample_index : u32,
-        [[builtin(sample_mask_in)]] mask_in : u32)
-        -> [[builtin(sample_mask_out)]] u32 {
+        [[builtin(sample_mask)]] mask_in : u32)
+        -> [[builtin(sample_mask)]] u32 {
   return mask_in;
 }
 )";
@@ -587,9 +587,9 @@
   auto* expect = R"(
 [[builtin(sample_index)]] var<in> tint_symbol : u32;
 
-[[builtin(sample_mask_in)]] var<in> tint_symbol_1 : array<u32, 1>;
+[[builtin(sample_mask)]] var<in> tint_symbol_1 : array<u32, 1>;
 
-[[builtin(sample_mask_out)]] var<out> tint_symbol_3 : array<u32, 1>;
+[[builtin(sample_mask)]] var<out> tint_symbol_3 : array<u32, 1>;
 
 fn tint_symbol_4(tint_symbol_2 : u32) {
   tint_symbol_3[0] = tint_symbol_2;
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 3738d69..a647585 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -1954,6 +1954,8 @@
       return "SV_DispatchThreadID";
     case ast::Builtin::kSampleIndex:
       return "SV_SampleIndex";
+    case ast::Builtin::kSampleMask:
+      return "SV_Coverage";
     case ast::Builtin::kSampleMaskIn:
       return "SV_Coverage";
     case ast::Builtin::kSampleMaskOut:
diff --git a/src/writer/hlsl/generator_impl_test.cc b/src/writer/hlsl/generator_impl_test.cc
index 773c1de..908c49f 100644
--- a/src/writer/hlsl/generator_impl_test.cc
+++ b/src/writer/hlsl/generator_impl_test.cc
@@ -83,6 +83,7 @@
         HlslBuiltinData{ast::Builtin::kGlobalInvocationId,
                         "SV_DispatchThreadID"},
         HlslBuiltinData{ast::Builtin::kSampleIndex, "SV_SampleIndex"},
+        HlslBuiltinData{ast::Builtin::kSampleMask, "SV_Coverage"},
         HlslBuiltinData{ast::Builtin::kSampleMaskIn, "SV_Coverage"},
         HlslBuiltinData{ast::Builtin::kSampleMaskOut, "SV_Coverage"}));
 
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index ddee33e..ea53d7d 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -1354,6 +1354,8 @@
       return "thread_position_in_grid";
     case ast::Builtin::kSampleIndex:
       return "sample_id";
+    case ast::Builtin::kSampleMask:
+      return "sample_mask";
     case ast::Builtin::kSampleMaskIn:
       return "sample_mask";
     case ast::Builtin::kSampleMaskOut:
diff --git a/src/writer/msl/generator_impl_test.cc b/src/writer/msl/generator_impl_test.cc
index 1fa7776..bc2ee55 100644
--- a/src/writer/msl/generator_impl_test.cc
+++ b/src/writer/msl/generator_impl_test.cc
@@ -74,6 +74,7 @@
                     MslBuiltinData{ast::Builtin::kGlobalInvocationId,
                                    "thread_position_in_grid"},
                     MslBuiltinData{ast::Builtin::kSampleIndex, "sample_id"},
+                    MslBuiltinData{ast::Builtin::kSampleMask, "sample_mask"},
                     MslBuiltinData{ast::Builtin::kSampleMaskIn, "sample_mask"},
                     MslBuiltinData{ast::Builtin::kSampleMaskOut,
                                    "sample_mask"}));
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 50278ca..4c8187b 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -3308,6 +3308,8 @@
     case ast::Builtin::kSampleIndex:
       push_capability(SpvCapabilitySampleRateShading);
       return SpvBuiltInSampleId;
+    case ast::Builtin::kSampleMask:
+      return SpvBuiltInSampleMask;
     case ast::Builtin::kSampleMaskIn:
       return SpvBuiltInSampleMask;
     case ast::Builtin::kSampleMaskOut:
diff --git a/src/writer/spirv/builder_global_variable_test.cc b/src/writer/spirv/builder_global_variable_test.cc
index 3b63687..b6bf64c 100644
--- a/src/writer/spirv/builder_global_variable_test.cc
+++ b/src/writer/spirv/builder_global_variable_test.cc
@@ -370,6 +370,10 @@
                     ast::StorageClass::kInput, SpvBuiltInGlobalInvocationId},
         BuiltinData{ast::Builtin::kSampleIndex, ast::StorageClass::kInput,
                     SpvBuiltInSampleId},
+        BuiltinData{ast::Builtin::kSampleMask, ast::StorageClass::kInput,
+                    SpvBuiltInSampleMask},
+        BuiltinData{ast::Builtin::kSampleMask, ast::StorageClass::kOutput,
+                    SpvBuiltInSampleMask},
         BuiltinData{ast::Builtin::kSampleMaskIn, ast::StorageClass::kInput,
                     SpvBuiltInSampleMask},
         BuiltinData{ast::Builtin::kSampleMaskOut, ast::StorageClass::kOutput,
@@ -622,16 +626,16 @@
 
 TEST_F(BuilderTest, SampleMask) {
   // Input:
-  // [[builtin(sample_mask_in)]] var<in> mask_in : u32;
-  // [[builtin(sample_mask_out)]] var<out> mask_out : u32;
+  // [[builtin(sample_mask)]] var<in> mask_in : u32;
+  // [[builtin(sample_mask)]] var<out> mask_out : u32;
   // [[stage(fragment)]]
   // fn main() {
   //   mask_out = mask_in;
   // }
 
   // After sanitization:
-  // [[builtin(sample_mask_in)]] var<in> mask_in : array<u32, 1>;
-  // [[builtin(sample_mask_out)]] var<out> mask_out : array<u32, 1>;
+  // [[builtin(sample_mask)]] var<in> mask_in : array<u32, 1>;
+  // [[builtin(sample_mask)]] var<out> mask_out : array<u32, 1>;
   // [[stage(fragment)]]
   // fn main() {
   //   mask_out[0] = mask_in[0];
@@ -639,11 +643,11 @@
 
   Global("mask_in", ty.u32(), ast::StorageClass::kInput, nullptr,
          ast::DecorationList{
-             create<ast::BuiltinDecoration>(ast::Builtin::kSampleMaskIn),
+             create<ast::BuiltinDecoration>(ast::Builtin::kSampleMask),
          });
   Global("mask_out", ty.u32(), ast::StorageClass::kOutput, nullptr,
          ast::DecorationList{
-             create<ast::BuiltinDecoration>(ast::Builtin::kSampleMaskOut),
+             create<ast::BuiltinDecoration>(ast::Builtin::kSampleMask),
          });
   Func("main", ast::VariableList{}, ty.void_(),
        ast::StatementList{