[spirv-reader] Emit module-scope builtin vars

Bug: tint:3
Change-Id: I47ed2e9ed97fd7c45a5aa060a9a6aeaca88092cd
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/18500
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index c41b005..e843e72 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -28,6 +28,8 @@
 #include "source/opt/type_manager.h"
 #include "source/opt/types.h"
 #include "spirv-tools/libspirv.hpp"
+#include "src/ast/builtin_decoration.h"
+#include "src/ast/decorated_variable.h"
 #include "src/ast/struct.h"
 #include "src/ast/struct_decoration.h"
 #include "src/ast/struct_member.h"
@@ -47,6 +49,7 @@
 #include "src/ast/type/void_type.h"
 #include "src/ast/variable.h"
 #include "src/ast/variable_decl_statement.h"
+#include "src/ast/variable_decoration.h"
 #include "src/type_manager.h"
 
 namespace tint {
@@ -638,7 +641,34 @@
     }
     auto ast_var = std::make_unique<ast::Variable>(
         namer_.GetName(var.result_id()), ast_storage_class, ast_store_type);
-    // TODO(dneto): decorated variables
+
+    std::vector<std::unique_ptr<ast::VariableDecoration>> ast_decorations;
+    for (auto& deco : GetDecorationsFor(var.result_id())) {
+      if (deco.empty()) {
+        return Fail() << "malformed decoration on ID " << var.result_id()
+                      << ": it is empty";
+      }
+      if (deco[0] == SpvDecorationBuiltIn) {
+        if (deco.size() == 1) {
+          return Fail() << "malformed BuiltIn decoration on ID "
+                        << var.result_id() << ": has no operand";
+        }
+        auto ast_builtin =
+            enum_converter_.ToBuiltin(static_cast<SpvBuiltIn>(deco[1]));
+        if (ast_builtin == ast::Builtin::kNone) {
+          return false;
+        }
+        ast_decorations.emplace_back(
+            std::make_unique<ast::BuiltinDecoration>(ast_builtin));
+      }
+    }
+    if (!ast_decorations.empty()) {
+      auto decorated_var =
+          std::make_unique<ast::DecoratedVariable>(std::move(ast_var));
+      decorated_var->set_decorations(std::move(ast_decorations));
+      ast_var = std::move(decorated_var);
+    }
+
     // TODO(dneto): initializers (a.k.a. constructor expression)
     ast_module_.AddGlobalVariable(std::move(ast_var));
   }
diff --git a/src/reader/spirv/parser_impl_module_var_test.cc b/src/reader/spirv/parser_impl_module_var_test.cc
index 1bee187..a3693f6 100644
--- a/src/reader/spirv/parser_impl_module_var_test.cc
+++ b/src/reader/spirv/parser_impl_module_var_test.cc
@@ -121,6 +121,28 @@
   })"));
 }
 
+TEST_F(SpvParserTest, ModuleScopeVar_BuiltinVerteIndex) {
+  auto p = parser(test::Assemble(R"(
+    OpDecorate %52 BuiltIn VertexIndex
+    %uint = OpTypeInt 32 0
+    %ptr = OpTypePointer Input %uint
+    %52 = OpVariable %ptr Input
+  )"));
+
+  EXPECT_TRUE(p->BuildAndParseInternalModule());
+  EXPECT_TRUE(p->error().empty());
+  const auto module_str = p->module().to_str();
+  EXPECT_THAT(module_str, HasSubstr(R"(
+  DecoratedVariable{
+    Decorations{
+      BuiltinDecoration{vertex_idx}
+    }
+    x_52
+    in
+    __u32
+  })"));
+}
+
 }  // namespace
 }  // namespace spirv
 }  // namespace reader