src/sem: Generate ParameterUsage from intrinsics.def

Add a template file to generate parameter_usage.h and
parameter_usage.cc when using tools/intrinsic-gen

Bug: tint:832
Change-Id: I0ca4d092fdcda7d7846b968d43202f34450e516d
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/52644
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/BUILD.gn b/src/BUILD.gn
index aa4e735..c0dce94 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -471,6 +471,8 @@
     "sem/multisampled_texture_type.cc",
     "sem/multisampled_texture_type.h",
     "sem/node.h",
+    "sem/parameter_usage.cc",
+    "sem/parameter_usage.h",
     "sem/pointer_type.cc",
     "sem/pointer_type.h",
     "sem/reference_type.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1b1bd36..cc9905b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -251,6 +251,8 @@
   sem/intrinsic.cc
   sem/intrinsic.h
   sem/member_accessor_expression.cc
+  sem/parameter_usage.cc
+  sem/parameter_usage.h
   sem/node.cc
   sem/node.h
   sem/statement.cc
diff --git a/src/intrinsic_table.cc b/src/intrinsic_table.cc
index bbdc9b4..7dd0984 100644
--- a/src/intrinsic_table.cc
+++ b/src/intrinsic_table.cc
@@ -665,10 +665,10 @@
     Parameter(
         Builder* m)  // NOLINT - implicit constructor required for Register()
         : matcher(m) {}
-    Parameter(sem::Parameter::Usage u, Builder* m) : matcher(m), usage(u) {}
+    Parameter(sem::ParameterUsage u, Builder* m) : matcher(m), usage(u) {}
 
     Builder* const matcher;
-    sem::Parameter::Usage const usage = sem::Parameter::Usage::kNone;
+    sem::ParameterUsage const usage = sem::ParameterUsage::kNone;
   };
 
   /// A single overload definition.
@@ -1145,18 +1145,18 @@
   auto* sampler = this->sampler(ast::SamplerKind::kSampler);
   auto* sampler_comparison =
       this->sampler(ast::SamplerKind::kComparisonSampler);
-  auto t = sem::Parameter::Usage::kTexture;
-  auto s = sem::Parameter::Usage::kSampler;
-  auto coords = sem::Parameter::Usage::kCoords;
-  auto array_index = sem::Parameter::Usage::kArrayIndex;
-  auto ddx = sem::Parameter::Usage::kDdx;
-  auto ddy = sem::Parameter::Usage::kDdy;
-  auto depth_ref = sem::Parameter::Usage::kDepthRef;
-  auto bias = sem::Parameter::Usage::kBias;
-  auto level = sem::Parameter::Usage::kLevel;
-  auto offset = sem::Parameter::Usage::kOffset;
-  auto value = sem::Parameter::Usage::kValue;
-  auto sample_index = sem::Parameter::Usage::kSampleIndex;
+  auto t = sem::ParameterUsage::kTexture;
+  auto s = sem::ParameterUsage::kSampler;
+  auto coords = sem::ParameterUsage::kCoords;
+  auto array_index = sem::ParameterUsage::kArrayIndex;
+  auto ddx = sem::ParameterUsage::kDdx;
+  auto ddy = sem::ParameterUsage::kDdy;
+  auto depth_ref = sem::ParameterUsage::kDepthRef;
+  auto bias = sem::ParameterUsage::kBias;
+  auto level = sem::ParameterUsage::kLevel;
+  auto offset = sem::ParameterUsage::kOffset;
+  auto value = sem::ParameterUsage::kValue;
+  auto sample_index = sem::ParameterUsage::kSampleIndex;
 
   // clang-format off
 
@@ -1302,7 +1302,7 @@
         ss << ", ";
       }
       first = false;
-      if (param.usage != sem::Parameter::Usage::kNone) {
+      if (param.usage != sem::ParameterUsage::kNone) {
         ss << sem::str(param.usage) << " : ";
       }
       ss << param.matcher->str();
diff --git a/src/intrinsic_table_test.cc b/src/intrinsic_table_test.cc
index df11c66..7a9125f 100644
--- a/src/intrinsic_table_test.cc
+++ b/src/intrinsic_table_test.cc
@@ -31,6 +31,7 @@
 
 using IntrinsicType = sem::IntrinsicType;
 using Parameter = sem::Parameter;
+using ParameterUsage = sem::ParameterUsage;
 
 class IntrinsicTableTest : public testing::Test, public ProgramBuilder {
  public:
@@ -87,9 +88,9 @@
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), vec4_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{i32, Parameter::Usage::kCoords},
-                          Parameter{i32, Parameter::Usage::kLevel}));
+              ElementsAre(Parameter{tex, ParameterUsage::kTexture},
+                          Parameter{i32, ParameterUsage::kCoords},
+                          Parameter{i32, ParameterUsage::kLevel}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchI32) {
@@ -250,9 +251,9 @@
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureSample);
   EXPECT_THAT(result.intrinsic->ReturnType(), vec4_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{sampler, Parameter::Usage::kSampler},
-                          Parameter{vec2_f32, Parameter::Usage::kCoords}));
+              ElementsAre(Parameter{tex, ParameterUsage::kTexture},
+                          Parameter{sampler, ParameterUsage::kSampler},
+                          Parameter{vec2_f32, ParameterUsage::kCoords}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchSampler) {
@@ -278,9 +279,9 @@
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), vec4_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{vec2_i32, Parameter::Usage::kCoords},
-                          Parameter{i32, Parameter::Usage::kLevel}));
+              ElementsAre(Parameter{tex, ParameterUsage::kTexture},
+                          Parameter{vec2_i32, ParameterUsage::kCoords},
+                          Parameter{i32, ParameterUsage::kLevel}));
 }
 
 TEST_F(IntrinsicTableTest, MatchMultisampledTexture) {
@@ -296,9 +297,9 @@
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), vec4_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{vec2_i32, Parameter::Usage::kCoords},
-                          Parameter{i32, Parameter::Usage::kSampleIndex}));
+              ElementsAre(Parameter{tex, ParameterUsage::kTexture},
+                          Parameter{vec2_i32, ParameterUsage::kCoords},
+                          Parameter{i32, ParameterUsage::kSampleIndex}));
 }
 
 TEST_F(IntrinsicTableTest, MatchDepthTexture) {
@@ -313,9 +314,9 @@
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{vec2_i32, Parameter::Usage::kCoords},
-                          Parameter{i32, Parameter::Usage::kLevel}));
+              ElementsAre(Parameter{tex, ParameterUsage::kTexture},
+                          Parameter{vec2_i32, ParameterUsage::kCoords},
+                          Parameter{i32, ParameterUsage::kLevel}));
 }
 
 TEST_F(IntrinsicTableTest, MatchExternalTexture) {
@@ -331,8 +332,8 @@
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), vec4_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{vec2_i32, Parameter::Usage::kCoords}));
+              ElementsAre(Parameter{tex, ParameterUsage::kTexture},
+                          Parameter{vec2_i32, ParameterUsage::kCoords}));
 }
 
 TEST_F(IntrinsicTableTest, MatchROStorageTexture) {
@@ -353,8 +354,8 @@
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), vec4_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{vec2_i32, Parameter::Usage::kCoords}));
+              ElementsAre(Parameter{tex, ParameterUsage::kTexture},
+                          Parameter{vec2_i32, ParameterUsage::kCoords}));
 }
 
 TEST_F(IntrinsicTableTest, MatchWOStorageTexture) {
@@ -375,9 +376,9 @@
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureStore);
   EXPECT_TRUE(result.intrinsic->ReturnType()->Is<sem::Void>());
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{vec2_i32, Parameter::Usage::kCoords},
-                          Parameter{vec4_f32, Parameter::Usage::kValue}));
+              ElementsAre(Parameter{tex, ParameterUsage::kTexture},
+                          Parameter{vec2_i32, ParameterUsage::kCoords},
+                          Parameter{vec4_f32, ParameterUsage::kValue}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchTexture) {
diff --git a/src/sem/call_target.cc b/src/sem/call_target.cc
index e3c87ff..d8c5f49 100644
--- a/src/sem/call_target.cc
+++ b/src/sem/call_target.cc
@@ -28,7 +28,7 @@
 
 CallTarget::~CallTarget() = default;
 
-int IndexOf(const ParameterList& parameters, Parameter::Usage usage) {
+int IndexOf(const ParameterList& parameters, ParameterUsage usage) {
   for (size_t i = 0; i < parameters.size(); i++) {
     if (parameters[i].usage == usage) {
       return static_cast<int>(i);
@@ -37,37 +37,6 @@
   return -1;
 }
 
-const char* str(Parameter::Usage usage) {
-  switch (usage) {
-    case Parameter::Usage::kArrayIndex:
-      return "array_index";
-    case Parameter::Usage::kBias:
-      return "bias";
-    case Parameter::Usage::kCoords:
-      return "coords";
-    case Parameter::Usage::kDepthRef:
-      return "depth_ref";
-    case Parameter::Usage::kDdx:
-      return "ddx";
-    case Parameter::Usage::kDdy:
-      return "ddy";
-    case Parameter::Usage::kLevel:
-      return "level";
-    case Parameter::Usage::kOffset:
-      return "offset";
-    case Parameter::Usage::kSampler:
-      return "sampler";
-    case Parameter::Usage::kSampleIndex:
-      return "sample_index";
-    case Parameter::Usage::kTexture:
-      return "texture";
-    case Parameter::Usage::kValue:
-      return "value";
-    default:
-      return "<unknown>";
-  }
-}
-
 std::ostream& operator<<(std::ostream& out, Parameter parameter) {
   out << "[type: " << parameter.type->FriendlyName(SymbolTable{ProgramID{}})
       << ", usage: " << str(parameter.usage) << "]";
diff --git a/src/sem/call_target.h b/src/sem/call_target.h
index 3b3ed90..520e22c 100644
--- a/src/sem/call_target.h
+++ b/src/sem/call_target.h
@@ -18,6 +18,7 @@
 #include <vector>
 
 #include "src/sem/node.h"
+#include "src/sem/parameter_usage.h"
 #include "src/sem/sampler_type.h"
 
 namespace tint {
@@ -28,28 +29,10 @@
 
 /// Parameter describes a single parameter of a call target
 struct Parameter {
-  /// Usage is extra metadata for identifying a parameter based on its overload
-  /// position
-  enum class Usage {
-    kNone,
-    kArrayIndex,
-    kBias,
-    kCoords,
-    kDepthRef,
-    kDdx,
-    kDdy,
-    kLevel,
-    kOffset,
-    kSampler,
-    kSampleIndex,
-    kTexture,
-    kValue,
-  };
-
   /// Parameter type
   sem::Type* const type;
   /// Parameter usage
-  Usage const usage = Usage::kNone;
+  ParameterUsage const usage = ParameterUsage::kNone;
 };
 
 std::ostream& operator<<(std::ostream& out, Parameter parameter);
@@ -59,9 +42,6 @@
   return a.type == b.type && a.usage == b.usage;
 }
 
-/// @returns a string representation of the given parameter usage.
-const char* str(Parameter::Usage usage);
-
 /// ParameterList is a list of Parameter
 using ParameterList = std::vector<Parameter>;
 
@@ -69,7 +49,7 @@
 /// @param usage the parameter usage to find
 /// @returns the index of the parameter with the given usage, or -1 if no
 /// parameter with the given usage exists.
-int IndexOf(const ParameterList& parameters, Parameter::Usage usage);
+int IndexOf(const ParameterList& parameters, ParameterUsage usage);
 
 /// CallTarget is the base for callable functions
 class CallTarget : public Castable<CallTarget, Node> {
diff --git a/src/sem/function.cc b/src/sem/function.cc
index 511c0a1..fcf192a 100644
--- a/src/sem/function.cc
+++ b/src/sem/function.cc
@@ -33,7 +33,7 @@
   ParameterList parameters;
   parameters.reserve(params.size());
   for (auto* param : params) {
-    parameters.emplace_back(Parameter{param->Type(), Parameter::Usage::kNone});
+    parameters.emplace_back(Parameter{param->Type(), ParameterUsage::kNone});
   }
   return parameters;
 }
diff --git a/src/sem/parameter_usage.cc b/src/sem/parameter_usage.cc
new file mode 100644
index 0000000..9a6263c
--- /dev/null
+++ b/src/sem/parameter_usage.cc
@@ -0,0 +1,58 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/intrinsic-gen
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/sem/parameter_usage.h"
+
+namespace tint {
+namespace sem {
+
+const char* str(ParameterUsage usage) {
+  switch (usage) {
+    case ParameterUsage::kNone:
+      return "none";
+    case ParameterUsage::kArrayIndex:
+      return "array_index";
+    case ParameterUsage::kBias:
+      return "bias";
+    case ParameterUsage::kCoords:
+      return "coords";
+    case ParameterUsage::kDdx:
+      return "ddx";
+    case ParameterUsage::kDdy:
+      return "ddy";
+    case ParameterUsage::kDepthRef:
+      return "depth_ref";
+    case ParameterUsage::kLevel:
+      return "level";
+    case ParameterUsage::kOffset:
+      return "offset";
+    case ParameterUsage::kSampleIndex:
+      return "sample_index";
+    case ParameterUsage::kSampler:
+      return "sampler";
+    case ParameterUsage::kTexture:
+      return "texture";
+    case ParameterUsage::kValue:
+      return "value";
+  }
+  return "<unknown>";
+}
+
+}  // namespace sem
+}  // namespace tint
diff --git a/src/sem/parameter_usage.cc.tmpl b/src/sem/parameter_usage.cc.tmpl
new file mode 100644
index 0000000..7650226
--- /dev/null
+++ b/src/sem/parameter_usage.cc.tmpl
@@ -0,0 +1,29 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/intrinsic-gen to generate parameter_usage.cc
+
+See:
+* tools/cmd/intrinsic-gen/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+#include "src/sem/parameter_usage.h"
+
+namespace tint {
+namespace sem {
+
+const char* str(ParameterUsage usage) {
+  switch (usage) {
+    case ParameterUsage::kNone:
+      return "none";
+{{- range .Sem.UniqueParameterNames  }}
+    case ParameterUsage::k{{PascalCase .}}:
+      return "{{.}}";
+{{- end  }}
+  }
+  return "<unknown>";
+}
+
+}  // namespace sem
+}  // namespace tint
diff --git a/src/sem/parameter_usage.h b/src/sem/parameter_usage.h
new file mode 100644
index 0000000..3c20c76
--- /dev/null
+++ b/src/sem/parameter_usage.h
@@ -0,0 +1,50 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/intrinsic-gen
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_SEM_PARAMETER_USAGE_H_
+#define SRC_SEM_PARAMETER_USAGE_H_
+
+namespace tint {
+namespace sem {
+
+/// ParameterUsage is extra metadata for identifying a parameter based on its
+/// overload position
+enum class ParameterUsage {
+  kNone = -1,
+  kArrayIndex,
+  kBias,
+  kCoords,
+  kDdx,
+  kDdy,
+  kDepthRef,
+  kLevel,
+  kOffset,
+  kSampleIndex,
+  kSampler,
+  kTexture,
+  kValue,
+};
+
+/// @returns a string representation of the given parameter usage.
+const char* str(ParameterUsage usage);
+
+}  // namespace sem
+}  // namespace tint
+
+#endif  // SRC_SEM_PARAMETER_USAGE_H_
diff --git a/src/sem/parameter_usage.h.tmpl b/src/sem/parameter_usage.h.tmpl
new file mode 100644
index 0000000..3110b20
--- /dev/null
+++ b/src/sem/parameter_usage.h.tmpl
@@ -0,0 +1,32 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/intrinsic-gen to generate parameter_usage.h
+
+See:
+* tools/cmd/intrinsic-gen/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+#ifndef SRC_SEM_PARAMETER_USAGE_H_
+#define SRC_SEM_PARAMETER_USAGE_H_
+
+namespace tint {
+namespace sem {
+
+/// ParameterUsage is extra metadata for identifying a parameter based on its
+/// overload position
+enum class ParameterUsage {
+  kNone = -1,
+{{- range .Sem.UniqueParameterNames  }}
+  k{{PascalCase .}},
+{{- end  }}
+};
+
+/// @returns a string representation of the given parameter usage.
+const char* str(ParameterUsage usage);
+
+}  // namespace sem
+}  // namespace tint
+
+#endif  // SRC_SEM_PARAMETER_USAGE_H_
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index aeb2258..d25dc88 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -827,7 +827,7 @@
                                     std::ostream& out,
                                     ast::CallExpression* expr,
                                     const sem::Intrinsic* intrinsic) {
-  using Usage = sem::Parameter::Usage;
+  using Usage = sem::ParameterUsage;
 
   auto parameters = intrinsic->Parameters();
   auto arguments = expr->params();
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 00ff69f..81e06e5 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -464,7 +464,7 @@
 
 bool GeneratorImpl::EmitTextureCall(ast::CallExpression* expr,
                                     const sem::Intrinsic* intrinsic) {
-  using Usage = sem::Parameter::Usage;
+  using Usage = sem::ParameterUsage;
 
   auto parameters = intrinsic->Parameters();
   auto arguments = expr->params();
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index c400293..26cacbe 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -2298,7 +2298,7 @@
                                        const sem::Intrinsic* intrinsic,
                                        Operand result_type,
                                        Operand result_id) {
-  using Usage = sem::Parameter::Usage;
+  using Usage = sem::ParameterUsage;
 
   auto parameters = intrinsic->Parameters();
   auto arguments = call->params();