writer: Use semantic info for constant IDs

This enables the backends to emit overridable constants that had no ID
specified in the attribute.

Bug: tint:755
Change-Id: I86587205e065715257f546b546e792a5262562e8
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50842
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index c7a3f26..d76f4f1 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -2689,8 +2689,8 @@
   auto* sem = builder_.Sem().Get(var);
   auto* type = sem->Type();
 
-  if (ast::HasDecoration<ast::OverrideDecoration>(var->decorations())) {
-    auto const_id = var->constant_id();
+  if (sem->IsPipelineConstant()) {
+    auto const_id = sem->ConstantId();
 
     out << "#ifndef WGSL_SPEC_CONSTANT_" << const_id << std::endl;
 
diff --git a/src/writer/hlsl/generator_impl_module_constant_test.cc b/src/writer/hlsl/generator_impl_module_constant_test.cc
index 6680341..6e82c94 100644
--- a/src/writer/hlsl/generator_impl_module_constant_test.cc
+++ b/src/writer/hlsl/generator_impl_module_constant_test.cc
@@ -33,11 +33,10 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant) {
-  auto* var = Const("pos", ty.f32(), Expr(3.0f),
-                    ast::DecorationList{
-                        create<ast::OverrideDecoration>(23),
-                    });
-  WrapInFunction(Decl(var));
+  auto* var = GlobalConst("pos", ty.f32(), Expr(3.0f),
+                          ast::DecorationList{
+                              create<ast::OverrideDecoration>(23),
+                          });
 
   GeneratorImpl& gen = Build();
 
@@ -67,6 +66,33 @@
 )");
 }
 
+TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoId) {
+  auto* a = GlobalConst("a", ty.f32(), Expr(3.0f),
+                        ast::DecorationList{
+                            create<ast::OverrideDecoration>(0),
+                        });
+  auto* b = GlobalConst("b", ty.f32(), Expr(2.0f),
+                        ast::DecorationList{
+                            create<ast::OverrideDecoration>(),
+                        });
+
+  GeneratorImpl& gen = Build();
+
+  ASSERT_TRUE(gen.EmitProgramConstVariable(out, a)) << gen.error();
+  ASSERT_TRUE(gen.EmitProgramConstVariable(out, b)) << gen.error();
+  EXPECT_EQ(result(), R"(#ifndef WGSL_SPEC_CONSTANT_0
+#define WGSL_SPEC_CONSTANT_0 3.0f
+#endif
+static const float a = WGSL_SPEC_CONSTANT_0;
+#undef WGSL_SPEC_CONSTANT_0
+#ifndef WGSL_SPEC_CONSTANT_1
+#define WGSL_SPEC_CONSTANT_1 2.0f
+#endif
+static const float b = WGSL_SPEC_CONSTANT_1;
+#undef WGSL_SPEC_CONSTANT_1
+)");
+}
+
 }  // namespace
 }  // namespace hlsl
 }  // namespace writer
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index afb3c5d..0996127 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -2257,8 +2257,9 @@
     out_ << " " << program_->Symbols().NameFor(var->symbol());
   }
 
-  if (ast::HasDecoration<ast::OverrideDecoration>(var->decorations())) {
-    out_ << " [[function_constant(" << var->constant_id() << ")]]";
+  auto* sem_var = program_->Sem().Get(var);
+  if (sem_var->IsPipelineConstant()) {
+    out_ << " [[function_constant(" << sem_var->ConstantId() << ")]]";
   } else if (var->constructor() != nullptr) {
     out_ << " = ";
     if (!EmitExpression(var->constructor())) {
diff --git a/src/writer/msl/generator_impl_module_constant_test.cc b/src/writer/msl/generator_impl_module_constant_test.cc
index a939ee2..ec70cf5 100644
--- a/src/writer/msl/generator_impl_module_constant_test.cc
+++ b/src/writer/msl/generator_impl_module_constant_test.cc
@@ -23,8 +23,8 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_ModuleConstant) {
-  auto* var = Const("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
-  WrapInFunction(Decl(var));
+  auto* var =
+      GlobalConst("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
 
   GeneratorImpl& gen = Build();
 
@@ -33,11 +33,10 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_SpecConstant) {
-  auto* var = Const("pos", ty.f32(), Expr(3.f),
-                    ast::DecorationList{
-                        create<ast::OverrideDecoration>(23),
-                    });
-  WrapInFunction(Decl(var));
+  auto* var = GlobalConst("pos", ty.f32(), Expr(3.f),
+                          ast::DecorationList{
+                              create<ast::OverrideDecoration>(23),
+                          });
 
   GeneratorImpl& gen = Build();
 
@@ -45,6 +44,25 @@
   EXPECT_EQ(gen.result(), "constant float pos [[function_constant(23)]];\n");
 }
 
+TEST_F(MslGeneratorImplTest, Emit_SpecConstant_NoId) {
+  auto* var_a = GlobalConst("a", ty.f32(), nullptr,
+                            ast::DecorationList{
+                                create<ast::OverrideDecoration>(0),
+                            });
+  auto* var_b = GlobalConst("b", ty.f32(), nullptr,
+                            ast::DecorationList{
+                                create<ast::OverrideDecoration>(),
+                            });
+
+  GeneratorImpl& gen = Build();
+
+  ASSERT_TRUE(gen.EmitProgramConstVariable(var_a)) << gen.error();
+  ASSERT_TRUE(gen.EmitProgramConstVariable(var_b)) << gen.error();
+  EXPECT_EQ(gen.result(), R"(constant float a [[function_constant(0)]];
+constant float b [[function_constant(1)]];
+)");
+}
+
 }  // namespace
 }  // namespace msl
 }  // namespace writer
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 377ed2c..2fd180a 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -1493,9 +1493,10 @@
                                           ast::Literal* lit) {
   ScalarConstant constant;
 
-  if (var && ast::HasDecoration<ast::OverrideDecoration>(var->decorations())) {
+  auto* sem_var = builder_.Sem().Get(var);
+  if (sem_var && sem_var->IsPipelineConstant()) {
     constant.is_spec_op = true;
-    constant.constant_id = var->constant_id();
+    constant.constant_id = sem_var->ConstantId();
   }
 
   if (auto* l = lit->As<ast::BoolLiteral>()) {
diff --git a/src/writer/spirv/builder_global_variable_test.cc b/src/writer/spirv/builder_global_variable_test.cc
index 79b8d5c..d3db49f 100644
--- a/src/writer/spirv/builder_global_variable_test.cc
+++ b/src/writer/spirv/builder_global_variable_test.cc
@@ -311,6 +311,32 @@
 )");
 }
 
+TEST_F(BuilderTest, GlobalVar_Override_NoId) {
+  auto* var_a = GlobalConst("a", ty.bool_(), Expr(true),
+                            ast::DecorationList{
+                                create<ast::OverrideDecoration>(0),
+                            });
+  auto* var_b = GlobalConst("b", ty.bool_(), Expr(false),
+                            ast::DecorationList{
+                                create<ast::OverrideDecoration>(),
+                            });
+
+  spirv::Builder& b = Build();
+
+  EXPECT_TRUE(b.GenerateGlobalVariable(var_a)) << b.error();
+  EXPECT_TRUE(b.GenerateGlobalVariable(var_b)) << b.error();
+  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "a"
+OpName %3 "b"
+)");
+  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
+OpDecorate %3 SpecId 1
+)");
+  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+%2 = OpSpecConstantTrue %1
+%3 = OpSpecConstantFalse %1
+)");
+}
+
 struct BuiltinData {
   ast::Builtin builtin;
   ast::StorageClass storage;
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index a5be99d..7317829 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -609,7 +609,10 @@
     } else if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
       out_ << "builtin(" << builtin->value() << ")";
     } else if (auto* override_deco = deco->As<ast::OverrideDecoration>()) {
-      out_ << "override(" << override_deco->value() << ")";
+      out_ << "override";
+      if (override_deco->HasValue()) {
+        out_ << "(" << override_deco->value() << ")";
+      }
     } else if (auto* size = deco->As<ast::StructMemberSizeDecoration>()) {
       out_ << "size(" << size->size() << ")";
     } else if (auto* align = deco->As<ast::StructMemberAlignDecoration>()) {
diff --git a/src/writer/wgsl/generator_impl_global_decl_test.cc b/src/writer/wgsl/generator_impl_global_decl_test.cc
index 4a91097..e9cceca 100644
--- a/src/writer/wgsl/generator_impl_global_decl_test.cc
+++ b/src/writer/wgsl/generator_impl_global_decl_test.cc
@@ -129,6 +129,21 @@
       "  [[group(0), binding(0)]] var t : [[access(read)]] texture_1d<f32>;\n");
 }
 
+TEST_F(WgslGeneratorImplTest, Emit_OverridableConstants) {
+  GlobalConst("a", ty.f32(), nullptr, {Override()});
+  GlobalConst("b", ty.f32(), nullptr, {Override(7u)});
+
+  GeneratorImpl& gen = Build();
+
+  gen.increment_indent();
+
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_EQ(gen.result(), R"(  [[override]] let a : f32;
+
+  [[override(7)]] let b : f32;
+)");
+}
+
 }  // namespace
 }  // namespace wgsl
 }  // namespace writer