spirv-reader: Refactor decoration-getting for vars

Bug: tint:508
Change-Id: Ib176eb5e0dfdd6901635a9dd627aa9c7316f0a80
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/49301
Commit-Queue: David Neto <dneto@google.com>
Auto-Submit: David Neto <dneto@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 8b58fc3..c8d3c64 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -1365,32 +1365,44 @@
     sc = ast::StorageClass::kNone;
   }
 
+  if (!ConvertDecorationsForVariable(id, &type, &decorations)) {
+    return nullptr;
+  }
+
+  std::string name = namer_.Name(id);
+  return create<ast::Variable>(Source{}, builder_.Symbols().Register(name), sc,
+                               type->Build(builder_), is_const, constructor,
+                               decorations);
+}
+
+bool ParserImpl::ConvertDecorationsForVariable(
+    uint32_t id,
+    const Type** type,
+    ast::DecorationList* decorations) {
   for (auto& deco : GetDecorationsFor(id)) {
     if (deco.empty()) {
-      Fail() << "malformed decoration on ID " << id << ": it is empty";
-      return nullptr;
+      return Fail() << "malformed decoration on ID " << id << ": it is empty";
     }
     if (deco[0] == SpvDecorationBuiltIn) {
       if (deco.size() == 1) {
-        Fail() << "malformed BuiltIn decoration on ID " << id
-               << ": has no operand";
-        return nullptr;
+        return Fail() << "malformed BuiltIn decoration on ID " << id
+                      << ": has no operand";
       }
       const auto spv_builtin = static_cast<SpvBuiltIn>(deco[1]);
       switch (spv_builtin) {
         case SpvBuiltInPointSize:
           special_builtins_[id] = spv_builtin;
-          return nullptr;
+          return false;  // This is not an error
         case SpvBuiltInSampleId:
         case SpvBuiltInVertexIndex:
         case SpvBuiltInInstanceIndex:
           // The SPIR-V variable is likely to be signed (because GLSL
           // requires signed), but WGSL requires unsigned.  Handle specially
           // so we always perform the conversion at load and store.
-          if (auto* forced_type = UnsignedTypeFor(type)) {
+          if (auto* forced_type = UnsignedTypeFor(*type)) {
             // Requires conversion and special handling in code generation.
             special_builtins_[id] = spv_builtin;
-            type = forced_type;
+            *type = forced_type;
           }
           break;
         case SpvBuiltInSampleMask: {
@@ -1404,7 +1416,7 @@
                       "SampleMask must be an array of 1 element.";
           }
           special_builtins_[id] = spv_builtin;
-          type = ty_.U32();
+          *type = ty_.U32();
           break;
         }
         default:
@@ -1412,43 +1424,38 @@
       }
       auto ast_builtin = enum_converter_.ToBuiltin(spv_builtin);
       if (ast_builtin == ast::Builtin::kNone) {
-        return nullptr;
+        // A diagnostic has already been emitted.
+        return false;
       }
-      decorations.emplace_back(
+      decorations->emplace_back(
           create<ast::BuiltinDecoration>(Source{}, ast_builtin));
     }
     if (deco[0] == SpvDecorationLocation) {
       if (deco.size() != 2) {
-        Fail() << "malformed Location decoration on ID " << id
-               << ": requires one literal operand";
-        return nullptr;
+        return Fail() << "malformed Location decoration on ID " << id
+                      << ": requires one literal operand";
       }
-      decorations.emplace_back(
+      decorations->emplace_back(
           create<ast::LocationDecoration>(Source{}, deco[1]));
     }
     if (deco[0] == SpvDecorationDescriptorSet) {
       if (deco.size() == 1) {
-        Fail() << "malformed DescriptorSet decoration on ID " << id
-               << ": has no operand";
-        return nullptr;
+        return Fail() << "malformed DescriptorSet decoration on ID " << id
+                      << ": has no operand";
       }
-      decorations.emplace_back(create<ast::GroupDecoration>(Source{}, deco[1]));
+      decorations->emplace_back(
+          create<ast::GroupDecoration>(Source{}, deco[1]));
     }
     if (deco[0] == SpvDecorationBinding) {
       if (deco.size() == 1) {
-        Fail() << "malformed Binding decoration on ID " << id
-               << ": has no operand";
-        return nullptr;
+        return Fail() << "malformed Binding decoration on ID " << id
+                      << ": has no operand";
       }
-      decorations.emplace_back(
+      decorations->emplace_back(
           create<ast::BindingDecoration>(Source{}, deco[1]));
     }
   }
-
-  std::string name = namer_.Name(id);
-  return create<ast::Variable>(Source{}, builder_.Symbols().Register(name), sc,
-                               type->Build(builder_), is_const, constructor,
-                               decorations);
+  return success();
 }
 
 TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index 683df89..834c1a5 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -200,6 +200,21 @@
   DecorationList GetDecorationsForMember(uint32_t id,
                                          uint32_t member_index) const;
 
+  /// Converts SPIR-V decorations for the variable with the given ID.
+  /// Registers the IDs of variables that require special handling by code
+  /// generation.  If the WGSL type differs from the store type for SPIR-V,
+  /// then the `type` parameter is updated.  Returns false on failure (with
+  /// a diagnostic), or when the variable should not be emitted, e.g. for a
+  /// PointSize builtin.
+  /// @param id the ID of the SPIR-V variable
+  /// @param type the WGSL store type for the variable, which should be
+  /// prepopulatd
+  /// @param ast_decos the decoration list to populate
+  /// @returns false when the variable should not be emitted as a variable
+  bool ConvertDecorationsForVariable(uint32_t id,
+                                     const Type** type,
+                                     ast::DecorationList* ast_decos);
+
   /// Converts a SPIR-V struct member decoration. If the decoration is
   /// recognized but deliberately dropped, then returns nullptr without a
   /// diagnostic. On failure, emits a diagnostic and returns nullptr.