Add --strip-reflect pass

Strips reflection info. This is limited to decorations and
decoration instructions related to the SPV_GOOGLE_hlsl_functionality1
extension.
It will remove the OpExtension for SPV_GOOGLE_hlsl_functionality1.
It will also remove the OpExtension for SPV_GOOGLE_decorate_string
if there are no further remaining uses of OpDecorateStringGOOGLE.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1398
diff --git a/Android.mk b/Android.mk
index a0cf5e8..e2afc82 100644
--- a/Android.mk
+++ b/Android.mk
@@ -119,6 +119,7 @@
 		source/opt/simplification_pass.cpp \
 		source/opt/strength_reduction_pass.cpp \
 		source/opt/strip_debug_info_pass.cpp \
+		source/opt/strip_reflect_info_pass.cpp \
 		source/opt/type_manager.cpp \
 		source/opt/types.cpp \
 		source/opt/unify_const_pass.cpp \
diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp
index bedf436..03eb1c2 100644
--- a/include/spirv-tools/optimizer.hpp
+++ b/include/spirv-tools/optimizer.hpp
@@ -133,6 +133,13 @@
 // Section 3.32.2 of the SPIR-V spec) of the SPIR-V module to be optimized.
 Optimizer::PassToken CreateStripDebugInfoPass();
 
+// Creates a strip-reflect-info pass.
+// A strip-reflect-info pass removes all reflections instructions.
+// For now, this is limited to removing decorations defined in
+// SPV_GOOGLE_hlsl_functionality1.  The coverage may expand in
+// the future.
+Optimizer::PassToken CreateStripReflectInfoPass();
+
 // Creates an eliminate-dead-functions pass.
 // An eliminate-dead-functions pass will remove all functions that are not in
 // the call trees rooted at entry points and exported functions.  These
diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt
index 854c950..4121f7c 100644
--- a/source/opt/CMakeLists.txt
+++ b/source/opt/CMakeLists.txt
@@ -80,6 +80,7 @@
   simplification_pass.h
   strength_reduction_pass.h
   strip_debug_info_pass.h
+  strip_reflect_info_pass.h
   tree_iterator.h
   type_manager.h
   types.h
@@ -150,6 +151,7 @@
   simplification_pass.cpp
   strength_reduction_pass.cpp
   strip_debug_info_pass.cpp
+  strip_reflect_info_pass.cpp
   type_manager.cpp
   types.cpp
   unify_const_pass.cpp
diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp
index b897a77..ba8961b 100644
--- a/source/opt/optimizer.cpp
+++ b/source/opt/optimizer.cpp
@@ -220,6 +220,11 @@
       MakeUnique<opt::StripDebugInfoPass>());
 }
 
+Optimizer::PassToken CreateStripReflectInfoPass() {
+  return MakeUnique<Optimizer::PassToken::Impl>(
+      MakeUnique<opt::StripReflectInfoPass>());
+}
+
 Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
   return MakeUnique<Optimizer::PassToken::Impl>(
       MakeUnique<opt::EliminateDeadFunctionsPass>());
diff --git a/source/opt/passes.h b/source/opt/passes.h
index f0fb289..04f3123 100644
--- a/source/opt/passes.h
+++ b/source/opt/passes.h
@@ -53,6 +53,7 @@
 #include "set_spec_constant_default_value_pass.h"
 #include "strength_reduction_pass.h"
 #include "strip_debug_info_pass.h"
+#include "strip_reflect_info_pass.h"
 #include "unify_const_pass.h"
 #include "workaround1209.h"
 #endif  // LIBSPIRV_OPT_PASSES_H_
diff --git a/source/opt/strip_reflect_info_pass.cpp b/source/opt/strip_reflect_info_pass.cpp
new file mode 100644
index 0000000..d863e66
--- /dev/null
+++ b/source/opt/strip_reflect_info_pass.cpp
@@ -0,0 +1,75 @@
+// Copyright (c) 2018 Google LLC
+//
+// 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.
+
+#include "strip_reflect_info_pass.h"
+
+#include <cstring>
+
+#include "instruction.h"
+#include "ir_context.h"
+
+namespace spvtools {
+namespace opt {
+
+using spvtools::ir::Instruction;
+
+Pass::Status StripReflectInfoPass::Process(ir::IRContext* irContext) {
+  bool modified = false;
+
+  std::vector<Instruction*> to_remove;
+
+  bool other_uses_for_decorate_string = false;
+  for (auto& inst : irContext->module()->annotations()) {
+    switch (inst.opcode()) {
+      case SpvOpDecorateStringGOOGLE:
+        if (inst.GetSingleWordInOperand(1) == SpvDecorationHlslSemanticGOOGLE) {
+          to_remove.push_back(&inst);
+        } else {
+          other_uses_for_decorate_string = true;
+        }
+        break;
+
+      case SpvOpDecorateId:
+        if (inst.GetSingleWordInOperand(1) ==
+            SpvDecorationHlslCounterBufferGOOGLE) {
+          to_remove.push_back(&inst);
+        }
+        break;
+
+      default:
+        break;
+    }
+  }
+
+  for (auto& inst : irContext->module()->extensions()) {
+    const char* ext_name =
+        reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
+    if (0 == std::strcmp(ext_name, "SPV_GOOGLE_hlsl_functionality1")) {
+      to_remove.push_back(&inst);
+    } else if (!other_uses_for_decorate_string &&
+               0 == std::strcmp(ext_name, "SPV_GOOGLE_decorate_string")) {
+      to_remove.push_back(&inst);
+    }
+  }
+
+  for (auto* inst : to_remove) {
+    modified = true;
+    irContext->KillInst(inst);
+  }
+
+  return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
+}
+
+}  // namespace opt
+}  // namespace spvtools
diff --git a/source/opt/strip_reflect_info_pass.h b/source/opt/strip_reflect_info_pass.h
new file mode 100644
index 0000000..b6e9f33
--- /dev/null
+++ b/source/opt/strip_reflect_info_pass.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2018 Google LLC
+//
+// 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.
+
+#ifndef LIBSPIRV_OPT_STRIP_REFLECT_INFO_PASS_H_
+#define LIBSPIRV_OPT_STRIP_REFLECT_INFO_PASS_H_
+
+#include "ir_context.h"
+#include "module.h"
+#include "pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// See optimizer.hpp for documentation.
+class StripReflectInfoPass : public Pass {
+ public:
+  const char* name() const override { return "strip-reflect"; }
+  Status Process(ir::IRContext* irContext) override;
+
+  // Return the mask of preserved Analyses.
+  ir::IRContext::Analysis GetPreservedAnalyses() override {
+    return ir::IRContext::kAnalysisInstrToBlockMapping |
+           ir::IRContext::kAnalysisCombinators | ir::IRContext::kAnalysisCFG |
+           ir::IRContext::kAnalysisDominatorAnalysis |
+           ir::IRContext::kAnalysisLoopAnalysis |
+           ir::IRContext::kAnalysisNameMap;
+  }
+};
+
+}  // namespace opt
+}  // namespace spvtools
+
+#endif  // LIBSPIRV_OPT_STRIP_REFLECT_INFO_PASS_H_
diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt
index 6029e8e..66eae1a 100644
--- a/test/opt/CMakeLists.txt
+++ b/test/opt/CMakeLists.txt
@@ -46,6 +46,11 @@
   LIBS SPIRV-Tools-opt
 )
 
+add_spvtools_unittest(TARGET pass_strip_reflect_info
+  SRCS strip_reflect_info_test.cpp pass_utils.cpp
+  LIBS SPIRV-Tools-opt
+)
+
 add_spvtools_unittest(TARGET pass_compact_ids
   SRCS compact_ids_test.cpp pass_utils.cpp
   LIBS SPIRV-Tools-opt
diff --git a/test/opt/strip_reflect_info_test.cpp b/test/opt/strip_reflect_info_test.cpp
new file mode 100644
index 0000000..3cf2cdc
--- /dev/null
+++ b/test/opt/strip_reflect_info_test.cpp
@@ -0,0 +1,65 @@
+// Copyright (c) 2018 Google LLC
+//
+// 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.
+
+#include "pass_fixture.h"
+#include "pass_utils.h"
+
+namespace {
+
+using namespace spvtools;
+
+using StripLineReflectInfoTest = PassTest<::testing::Test>;
+
+TEST_F(StripLineReflectInfoTest, StripHlslSemantic) {
+  // This is a non-sensical example, but exercises the instructions.
+  std::string before = R"(OpCapability Shader
+OpCapability Linkage
+OpExtension "SPV_GOOGLE_decorate_string"
+OpExtension "SPV_GOOGLE_hlsl_functionality1"
+OpMemoryModel Logical Simple
+OpDecorateStringGOOGLE %float HlslSemanticGOOGLE "foobar"
+OpDecorateStringGOOGLE %void HlslSemanticGOOGLE "my goodness"
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+)";
+  std::string after = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical Simple
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+)";
+
+  SinglePassRunAndCheck<opt::StripReflectInfoPass>(before, after, false);
+}
+
+TEST_F(StripLineReflectInfoTest, StripHlslCounterBuffer) {
+  std::string before = R"(OpCapability Shader
+OpCapability Linkage
+OpExtension "SPV_GOOGLE_hlsl_functionality1"
+OpMemoryModel Logical Simple
+OpDecorateId %void HlslCounterBufferGOOGLE %float
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+)";
+  std::string after = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical Simple
+%void = OpTypeVoid
+%float = OpTypeFloat 32
+)";
+
+  SinglePassRunAndCheck<opt::StripReflectInfoPass>(before, after, false);
+}
+
+}  // anonymous namespace
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index ca63c19..ccfbd0b 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -278,6 +278,9 @@
                Replaces instructions with equivalent and less expensive ones.
   --strip-debug
                Remove all debug instructions.
+  --strip-reflect
+               Remove all reflection information.  For now, this covers
+               reflection information defined by SPV_GOOGLE_hlsl_functionality1.
   --workaround-1209
                Rewrites instructions for which there are known driver bugs to
                avoid triggering those bugs.
@@ -411,6 +414,8 @@
         }
       } else if (0 == strcmp(cur_arg, "--strip-debug")) {
         optimizer->RegisterPass(CreateStripDebugInfoPass());
+      } else if (0 == strcmp(cur_arg, "--strip-reflect")) {
+        optimizer->RegisterPass(CreateStripReflectInfoPass());
       } else if (0 == strcmp(cur_arg, "--set-spec-const-default-value")) {
         if (++argi < argc) {
           auto spec_ids_vals =