Merge remote-tracking branch 'aosp/upstream-master' into update-shaderc-sources

Adds the following:

4a3e551 Fix tests for catching up with the master of glslang.
0b7140e Add Adam Chainz (adam@adamj.eu) into CONTRIBUTORS.
af6a8a7 Use .io readthedocs links for nosetests.
bdae28e Android: Use grammar files from SPIRV-Headers repo
1a9d48f SPIRV-Tools now depends on external SPIRV-Headers repo
43620d2 SPIRV-Tools now requires SPIRV-Headers.
88a7261 SPIRV-Tools validator sources have moved.
d0c93d2 Glslang has a new source file.
8d8aecd Fix parsing of version from CHANGES file: -dev is optional
ebeff38 MinGW linking C executables: statically link libgcc
bc1b677 Print <yyyy>-<index> info for --version option
b3cfde4 -mfmt=bin/c/num to select binary output format
5e1f49e README links to glslc manual
52ecd9b Register the new file in glslang into Android.mk.
e050f37 Register new files appearing in glslang into Android.mk.
cd8793c Fix add_copyright.py and add license to android_test/test.cpp.
235eb39 Add rules to create build-version.inc on Android.
79c9e9d Update Android.mk for new SPIR-V Tools source file
e1206a1 Update glslc manual about assembling support.
9a35bcf Add new dependencies for assembling support into Android.mk.
215a0b6 Add support for assembly files in glslc.
cf4c497 Add assembling support into shaderc C and C++ interface.
a0510ce Move SPIRV-Tools wrapper functions into their own files.
c2dcb79 Compilation fails for null input file name string
7308a2c Add comment for one CMake custom target.
f9651b7 Add .inc grammar generation to Android.mk.
diff --git a/.appveyor.yml b/.appveyor.yml
index 78ee8d9..50446ac 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -27,9 +27,10 @@
 
 # scripts that run after cloning repository
 install:
-  - git clone https://github.com/google/googletest.git third_party/googletest
-  - git clone https://github.com/google/glslang.git third_party/glslang
-  - git clone https://github.com/KhronosGroup/SPIRV-Tools.git third_party/spirv-tools
+  - git clone https://github.com/google/googletest.git          third_party/googletest
+  - git clone https://github.com/google/glslang.git             third_party/glslang
+  - git clone https://github.com/KhronosGroup/SPIRV-Tools.git   third_party/spirv-tools
+  - git clone https://github.com/KhronosGroup/SPIRV-Headers.git third_party/spirv-tools/external/spirv-headers
 
 build:
   parallel: true  # enable MSBuild parallel builds
diff --git a/.travis.yml b/.travis.yml
index d1a0b21..c3ad01c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -60,9 +60,10 @@
     fi
 
 before_script:
-  - git clone https://github.com/google/googletest.git        third_party/googletest
-  - git clone https://github.com/google/glslang.git           third_party/glslang
-  - git clone https://github.com/KhronosGroup/SPIRV-Tools.git third_party/spirv-tools
+  - git clone https://github.com/google/googletest.git          third_party/googletest
+  - git clone https://github.com/google/glslang.git             third_party/glslang
+  - git clone https://github.com/KhronosGroup/SPIRV-Tools.git   third_party/spirv-tools
+  - git clone https://github.com/KhronosGroup/SPIRV-Headers.git third_party/spirv-tools/external/spirv-headers
 
 script:
   - mkdir build && cd build
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..89150ec
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,17 @@
+Revision history for Shaderc
+
+v2016.0-dev 2016-05-19
+
+ - Adds v<year>.<index> versioning, with "-dev" suffix to indicate work in
+   progress. The intent is to summarize and report functionalities more easily
+   for incorporating into downstream projects.
+
+ - Summary of functionalities (See the README.md for more details):
+   - Provides libraries and command line tools for generating SPIR-V modules
+   - Supports GLSL source code or SPIR-V assembly as input
+   - Supports SPIR-V binary or assembly text as output
+   - Command line options follow GCC/Clang conventions
+   - Supports various semantics (OpenGL, OpenGL Compatible and Vulkan)
+   - Supports #include
+   - Supports user-defined macros
+   - Supports dependency information dumping
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 4e7b407..503b32d 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -19,3 +19,5 @@
 Damien Mabin <dmabin@google.com>
 Qining Lu <qining@google.com>
 Jakob Vogel <JakobpunktVogel@gmail.com>
+David Yen <dyen@google.com>
+Adam Chainz <adam@adamj.eu>
diff --git a/README.md b/README.md
index 146d64f..a1270f5 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
 A collection of tools, libraries and tests for shader compilation.
 At the moment it includes:
 
-- `glslc`, a command line compiler for GLSL to SPIR-V, and
+- [`glslc`](glslc), a command line compiler for GLSL to SPIR-V, and
 - `libshaderc` a library API for doing the same.
 
 ## Status
@@ -63,6 +63,7 @@
 git clone https://github.com/google/googletest.git
 git clone https://github.com/google/glslang.git
 git clone https://github.com/KhronosGroup/SPIRV-Tools.git spirv-tools
+git clone https://github.com/KhronosGroup/SPIRV-Headers.git spirv-tools/external/spirv-headers
 cd $SOURCE_DIR/
 ```
 
@@ -146,7 +147,7 @@
  - [`asciidoctor`](http://asciidoctor.org/): for generating documenation.
    - [`pygments.rb`](https://rubygems.org/gems/pygments.rb) required by
      `asciidoctor` for syntax highlighting.
- - [`nosetests`](https://nose.readthedocs.org): for testing the Python code.
+ - [`nosetests`](https://nose.readthedocs.io): for testing the Python code.
 
 ### Building and running Shderc using Docker
 
diff --git a/android_test/test.cpp b/android_test/test.cpp
index d443375..23df9b8 100644
--- a/android_test/test.cpp
+++ b/android_test/test.cpp
@@ -1,3 +1,17 @@
+// Copyright 2015 The Shaderc Authors. All rights reserved.
+//
+// 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 "shaderc/shaderc.hpp"
 #include <android_native_app_glue.h>
 
diff --git a/cmake/utils.cmake b/cmake/utils.cmake
index 31fb214..0d1b4bb 100644
--- a/cmake/utils.cmake
+++ b/cmake/utils.cmake
@@ -19,6 +19,14 @@
       # requires clang to be built with compiler-rt.
       target_link_libraries(${TARGET} PRIVATE --coverage)
     endif()
+    if (NOT SHADERC_ENABLE_SHARED_CRT)
+      if (WIN32)
+	# For MinGW cross compile, statically link to the libgcc runtime.
+	# But it still depends on MSVCRT.dll.
+	set_target_properties(${TARGET} PROPERTIES
+		LINK_FLAGS "-static -static-libgcc")
+      endif(WIN32)
+    endif(NOT SHADERC_ENABLE_SHARED_CRT)
   else()
     # disable warning C4800: 'int' : forcing value to bool 'true' or 'false'
     # (performance warning)
@@ -31,12 +39,12 @@
   if (NOT "${MSVC}")
     target_compile_options(${TARGET} PRIVATE -std=c++11)
     if (NOT SHADERC_ENABLE_SHARED_CRT)
-      if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
-	# For MinGW cross compile, statically link to the C++ runtime
+      if (WIN32)
+	# For MinGW cross compile, statically link to the C++ runtime.
 	# But it still depends on MSVCRT.dll.
-	set_target_properties(${TARGET} PROPERTIES LINK_FLAGS
-			      -static -static-libgcc -static-libstdc++)
-      endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+	set_target_properties(${TARGET} PROPERTIES
+		LINK_FLAGS "-static -static-libgcc -static-libstdc++")
+      endif(WIN32)
     endif(NOT SHADERC_ENABLE_SHARED_CRT)
   endif()
 endfunction(shaderc_default_compile_options)
diff --git a/glslc/README.asciidoc b/glslc/README.asciidoc
index 1c4021b..9709227 100644
--- a/glslc/README.asciidoc
+++ b/glslc/README.asciidoc
@@ -23,9 +23,13 @@
 
 == Description
 
-=== Shader stage specification
+=== Input file languages
 
-glslc provides three ways to specify the shader stage of an input shader file:
+glslc accepts both GLSL source and SPIR-V assembly files as inputs.
+
+==== Shader stage specification
+
+glslc provides three ways to specify the shader stage of a GLSL source file:
 `-fshader-stage=<stage>`, `#pragma shader_stage(<stage>)`, and file extension.
 The `-fshader-stage=` option overrides `#pragma shader_stage()`, which overrides
 the file extension.
@@ -62,6 +66,16 @@
   translation unit, all the ``stage``s specified must be the same. Otherwise,
   glslc will issue an error.
 
+==== SPIR-V assembly files
+
+SPIR-V assembly input files should follow the
+https://github.com/KhronosGroup/SPIRV-Tools/blob/master/syntax.md[syntax]
+defined in the https://github.com/KhronosGroup/SPIRV-Tools[SPIRV-Tools]
+project and have the `.spvasm` extension. Command line options treat SPIR-V
+assembly files differently; some may ignore them, e.g., `<<option-cap-e,-E>>`,
+`<<option-cap-s,-S>>`, and some may even treat them not as SPIR-V assembly
+files, e.g., `<<shader-stage-with-spirv-assembly,-fshader-stage\=>>`.
+
 [[output-file-naming]]
 === Output file naming
 
@@ -124,6 +138,15 @@
   extension, the file extension is ignored and the `-fshader-stage=` argument
   is used instead.
 
+[[shader-stage-with-spirv-assembly]]
+CAUTION: `-fshader-stage=` overrides file extension; that means it should not
+be used together with SPIR-V assembly files because glslc will treat the given
+SPIR-V assembly files as GLSL source code of the given shader stage. If you
+need to supply both SPIR-V assembly files and `-fshader-stage=` on the same
+command line, please put SPIR-V assembly files ahead of the first
+`-fshader-stage=`, since `-fshader-stage=` only affects the treatment of
+subsequent files.
+
 ==== `-std=`
 
 `-std=<value>` lets you specify a shader version and profile on the command
@@ -177,6 +200,7 @@
 files are named by the rules in the <<output-file-naming,Output File Naming>>
 section.
 
+[[option-cap-e]]
 ==== `-E`
 
 `-E` tells the glslc compiler to run only the preprocessing stage. It overrides
@@ -185,6 +209,9 @@
 files are given, their preprocessed output are all written to standard output,
 in the order specified on the command line.
 
+glslc will do nothing for SPIR-V assembly files with this option.
+
+[[option-cap-s]]
 ==== `-S`
 
 `-S` tells the glslc compiler to run the preprocessing, compiling, and then
@@ -192,6 +219,8 @@
 SPIR-V assembly file; these SPIR-V assembly files are named by the rules in the
 <<output-file-naming,Output File Naming>> section.
 
+glslc will do nothing for SPIR-V assembly files with this option.
+
 ==== No Compilation Stage Selection
 
 If none of the above options is given, the glslc compiler will run
@@ -223,6 +252,39 @@
 NOTE: Currently this option has no effect.  Full functionality depends on
 glslang support for generating debug info.
 
+==== `-mfmt=<format>`
+
+`-mfmt=<format>` selects output format for compilation output in SPIR-V binary
+code form.  Supported options are listed in the
+<<binary-output-format-options,binary output format options>> table. This
+option is only valid to be used when the compilation output is SPIR-V binary
+code. Specifying any options listed below when the output is not SPIR-V binary
+code, like disassembly (with `-S` specified), text (with `-M`, `-MM` or `-E`
+specified) will trigger an error.
+
+[[binary-output-format-options]]
+.Binary Output Format Options
+[cols="20%,80%"]
+|===
+|Format option  |Description
+
+|bin            |Output SPIR-V binary code as a sequence of binary 32-bitwords
+                 in host native endianness. This is the default format for
+                 SPIR-V binary compilation output.
+|num            |Output SPIR-V binary code as a text file containing a list of
+                 comma-separated hex numbers. +
+                 Example: `glslc -c -mfmt=num main.vert -o output_file.txt` +
+                 Content of the output_file.txt: +
+                 0x07230203,0x00010000,0x00080001,0x00000006...
+|c              |Output SPIR-V binary code as a text file containing C-style +
+                 initializer list. +
+                 This is just wrapping the output of `num` option with curly
+                 brackets. +
+                 Example: `glslc -c -mfmt=c main.vert -o output_file.txt` +
+                 Content of output_file.txt: +
+                 {0x07230203, 0x00010000, 0x00080001, 0x00000006...}
+|===
+
 === Warning and Error Options
 
 ==== `-w`
diff --git a/glslc/src/file_compiler.cc b/glslc/src/file_compiler.cc
index 655e4b1..311fddf 100644
--- a/glslc/src/file_compiler.cc
+++ b/glslc/src/file_compiler.cc
@@ -14,8 +14,11 @@
 
 #include "file_compiler.h"
 
+#include <cassert>
 #include <fstream>
+#include <iomanip>
 #include <iostream>
+#include <sstream>
 
 #include "file.h"
 #include "file_includer.h"
@@ -27,6 +30,35 @@
 namespace {
 using shaderc_util::string_piece;
 
+// A helper function to emit SPIR-V binary code as a list of hex numbers in
+// text form. Returns true if a non-empty compilation result is emitted
+// successfully. Return false if nothing should be emitted, either because the
+// compilation result is empty, or the compilation output is not SPIR-V binary
+// code.
+template <typename CompilationResultType>
+bool EmitSpirvBinaryAsCommaSeparatedNumbers(const CompilationResultType& result,
+                                            std::ostream* out) {
+  // Return early if the compilation output is not in SPIR-V binary code form.
+  if (!std::is_same<CompilationResultType,
+                    shaderc::SpvCompilationResult>::value)
+    return false;
+  // Return early if the compilation result is empty.
+  if (result.cbegin() == result.cend()) return false;
+  std::ios::fmtflags output_stream_flag_cache(out->flags());
+  *out << std::hex << std::setfill('0');
+  auto RI = result.cbegin();
+  *out << "0x" << std::setw(8) << *RI++;
+  for (size_t counter = 1; RI != result.cend(); RI++, counter++) {
+    *out << ",";
+    // Break line for every four words.
+    if (counter % 4 == 0) {
+      *out << std::endl;
+    }
+    *out << "0x" << std::setw(8) << *RI;
+  }
+  out->flags(output_stream_flag_cache);
+  return true;
+}
 }  // anonymous namespace
 
 namespace glslc {
@@ -54,10 +86,10 @@
     error_file_name = "<stdin>";
   }
 
-  string_piece source_string;
+  string_piece source_string = "";
   if (!input_data.empty()) {
-    source_string = string_piece(&(*input_data.begin()),
-                                 &(*input_data.begin()) + input_data.size());
+    source_string = {&input_data.front(),
+                     &input_data.front() + input_data.size()};
   }
 
   std::unique_ptr<FileIncluder> includer(
@@ -67,6 +99,18 @@
   const auto& used_source_files = includer->file_path_trace();
   options_.SetIncluder(std::move(includer));
 
+  if (shader_stage == shaderc_spirv_assembly) {
+    // Only act if the requested target is SPIR-V binary.
+    if (output_type_ == OutputType::SpirvBinary) {
+      const auto result =
+          compiler_.AssembleToSpv(source_string.data(), source_string.size());
+      return EmitCompiledResult(result, input_file, error_file_name,
+                                used_source_files, output_stream);
+    } else {
+      return true;
+    }
+  }
+
   switch (output_type_) {
     case OutputType::SpirvBinary: {
       const auto result = compiler_.CompileGlslToSpv(
@@ -156,8 +200,40 @@
     }
   }
 
-  // Write compilation output to output file.
-  out->write(compilation_output.data(), compilation_output.size());
+  // Write compilation output to output file. If an output format for SPIR-V
+  // binary code is specified, it is handled here.
+  switch (binary_emission_format_) {
+    case SpirvBinaryEmissionFormat::Unspecified:
+    case SpirvBinaryEmissionFormat::Binary:
+      // The output format is unspecified or specified as binary output.
+      out->write(compilation_output.data(), compilation_output.size());
+      break;
+    case SpirvBinaryEmissionFormat::Numbers:
+      // The output format is specified to be a list of hex numbers, the
+      // compilation output must be in SPIR-V binary code form.
+      assert(output_type_ == OutputType::SpirvBinary);
+      if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
+        // Only emits the end-of-line character when the emitted compilation
+        // result is not empty.
+        *out << std::endl;
+      }
+      break;
+    case SpirvBinaryEmissionFormat::CInitList:
+      // The output format is specified to be a C-style initializer list, the
+      // compilation output must be in SPIR-V binary code form.
+      assert(output_type_ == OutputType::SpirvBinary);
+      if (result.begin() != result.end()) {
+        // Only emits the '{' when the compilation result is not empty.
+        *out << "{";
+      }
+      if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
+        // Only emits the end-of-line character when the emitted compilation
+        // result is not empty.
+        *out << "}" << std::endl;
+      }
+      break;
+  }
+
   // Write error message to std::cerr.
   std::cerr << result.GetErrorMessage();
   if (out->fail()) {
@@ -217,9 +293,9 @@
 
   // If we are outputting many object files, we cannot specify -o. Also
   // if we are preprocessing multiple files they must be to stdout.
-  if (num_files > 1 &&
-      ((!PreprocessingOnly() && !needs_linking_ && !output_file_name_.empty()) ||
-       (PreprocessingOnly() && output_file_name_ != "-"))) {
+  if (num_files > 1 && ((!PreprocessingOnly() && !needs_linking_ &&
+                         !output_file_name_.empty()) ||
+                        (PreprocessingOnly() && output_file_name_ != "-"))) {
     std::cerr << "glslc: error: cannot specify -o when generating multiple"
                  " output files"
               << std::endl;
@@ -238,6 +314,37 @@
     }
   }
 
+  // If the output format is specified to be a binary, a list of hex numbers or
+  // a C-style initializer list, the output must be in SPIR-V binary code form.
+  if (binary_emission_format_ != SpirvBinaryEmissionFormat::Unspecified) {
+    if (output_type_ != OutputType::SpirvBinary) {
+      std::cerr << "glslc: error: cannot emit output as a ";
+      switch (binary_emission_format_) {
+        case SpirvBinaryEmissionFormat::Binary:
+          std::cerr << "binary";
+          break;
+        case SpirvBinaryEmissionFormat::Numbers:
+          std::cerr << "list of hex numbers";
+          break;
+        case SpirvBinaryEmissionFormat::CInitList:
+          std::cerr << "C-style initializer list";
+          break;
+        case SpirvBinaryEmissionFormat::Unspecified:
+          // The compiler should never be here at runtime. This case is added to
+          // complete the switch cases.
+          break;
+      }
+      std::cerr << " when the output is not SPIR-V binary code" << std::endl;
+      return false;
+    }
+    if (dependency_info_dumping_handler_ &&
+        dependency_info_dumping_handler_->DumpingAsCompilationOutput()) {
+      std::cerr << "glslc: error: cannot dump dependency info when specifying "
+                   "any binary output format"
+                << std::endl;
+    }
+  }
+
   return true;
 }
 
diff --git a/glslc/src/file_compiler.h b/glslc/src/file_compiler.h
index ffd1b7d..6b077a1 100644
--- a/glslc/src/file_compiler.h
+++ b/glslc/src/file_compiler.h
@@ -29,8 +29,19 @@
 // SPIR-V files or preprocessed output.
 class FileCompiler {
  public:
+  enum class SpirvBinaryEmissionFormat {
+    Unspecified,  // No binary output format specified, this is the only valid
+                  // option when the compilation output is not in SPIR-V binary
+                  // code form.
+    Binary,       // Emits SPIR-V binary code directly.
+    Numbers,      // Emits SPIR-V binary code as a list of hex numbers.
+    CInitList,    // Emits SPIR-V bianry code as a C-style initializer list
+                  // of hex numbers.
+  };
+
   FileCompiler()
       : output_type_(OutputType::SpirvBinary),
+        binary_emission_format_(SpirvBinaryEmissionFormat::Unspecified),
         needs_linking_(true),
         total_warnings_(0),
         total_errors_(0) {}
@@ -63,6 +74,11 @@
     output_file_name_ = file;
   }
 
+  // Sets the format for SPIR-V binary compilation output.
+  void SetSpirvBinaryOutputFormat(SpirvBinaryEmissionFormat format) {
+    binary_emission_format_ = format;
+  }
+
   // Returns false if any options are incompatible. The num_files parameter
   // represents the number of files that will be compiled.
   bool ValidateOptions(size_t num_files);
@@ -166,7 +182,9 @@
   std::string GetCandidateOutputFileName(std::string input_filename);
 
   // Returns true if the compiler's output is preprocessed text.
-  bool PreprocessingOnly() { return output_type_ == OutputType::PreprocessedText; }
+  bool PreprocessingOnly() {
+    return output_type_ == OutputType::PreprocessedText;
+  }
 
   // Performs actual SPIR-V compilation on the contents of input files.
   shaderc::Compiler compiler_;
@@ -178,6 +196,10 @@
   // What kind of output will be produced?
   OutputType output_type_;
 
+  // The Flag to indicate to which format the output SPIR-V binary code should
+  // be emitted.
+  SpirvBinaryEmissionFormat binary_emission_format_;
+
   // A FileFinder used to substitute #include directives in the source code.
   shaderc_util::FileFinder include_file_finder_;
 
diff --git a/glslc/src/main.cc b/glslc/src/main.cc
index 38a85b2..900b8f2 100644
--- a/glslc/src/main.cc
+++ b/glslc/src/main.cc
@@ -59,6 +59,10 @@
   -std=<value>      Version and profile for input files. Possible values
                     are concatenations of version and profile, e.g. 310es,
                     450core, etc.
+  -mfmt=<format>    Output SPIR-V binary code using the selected format. This
+                    option may be specified only when the compilation output is
+                    in SPIR-V binary code form. Available options include bin, c
+                    and num. By default the binary output format is bin.
   -M                Generate make dependencies. Implies -E and -w.
   -MM               An alias for -M.
   -MD               Generate make dependencies and compile.
@@ -167,6 +171,23 @@
         return 1;
       }
       compiler.options().SetTargetEnvironment(target_env, 0);
+    } else if (arg.starts_with("-mfmt=")) {
+      const string_piece binary_output_format =
+          arg.substr(std::strlen("-mfmt="));
+      if (binary_output_format == "bin") {
+        compiler.SetSpirvBinaryOutputFormat(
+            glslc::FileCompiler::SpirvBinaryEmissionFormat::Binary);
+      } else if (binary_output_format == "num") {
+        compiler.SetSpirvBinaryOutputFormat(
+            glslc::FileCompiler::SpirvBinaryEmissionFormat::Numbers);
+      } else if (binary_output_format == "c") {
+        compiler.SetSpirvBinaryOutputFormat(
+            glslc::FileCompiler::SpirvBinaryEmissionFormat::CInitList);
+      } else {
+        std::cerr << "glslc: error: invalid value '" << binary_output_format
+                  << "' in '-mfmt=" << binary_output_format << "'" << std::endl;
+        return 1;
+      }
     } else if (arg.starts_with("-x")) {
       string_piece option_arg;
       if (!GetOptionArgument(argc, argv, &i, "-x", &option_arg)) {
diff --git a/glslc/src/shader_stage.cc b/glslc/src/shader_stage.cc
index 8e2baa7..f6b227d 100644
--- a/glslc/src/shader_stage.cc
+++ b/glslc/src/shader_stage.cc
@@ -60,7 +60,9 @@
       {"tesc", shaderc_glsl_default_tess_control_shader},
       {"tese", shaderc_glsl_default_tess_evaluation_shader},
       {"geom", shaderc_glsl_default_geometry_shader},
-      {"comp", shaderc_glsl_default_compute_shader}};
+      {"comp", shaderc_glsl_default_compute_shader},
+      {"spvasm", shaderc_spirv_assembly},
+  };
 
   const string_piece extension = glslc::GetFileExtension(file_name);
   shaderc_shader_kind stage = shaderc_glsl_infer_from_source;
diff --git a/glslc/test/assembly.py b/glslc/test/assembly.py
new file mode 100644
index 0000000..d4bc025
--- /dev/null
+++ b/glslc/test/assembly.py
@@ -0,0 +1,136 @@
+# Copyright 2015 The Shaderc Authors. All rights reserved.
+#
+# 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.
+
+import expect
+from glslc_test_framework import inside_glslc_testsuite
+from placeholder import FileShader
+
+
+def assembly_comments():
+    return """
+    ; SPIR-V
+    ; Version: 1.0
+    ; Generator: Khronos Glslang Reference Front End; 1
+    ; Bound: 6
+    ; Schema: 0"""
+
+
+def empty_main_assembly():
+    return assembly_comments() + """
+         OpCapability Shader
+    %1 = OpExtInstImport "GLSL.std.450"
+         OpMemoryModel Logical GLSL450
+         OpEntryPoint Vertex %4 "main"
+         OpSource ESSL 310
+         OpName %4 "main"
+    %2 = OpTypeVoid
+    %3 = OpTypeFunction %2
+    %4 = OpFunction %2 None %3
+    %5 = OpLabel
+         OpReturn
+         OpFunctionEnd"""
+
+
+def empty_main():
+    return '#version 310 es\nvoid main() {}'
+
+
+@inside_glslc_testsuite('SpirvAssembly')
+class TestAssemblyFileAsOnlyParameter(expect.ValidNamedObjectFile):
+    """Tests that glslc accepts a SPIR-V assembly file as the only parameter."""
+
+    shader = FileShader(empty_main_assembly(), '.spvasm')
+    glslc_args = [shader]
+    expected_object_filenames = ('a.spv',)
+
+
+@inside_glslc_testsuite('SpirvAssembly')
+class TestDashCAssemblyFile(expect.ValidObjectFile):
+    """Tests that -c works with SPIR-V assembly file."""
+
+    shader = FileShader(empty_main_assembly(), '.spvasm')
+    glslc_args = ['-c', shader]
+
+
+@inside_glslc_testsuite('SpirvAssembly')
+class TestAssemblyFileWithOnlyComments(expect.ValidObjectFile):
+    """Tests that glslc accepts an assembly file with only comments inside."""
+
+    shader = FileShader(assembly_comments(), '.spvasm')
+    glslc_args = ['-c', shader]
+
+
+@inside_glslc_testsuite('SpirvAssembly')
+class TestEmptyAssemblyFile(expect.ValidObjectFile):
+    """Tests that glslc accepts an empty assembly file."""
+
+    shader = FileShader('', '.spvasm')
+    glslc_args = ['-c', shader]
+
+
+@inside_glslc_testsuite('SpirvAssembly')
+class TestDashEAssemblyFile(expect.SuccessfulReturn, expect.NoGeneratedFiles):
+    """Tests that -E works with SPIR-V assembly file."""
+
+    shader = FileShader(empty_main_assembly(), '.spvasm')
+    glslc_args = ['-E', shader]
+
+
+@inside_glslc_testsuite('SpirvAssembly')
+class TestDashSAssemblyFile(expect.SuccessfulReturn, expect.NoGeneratedFiles):
+    """Tests that -S works with SPIR-V assembly file."""
+
+    shader = FileShader(empty_main_assembly(), '.spvasm')
+    glslc_args = ['-S', shader]
+
+
+@inside_glslc_testsuite('SpirvAssembly')
+class TestMultipleAssemblyFiles(expect.ValidObjectFile):
+    """Tests that glslc accepts multiple SPIR-V assembly files."""
+
+    shader1 = FileShader(empty_main_assembly(), '.spvasm')
+    shader2 = FileShader(empty_main_assembly(), '.spvasm')
+    shader3 = FileShader(empty_main_assembly(), '.spvasm')
+    glslc_args = ['-c', shader1, shader2, shader3]
+
+
+@inside_glslc_testsuite('SpirvAssembly')
+class TestHybridInputFiles(expect.ValidObjectFile):
+    """Tests that glslc accepts a mix of SPIR-V assembly files and
+    GLSL source files."""
+
+    shader1 = FileShader(empty_main_assembly(), '.spvasm')
+    shader2 = FileShader(empty_main(), '.vert')
+    shader3 = FileShader(empty_main(), '.frag')
+    glslc_args = ['-c', shader1, shader2, shader3]
+
+
+@inside_glslc_testsuite('SpirvAssembly')
+class TestShaderStageWithAssemblyFile(expect.ErrorMessage):
+    """Tests that assembly files don't work with -fshader-stage"""
+
+    shader = FileShader(empty_main_assembly(), '.spvasm')
+    glslc_args = ['-c', '-fshader-stage=vertex', shader]
+
+    expected_error = [
+        shader, ":2: error: '' :  syntax error\n",
+        '1 error generated.\n']
+
+
+@inside_glslc_testsuite('SpirvAssembly')
+class TestStdWithAssemblyFile(expect.ValidObjectFile):
+    """Tests that --std= doesn't affect the processing of assembly files."""
+
+    shader = FileShader(empty_main_assembly(), '.spvasm')
+    glslc_args = ['-c', '-std=310es', shader]
diff --git a/glslc/test/expect.py b/glslc/test/expect.py
index 0749c5d..9a5db83 100644
--- a/glslc/test/expect.py
+++ b/glslc/test/expect.py
@@ -18,7 +18,7 @@
 as superclass and providing the expected_* variables required by the check_*()
 methods in the mixin classes.
 """
-import os.path
+import os
 import re
 from glslc_test_framework import GlslCTest
 
@@ -37,7 +37,7 @@
     foo -> foo.[extension]
     """
     if filename[-5:] not in ['.vert', '.frag', '.tesc', '.tese',
-                             '.geom', '.comp']:
+                             '.geom', '.comp', '.spvasm']:
         return filename.rsplit('.', 1)[0] + '.' + extension
     else:
         return filename + '.' + extension
@@ -96,6 +96,21 @@
     pass
 
 
+class NoGeneratedFiles(GlslCTest):
+    """Mixin class for checking that there is no file generated."""
+
+    def check_no_generated_files(self, status):
+        all_files = os.listdir(status.directory)
+        input_files = status.input_filenames
+        if all([f.startswith(status.directory) for f in input_files]):
+            all_files = [os.path.join(status.directory, f) for f in all_files]
+        generated_files = set(all_files) - set(input_files)
+        if len(generated_files) == 0:
+            return True, ''
+        else:
+            return False, 'Extra files generated: {}'.format(generated_files)
+
+
 class CorrectObjectFilePreamble(GlslCTest):
     """Provides methods for verifying preamble for a SPV object file."""
 
@@ -148,8 +163,9 @@
             # SPIR-V version number
             if read_word(preamble, 1, little_endian) != 0x00010000:
                 return False, 'Incorrect SPV binary: wrong version number'
-            # glslang SPIR-V magic number
-            if read_word(preamble, 2, little_endian) != 0x00080001:
+            # glslang (0x0008....) or SPIRV-Tools (0x0007....) generator number
+            if read_word(preamble, 2, little_endian) != 0x00080001 and \
+                    read_word(preamble, 2, little_endian) != 0x00070000:
                 return False, ('Incorrect SPV binary: wrong generator magic '
                                'number')
             # reserved for instruction schema
@@ -223,11 +239,20 @@
             return False, 'Cannot find file: ' + target_filename
         with open(target_filename, 'r') as target_file:
             file_contents = target_file.read()
-            if file_contents == self.expected_file_contents:
-                return True, ''
-            return False, ('Incorrect file output: \n{act}\nExpected:\n{exp}'
-                           ''.format(act=file_contents,
-                                     exp=self.expected_file_contents))
+            if type(self.expected_file_contents) == str:
+                if file_contents == self.expected_file_contents:
+                    return True, ''
+                return False, ('Incorrect file output: \n{act}\nExpected:\n{exp}'
+                               ''.format(act=file_contents,
+                                         exp=self.expected_file_contents))
+            elif isinstance(self.expected_file_contents, type(re.compile(''))):
+                if self.expected_file_contents.search(file_contents):
+                    return True, ''
+                return False, (
+                    'Incorrect file output: \n{act}\n'
+                    'Expected matching regex pattern:\n{exp}'.format(
+                        act=file_contents,
+                        exp=self.expected_file_contents.pattern))
         return False, ('Could not open target file ' + target_filename +
                        ' for reading')
 
diff --git a/glslc/test/glslc_test_framework.py b/glslc/test/glslc_test_framework.py
index 6a2a3b9..9454a66 100755
--- a/glslc/test/glslc_test_framework.py
+++ b/glslc/test/glslc_test_framework.py
@@ -147,7 +147,7 @@
         self.stderr = stderr
         # temporary directory where the test runs
         self.directory = directory
-        # the names of input shader files (without path)
+        # the names of input shader files (potentially including paths)
         self.input_filenames = input_filenames
 
 
diff --git a/glslc/test/option_dash_D.py b/glslc/test/option_dash_D.py
index df4d518..ca71d6e 100644
--- a/glslc/test/option_dash_D.py
+++ b/glslc/test/option_dash_D.py
@@ -181,11 +181,11 @@
         """#version 310 es
         void main(){X}
         void foo(){Y}""", '.vert')
-    glslc_args = ['-DX=', '-DY=return 3;', '-std=450compatibility', shader]
+    glslc_args = ['-DX=', '-DY=return 3;', '-std=450core', shader]
 
     expected_error = [
         shader, ': warning: (version, profile) forced to be (450, ',
-        'compatibility), while in source code it is (310, es)\n',
+        'core), while in source code it is (310, es)\n',
         shader, ":3: error: 'return' : void function cannot return a value\n",
         '1 warning and 1 error generated.\n']
 
diff --git a/glslc/test/option_mfmt.py b/glslc/test/option_mfmt.py
new file mode 100644
index 0000000..2466319
--- /dev/null
+++ b/glslc/test/option_mfmt.py
@@ -0,0 +1,197 @@
+# Copyright 2016 The Shaderc Authors. All rights reserved.
+#
+# 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.
+
+import expect
+import re
+from glslc_test_framework import inside_glslc_testsuite
+from placeholder import FileShader
+
+MINIMAL_SHADER = '#version 140\nvoid main() {}'
+# Regular expression patterns for the minimal shader. The magic number should
+# match exactly, and there should not be a trailing comma at the end of the
+# list. When -mfmt=c is specified, curly brackets should be presented.
+MINIMAL_SHADER_NUM_FORMAT_PATTERN = "^0x07230203.*[0-9a-f]$"
+MINIMAL_SHADER_C_FORMAT_PATTERN = "^\{0x07230203.*[0-9a-f]\}"
+ERROR_SHADER = '#version 140\n#error\nvoid main() {}'
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtCWorksWithDashC(expect.ValidFileContents):
+    """Tests that -mfmt=c works with -c for single input file. SPIR-V binary
+    code output should be emitted as a C-style initializer list in the output
+    file.
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-c', '-mfmt=c', '-o', 'output_file']
+    target_filename = 'output_file'
+    expected_file_contents = re.compile(MINIMAL_SHADER_C_FORMAT_PATTERN, re.S)
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtNumWorksWithDashC(expect.ValidFileContents):
+    """Tests that -mfmt=num works with -c for single input file. SPIR-V binary
+    code output should be emitted as a list of hex numbers in the output file.
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-c', '-mfmt=num', '-o', 'output_file']
+    target_filename = 'output_file'
+    expected_file_contents = re.compile(MINIMAL_SHADER_NUM_FORMAT_PATTERN, re.S)
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtBinWorksWithDashC(expect.ValidObjectFile):
+    """Tests that -mfmt=bin works with -c for single input file. This test
+    should simply have the SPIR-V binary generated.
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-c', '-mfmt=bin']
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtCWithLinking(expect.ValidFileContents):
+    """Tests that -mfmt=c works when linkding is enabled (no -c specified).
+    SPIR-V binary code should be emitted as a C-style initializer list in the
+    output file.
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=c']
+    target_filename = 'a.spv'
+    expected_file_contents = re.compile(MINIMAL_SHADER_C_FORMAT_PATTERN, re.S)
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtNumWithLinking(expect.ValidFileContents):
+    """Tests that -mfmt=num works when linkding is enabled (no -c specified).
+    SPIR-V binary code should be emitted as a C-style initializer list in the
+    output file.
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=num']
+    target_filename = 'a.spv'
+    expected_file_contents = re.compile(MINIMAL_SHADER_NUM_FORMAT_PATTERN, re.S)
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtCErrorWhenOutputDisasembly(expect.ErrorMessage):
+    """Tests that specifying '-mfmt=c' when the compiler is set to
+    disassembly mode should trigger an error.
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=c', '-S', '-o', 'output_file']
+    expected_error = ("glslc: error: cannot emit output as a C-style "
+                      "initializer list when the output is not SPIR-V "
+                      "binary code\n")
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtNumErrorWhenOutputDisasembly(expect.ErrorMessage):
+    """Tests that specifying '-mfmt=num' when the compiler is set to
+    disassembly mode should trigger an error.
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=num', '-S', '-o', 'output_file']
+    expected_error = (
+        "glslc: error: cannot emit output as a list of hex numbers "
+        "when the output is not SPIR-V binary code\n")
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtBinErrorWhenOutputDisasembly(expect.ErrorMessage):
+    """Tests that specifying '-mfmt=bin' when the compiler is set to
+    disassembly mode should trigger an error.
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=bin', '-S', '-o', 'output_file']
+    expected_error = ("glslc: error: cannot emit output as a binary "
+                      "when the output is not SPIR-V binary code\n")
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtNumErrorWhenOutputPreprocess(expect.ErrorMessage):
+    """Tests that specifying '-mfmt=num' when the compiler is set to
+    preprocessing only mode should trigger an error.
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=num', '-E', '-o', 'output_file']
+    expected_error = (
+        "glslc: error: cannot emit output as a list of hex numbers "
+        "when the output is not SPIR-V binary code\n")
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtCErrorWithDashCapM(expect.ErrorMessage):
+    """Tests that specifying '-mfmt=c' should trigger an error when the
+    compiler is set to dump dependency info as the output (-M or -MM is
+    specified).
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=c', '-M', '-o', 'output_file']
+    expected_error = ("glslc: error: cannot emit output as a C-style "
+                      "initializer list when the output is not SPIR-V "
+                      "binary code\n")
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtCWorksWithDashCapMD(expect.ValidFileContents):
+    """Tests that -mfmt=c works with '-c -MD'. SPIR-V binary code
+    should be emitted as a C-style initializer list in the output file.
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=c', '-c', '-MD', '-o', 'output_file']
+    target_filename = 'output_file'
+    expected_file_contents = re.compile(MINIMAL_SHADER_C_FORMAT_PATTERN, re.S)
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtNumWorksWithDashCapMD(expect.ValidFileContents):
+    """Tests that -mfmt=num works with '-c -MD'. SPIR-V binary code
+    should be emitted as a C-style initializer list in the output file.
+    """
+    shader = FileShader(MINIMAL_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=num', '-c', '-MD', '-o', 'output_file']
+    target_filename = 'output_file'
+    expected_file_contents = re.compile(MINIMAL_SHADER_NUM_FORMAT_PATTERN, re.S)
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtCExitsElegantlyWithErrorInShader(expect.ErrorMessage):
+    """Tests that the compiler fails elegantly with -mfmt=c when there are
+    errors in the input shader.
+    """
+    shader = FileShader(ERROR_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=c']
+    expected_error = [shader, ':3: error: \'#error\' :\n',
+                      '1 error generated.\n']
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtNumExitsElegantlyWithErrorInShader(expect.ErrorMessage):
+    """Tests that the compiler fails elegantly with -mfmt=num when there are
+    errors in the input shader.
+    """
+    shader = FileShader(ERROR_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=num']
+    expected_error = [shader, ':3: error: \'#error\' :\n',
+                      '1 error generated.\n']
+
+
+@inside_glslc_testsuite('OptionMfmt')
+class TestFmtBinExitsElegantlyWithErrorInShader(expect.ErrorMessage):
+    """Tests that the compiler fails elegantly with -mfmt=binary when there are
+    errors in the input shader.
+    """
+    shader = FileShader(ERROR_SHADER, '.vert')
+    glslc_args = [shader, '-mfmt=bin']
+    expected_error = [shader, ':3: error: \'#error\' :\n',
+                      '1 error generated.\n']
diff --git a/glslc/test/option_std.py b/glslc/test/option_std.py
index 0c02be0..cce0d81 100644
--- a/glslc/test/option_std.py
+++ b/glslc/test/option_std.py
@@ -112,11 +112,11 @@
     shader2 = FileShader(core_vert_shader_without_version(), '.vert')
     shader3 = FileShader(
         '#version 310 es\n' + core_frag_shader_without_version(), '.frag')
-    glslc_args = ['-c', '-std=450compatibility', shader1, shader2, shader3]
+    glslc_args = ['-c', '-std=450core', shader1, shader2, shader3]
 
     expected_warning = [
         shader3, ': warning: (version, profile) forced to be (450, '
-        'compatibility), while in source code it is (310, es)\n'
+        'core), while in source code it is (310, es)\n'
         '1 warning generated.\n']
 
 
diff --git a/glslc/test/parameter_tests.py b/glslc/test/parameter_tests.py
index c52d15a..235b609 100644
--- a/glslc/test/parameter_tests.py
+++ b/glslc/test/parameter_tests.py
@@ -71,6 +71,10 @@
   -std=<value>      Version and profile for input files. Possible values
                     are concatenations of version and profile, e.g. 310es,
                     450core, etc.
+  -mfmt=<format>    Output SPIR-V binary code using the selected format. This
+                    option may be specified only when the compilation output is
+                    in SPIR-V binary code form. Available options include bin, c
+                    and num. By default the binary output format is bin.
   -M                Generate make dependencies. Implies -E and -w.
   -MM               An alias for -M.
   -MD               Generate make dependencies and compile.
diff --git a/libshaderc/Android.mk b/libshaderc/Android.mk
index 60a5b9d..4b1a74b 100644
--- a/libshaderc/Android.mk
+++ b/libshaderc/Android.mk
@@ -6,7 +6,7 @@
 LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)/include
 LOCAL_SRC_FILES:=src/shaderc.cc
 LOCAL_C_INCLUDES:=$(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES=shaderc_util
+LOCAL_STATIC_LIBRARIES=shaderc_util SPIRV-Tools
 LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti
 LOCAL_EXPORT_CPPFLAGS:=-std=c++11
 LOCAL_EXPORT_LDFLAGS:=-latomic
diff --git a/libshaderc/CMakeLists.txt b/libshaderc/CMakeLists.txt
index e32e8fc..3f979f7 100644
--- a/libshaderc/CMakeLists.txt
+++ b/libshaderc/CMakeLists.txt
@@ -16,7 +16,8 @@
 target_link_libraries(shaderc PRIVATE
   glslang OSDependent OGLCompiler glslang ${CMAKE_THREAD_LIBS_INIT})
 target_link_libraries(shaderc PRIVATE shaderc_util)
-target_link_libraries(shaderc PRIVATE SPIRV)
+target_link_libraries(shaderc PRIVATE SPIRV)  # from glslang
+target_link_libraries(shaderc PRIVATE SPIRV-Tools)
 
 
 shaderc_add_tests(
diff --git a/libshaderc/include/shaderc/shaderc.h b/libshaderc/include/shaderc/shaderc.h
index 7823671..279addb 100644
--- a/libshaderc/include/shaderc/shaderc.h
+++ b/libshaderc/include/shaderc/shaderc.h
@@ -44,6 +44,7 @@
   shaderc_glsl_default_geometry_shader,
   shaderc_glsl_default_tess_control_shader,
   shaderc_glsl_default_tess_evaluation_shader,
+  shaderc_spirv_assembly,
 } shaderc_shader_kind;
 
 typedef enum {
@@ -70,6 +71,7 @@
   shaderc_compilation_status_compilation_error,
   shaderc_compilation_status_internal_error,  // unexpected failure
   shaderc_compilation_status_null_result_object,
+  shaderc_compilation_status_invalid_assembly,
 } shaderc_compilation_status;
 
 // Usage examples:
@@ -154,7 +156,6 @@
 void shaderc_compile_options_set_generate_debug_info(
     shaderc_compile_options_t options);
 
-
 // Forces the GLSL language version and profile to a given pair. The version
 // number is the same as would appear in the #version annotation in the source.
 // Version and profile specified here overrides the #version annotation in the
@@ -197,13 +198,11 @@
 // The type parameter specifies the kind of inclusion request being made.
 // The requesting_source parameter specifies the name of the source containing
 // the #include request.  The includer owns the result object and its contents,
-// and both must remain valid until the release callback is called on the result object.
+// and both must remain valid until the release callback is called on the result
+// object.
 typedef shaderc_include_result* (*shaderc_include_resolve_fn)(
-    void* user_data,
-    const char* requested_source,
-    int type,
-    const char* requesting_source,
-    size_t include_depth);
+    void* user_data, const char* requested_source, int type,
+    const char* requesting_source, size_t include_depth);
 
 // An includer callback type for destroying an include result.
 typedef void (*shaderc_include_result_release_fn)(
@@ -214,7 +213,6 @@
     shaderc_compile_options_t options, shaderc_include_resolve_fn resolver,
     shaderc_include_result_release_fn result_releaser, void* user_data);
 
-
 // Sets the compiler mode to suppress warnings, overriding warnings-as-errors
 // mode. When both suppress-warnings and warnings-as-errors modes are
 // turned on, warning messages will be inhibited, and will not be emitted
@@ -281,6 +279,18 @@
     size_t source_text_size, shaderc_shader_kind shader_kind,
     const char* input_file_name, const char* entry_point_name,
     const shaderc_compile_options_t additional_options);
+
+// Takes an assembly string of the format defined in the SPIRV-Tools project
+// (https://github.com/KhronosGroup/SPIRV-Tools/blob/master/syntax.md),
+// assembles it into SPIR-V binary and a shaderc_compilation_result will be
+// returned to hold the results.
+// May be safely called from multiple threads without explicit synchronization.
+// If there was failure in allocating the compiler object, null will be
+// returned.
+shaderc_compilation_result_t shaderc_assemble_into_spv(
+    const shaderc_compiler_t compiler, const char* source_assembly,
+    size_t source_assembly_size);
+
 // The following functions, operating on shaderc_compilation_result_t objects,
 // offer only the basic thread-safety guarantee.
 
diff --git a/libshaderc/include/shaderc/shaderc.hpp b/libshaderc/include/shaderc/shaderc.hpp
index 5131995..269445d 100644
--- a/libshaderc/include/shaderc/shaderc.hpp
+++ b/libshaderc/include/shaderc/shaderc.hpp
@@ -167,10 +167,10 @@
   class IncluderInterface {
    public:
     // Handles shaderc_include_resolver_fn callbacks.
-    virtual shaderc_include_result* GetInclude(
-        const char* requested_source, shaderc_include_type type,
-        const char* requesting_source,
-        size_t include_depth) = 0;
+    virtual shaderc_include_result* GetInclude(const char* requested_source,
+                                               shaderc_include_type type,
+                                               const char* requesting_source,
+                                               size_t include_depth) = 0;
 
     // Handles shaderc_include_result_release_fn callbacks.
     virtual void ReleaseInclude(shaderc_include_result* data) = 0;
@@ -183,9 +183,8 @@
     includer_ = std::move(includer);
     shaderc_compile_options_set_include_callbacks(
         options_,
-        [](void* user_data, const char* requested_source,
-           int type, const char* requesting_source,
-           size_t include_depth) {
+        [](void* user_data, const char* requested_source, int type,
+           const char* requesting_source, size_t include_depth) {
           auto* includer = static_cast<IncluderInterface*>(user_data);
           return includer->GetInclude(requested_source,
                                       (shaderc_include_type)type,
@@ -323,6 +322,27 @@
                             input_file_name);
   }
 
+  // Assembles the given SPIR-V assembly and returns a SPIR-V binary module
+  // compilation result.
+  // The assembly should follow the syntax defined in the SPIRV-Tools project
+  // (https://github.com/KhronosGroup/SPIRV-Tools/blob/master/syntax.md).
+  // It is valid for the returned CompilationResult object to outlive this
+  // compiler object.
+  SpvCompilationResult AssembleToSpv(const char* source_assembly,
+                                     size_t source_assembly_size) const {
+    return SpvCompilationResult(shaderc_assemble_into_spv(
+        compiler_, source_assembly, source_assembly_size));
+  }
+
+  // Assembles the given SPIR-V assembly and returns a SPIR-V binary module
+  // compilation result.
+  // Like the first AssembleToSpv method but the source is provided as a
+  // std::string.
+  SpvCompilationResult AssembleToSpv(const std::string& source_assembly) const {
+    return SpvCompilationResult(shaderc_assemble_into_spv(
+        compiler_, source_assembly.data(), source_assembly.size()));
+  }
+
   // Compiles the given source GLSL and returns the SPIR-V assembly text
   // compilation result.
   // Options are similar to the first CompileToSpv method.
diff --git a/libshaderc/src/common_shaders_for_test.h b/libshaderc/src/common_shaders_for_test.h
index c4c3c84..07f6bf6 100644
--- a/libshaderc/src/common_shaders_for_test.h
+++ b/libshaderc/src/common_shaders_for_test.h
@@ -32,12 +32,12 @@
 
 // The minimal shader that needs valueless predefinition of 'E' to compile.
 const char kValuelessPredefinitionShader[] =
-      "#version 140\n"
-      "#ifdef E\n"
-      "void main(){}\n"
-      "#else\n"
-      "#error\n"
-      "#endif";
+    "#version 140\n"
+    "#ifdef E\n"
+    "void main(){}\n"
+    "#else\n"
+    "#error\n"
+    "#endif";
 
 // By default the compiler will emit a warning on line 2 complaining
 // that 'float' is a deprecated attribute in version 130.  Use verison 140
@@ -196,6 +196,26 @@
     "               OpReturn\n"
     "               OpFunctionEnd\n"};
 
+const char kMinimalShaderAssembly[] = R"(
+    ; SPIR-V
+    ; Version: 1.0
+    ; Generator: Khronos Glslang Reference Front End; 1
+    ; Bound: 6
+    ; Schema: 0
+
+         OpCapability Shader
+    %1 = OpExtInstImport "GLSL.std.450"
+         OpMemoryModel Logical GLSL450
+         OpEntryPoint Vertex %4 "main"
+         OpSource ESSL 310
+         OpName %4 "main"
+    %2 = OpTypeVoid
+    %3 = OpTypeFunction %2
+    %4 = OpFunction %2 None %3
+    %5 = OpLabel
+         OpReturn
+         OpFunctionEnd)";
+
 #ifdef __cplusplus
 }
 #endif  // __cplusplus
diff --git a/libshaderc/src/shaderc.cc b/libshaderc/src/shaderc.cc
index 4d83b45..fe33f44 100644
--- a/libshaderc/src/shaderc.cc
+++ b/libshaderc/src/shaderc.cc
@@ -25,6 +25,7 @@
 #include "libshaderc_util/compiler.h"
 #include "libshaderc_util/counting_includer.h"
 #include "libshaderc_util/resources.h"
+#include "libshaderc_util/spirv_tools_wrapper.h"
 #include "libshaderc_util/version_profile.h"
 
 #if (defined(_MSC_VER) && !defined(_CPPUNWIND)) || !defined(__EXCEPTIONS)
@@ -62,6 +63,7 @@
     case shaderc_glsl_default_geometry_shader:
     case shaderc_glsl_default_tess_control_shader:
     case shaderc_glsl_default_tess_evaluation_shader:
+    case shaderc_spirv_assembly:
       return EShLangCount;
   }
   assert(0 && "Unhandled shaderc_shader_kind");
@@ -149,6 +151,8 @@
         return EShLangTessControl;
       case shaderc_glsl_default_tess_evaluation_shader:
         return EShLangTessEvaluation;
+    case shaderc_spirv_assembly:
+        return EShLangCount;
     }
     assert(0 && "Unhandled shaderc_shader_kind");
     return EShLangCount;
@@ -173,8 +177,7 @@
  private:
   // Check the validity of the callbacks.
   bool AreValidCallbacks() const {
-    return resolver_ != nullptr &&
-           result_releaser_ != nullptr;
+    return resolver_ != nullptr && result_releaser_ != nullptr;
   }
 
   // Maps a shaderc_include_type to the correpsonding Glslang include type.
@@ -202,8 +205,7 @@
   virtual glslang::TShader::Includer::IncludeResult* include_delegate(
       const char* requested_source,
       glslang::TShader::Includer::IncludeType type,
-      const char* requesting_source,
-      size_t include_depth) override {
+      const char* requesting_source, size_t include_depth) override {
     if (!AreValidCallbacks()) {
       const char kUnexpectedIncludeError[] =
           "#error unexpected include directive";
@@ -276,7 +278,6 @@
   options->compiler.SetGenerateDebugInfo();
 }
 
-
 void shaderc_compile_options_set_forced_version_profile(
     shaderc_compile_options_t options, int version, shaderc_profile profile) {
   // Transfer the profile parameter from public enum type to glslang internal
@@ -299,16 +300,13 @@
 }
 
 void shaderc_compile_options_set_include_callbacks(
-    shaderc_compile_options_t options,
-    shaderc_include_resolve_fn resolver,
-    shaderc_include_result_release_fn result_releaser,
-    void* user_data) {
+    shaderc_compile_options_t options, shaderc_include_resolve_fn resolver,
+    shaderc_include_result_release_fn result_releaser, void* user_data) {
   options->include_resolver = resolver;
   options->include_result_releaser = result_releaser;
   options->include_user_data = user_data;
 }
 
-
 void shaderc_compile_options_set_suppress_warnings(
     shaderc_compile_options_t options) {
   options->compiler.SetSuppressWarnings();
@@ -344,10 +342,14 @@
     const char* input_file_name, const char* entry_point_name,
     const shaderc_compile_options_t additional_options,
     shaderc_util::Compiler::OutputType output_type) {
-  shaderc_compilation_result_t result =
-      new (std::nothrow) shaderc_compilation_result;
-  if (!result) {
-    return nullptr;
+  auto* result = new (std::nothrow) shaderc_compilation_result_vector;
+  if (!result) return nullptr;
+
+  if (!input_file_name) {
+    result->messages = "Input file name string was null.";
+    result->num_errors = 1;
+    result->compilation_status = shaderc_compilation_status_compilation_error;
+    return result;
   }
   result->compilation_status = shaderc_compilation_status_invalid_stage;
   bool compilation_succeeded = false;  // In case we exit early.
@@ -364,10 +366,9 @@
         shaderc_util::string_piece(source_text, source_text + source_text_size);
     StageDeducer stage_deducer(shader_kind);
     if (additional_options) {
-      InternalFileIncluder includer(
-                  additional_options->include_resolver,
-                  additional_options->include_result_releaser,
-                  additional_options->include_user_data);
+      InternalFileIncluder includer(additional_options->include_resolver,
+                                    additional_options->include_result_releaser,
+                                    additional_options->include_user_data);
       // Depends on return value optimization to avoid extra copy.
       std::tie(compilation_succeeded, compilation_output_data,
                compilation_output_data_size_in_bytes) =
@@ -376,10 +377,8 @@
               // stage_deducer has a flag: error_, which we need to check later.
               // We need to make this a reference wrapper, so that std::function
               // won't make a copy for this callable object.
-              std::ref(stage_deducer),
-              includer,
-              output_type, &errors, &total_warnings, &total_errors,
-              compiler->initializer);
+              std::ref(stage_deducer), includer, output_type, &errors,
+              &total_warnings, &total_errors, compiler->initializer);
     } else {
       // Compile with default options.
       InternalFileIncluder includer;
@@ -387,12 +386,12 @@
                compilation_output_data_size_in_bytes) =
           shaderc_util::Compiler().Compile(
               source_string, forced_stage, input_file_name_str,
-              std::ref(stage_deducer), includer, output_type,
-              &errors, &total_warnings, &total_errors, compiler->initializer);
+              std::ref(stage_deducer), includer, output_type, &errors,
+              &total_warnings, &total_errors, compiler->initializer);
     }
 
     result->messages = errors.str();
-    result->output_data = std::move(compilation_output_data);
+    result->SetOutputData(std::move(compilation_output_data));
     result->output_data_size = compilation_output_data_size_in_bytes;
     result->num_warnings = total_warnings;
     result->num_errors = total_errors;
@@ -447,6 +446,39 @@
       shaderc_util::Compiler::OutputType::PreprocessedText);
 }
 
+shaderc_compilation_result_t shaderc_assemble_into_spv(
+    const shaderc_compiler_t compiler, const char* source_assembly,
+    size_t source_assembly_size) {
+  auto* result = new (std::nothrow) shaderc_compilation_result_spv_binary;
+  if (!result) return nullptr;
+  result->compilation_status = shaderc_compilation_status_invalid_assembly;
+  if (!compiler->initializer) return result;
+  if (source_assembly == nullptr) return result;
+
+  TRY_IF_EXCEPTIONS_ENABLED {
+    spv_binary assembling_output_data = nullptr;
+    std::string errors;
+    const bool assembling_succeeded = shaderc_util::SpirvToolsAssemble(
+        {source_assembly, source_assembly + source_assembly_size},
+        &assembling_output_data, &errors);
+    result->num_errors = !assembling_succeeded;
+    if (assembling_succeeded) {
+      result->SetOutputData(assembling_output_data);
+      result->output_data_size =
+          assembling_output_data->wordCount * sizeof(uint32_t);
+      result->compilation_status = shaderc_compilation_status_success;
+    } else {
+      result->messages = std::move(errors);
+      result->compilation_status = shaderc_compilation_status_invalid_assembly;
+    }
+  }
+  CATCH_IF_EXCEPTIONS_ENABLED(...) {
+    result->compilation_status = shaderc_compilation_status_internal_error;
+  }
+
+  return result;
+}
+
 size_t shaderc_result_get_length(const shaderc_compilation_result_t result) {
   return result->output_data_size;
 }
@@ -463,7 +495,7 @@
 
 const char* shaderc_result_get_bytes(
     const shaderc_compilation_result_t result) {
-  return reinterpret_cast<const char*>(result->output_data.data());
+  return result->GetBytes();
 }
 
 void shaderc_result_release(shaderc_compilation_result_t result) {
diff --git a/libshaderc/src/shaderc_cpp_test.cc b/libshaderc/src/shaderc_cpp_test.cc
index cd5bcad..0ba4c97 100644
--- a/libshaderc/src/shaderc_cpp_test.cc
+++ b/libshaderc/src/shaderc_cpp_test.cc
@@ -129,6 +129,18 @@
     return compilation_result.GetErrorMessage();
   }
 
+  // Assembles the given SPIR-V assembly and returns true on success.
+  bool AssemblingSuccess(const std::string& shader) const {
+    return compiler_.AssembleToSpv(shader).GetCompilationStatus() ==
+           shaderc_compilation_status_success;
+  }
+
+  // Assembles the given SPIR-V assembly and returns true if the result contains
+  // a valid SPIR-V module.
+  bool AssemblingValid(const std::string& shader) const {
+    return IsValidSpv(compiler_.AssembleToSpv(shader));
+  }
+
   // Compiles a shader, expects compilation success, and returns the output
   // bytes.
   // The input file name is set to "shader" by default.
@@ -205,6 +217,10 @@
   EXPECT_FALSE(CompilationSuccess("", shaderc_glsl_fragment_shader));
 }
 
+TEST_F(CppInterface, AssembleEmptyString) {
+  EXPECT_TRUE(AssemblingSuccess(""));
+}
+
 TEST_F(CppInterface, ResultObjectMoves) {
   SpvCompilationResult result = compiler_.CompileGlslToSpv(
       kMinimalShader, shaderc_glsl_vertex_shader, "shader");
@@ -219,6 +235,13 @@
   EXPECT_FALSE(CompilationSuccess("jfalkds", shaderc_glsl_fragment_shader));
 }
 
+TEST_F(CppInterface, AssembleGarbageString) {
+  const auto result = compiler_.AssembleToSpv("jfalkds");
+  EXPECT_FALSE(CompilationResultIsSuccess(result));
+  EXPECT_EQ(0u, result.GetNumWarnings());
+  EXPECT_EQ(1u, result.GetNumErrors());
+}
+
 TEST_F(CppInterface, MinimalShader) {
   EXPECT_TRUE(CompilesToValidSpv(compiler_, kMinimalShader,
                                  shaderc_glsl_vertex_shader));
@@ -226,6 +249,10 @@
                                  shaderc_glsl_fragment_shader));
 }
 
+TEST_F(CppInterface, AssembleMinimalShader) {
+  EXPECT_TRUE(AssemblingValid(kMinimalShaderAssembly));
+}
+
 TEST_F(CppInterface, BasicOptions) {
   EXPECT_TRUE(CompilesToValidSpv(compiler_, kMinimalShader,
                                  shaderc_glsl_vertex_shader, options_));
diff --git a/libshaderc/src/shaderc_private.h b/libshaderc/src/shaderc_private.h
index f15141d..a11d449 100644
--- a/libshaderc/src/shaderc_private.h
+++ b/libshaderc/src/shaderc_private.h
@@ -21,16 +21,17 @@
 
 #include "shaderc/shaderc.h"
 
+#include "spirv-tools/libspirv.h"
+
 // Described in shaderc.h.
 struct shaderc_compilation_result {
-  // Compilation output data. In normal compilation mode, it contains the
-  // compiled SPIR-V binary code. In disassembly and preprocessing-only mode, it
-  // contains a null-terminated string which is the text output. For text
-  // output, extra bytes with value 0x00 might be appended to complete the last
-  // uint32_t element.
-  std::vector<uint32_t> output_data;
+  virtual ~shaderc_compilation_result() {}
+
+  // Returns the data from this compilation as a sequence of bytes.
+  virtual const char* GetBytes() const = 0;
+
   // The size of the output data in term of bytes.
-  size_t output_data_size;
+  size_t output_data_size = 0;
   // Compilation messages.
   std::string messages;
   // Number of errors.
@@ -42,6 +43,46 @@
       shaderc_compilation_status_null_result_object;
 };
 
+// Compilation result class using a vector for holding the compilation
+// output data.
+class shaderc_compilation_result_vector : public shaderc_compilation_result {
+ public:
+  ~shaderc_compilation_result_vector() = default;
+
+  void SetOutputData(std::vector<uint32_t>&& data) {
+    output_data_ = std::move(data);
+  }
+
+  const char* GetBytes() const override {
+    return reinterpret_cast<const char*>(output_data_.data());
+  }
+
+ private:
+  // Compilation output data. In normal compilation mode, it contains the
+  // compiled SPIR-V binary code. In disassembly and preprocessing-only mode, it
+  // contains a null-terminated string which is the text output. For text
+  // output, extra bytes with value 0x00 might be appended to complete the last
+  // uint32_t element.
+  std::vector<uint32_t> output_data_;
+};
+
+// Compilation result class using a spv_binary for holding the compilation
+// output data.
+class shaderc_compilation_result_spv_binary
+    : public shaderc_compilation_result {
+ public:
+  ~shaderc_compilation_result_spv_binary() { spvBinaryDestroy(output_data_); }
+
+  void SetOutputData(spv_binary data) { output_data_ = data; }
+
+  const char* GetBytes() const override {
+    return reinterpret_cast<const char*>(output_data_->code);
+  }
+
+ private:
+  spv_binary output_data_ = nullptr;
+};
+
 namespace shaderc_util {
 class GlslInitializer;
 }
diff --git a/libshaderc/src/shaderc_test.cc b/libshaderc/src/shaderc_test.cc
index 50afe8e..b4ce44b 100644
--- a/libshaderc/src/shaderc_test.cc
+++ b/libshaderc/src/shaderc_test.cc
@@ -99,10 +99,10 @@
   return shaderc_compile_into_spv(compiler, shader.c_str(), shader.size(), kind,
                                   input_file_name, "", options);
 }
-// RAII class for shaderc_compilation_result.
+// RAII class for shaderc_compilation_result. Used for shader compilation.
 class Compilation {
  public:
-  // Compiles shader, keeping the result.
+  // Compiles shader and keeps the result.
   Compilation(const shaderc_compiler_t compiler, const std::string& shader,
               shaderc_shader_kind kind, const char* input_file_name,
               const shaderc_compile_options_t options = nullptr,
@@ -118,6 +118,22 @@
   shaderc_compilation_result_t compiled_result_;
 };
 
+// RAII class for shaderc_compilation_result. Used for shader assembling.
+class Assembling {
+ public:
+  // Assembles shader and keeps the result.
+  Assembling(const shaderc_compiler_t compiler, const std::string& assembly)
+      : compiled_result_(shaderc_assemble_into_spv(compiler, assembly.data(),
+                                                   assembly.size())) {}
+
+  ~Assembling() { shaderc_result_release(compiled_result_); }
+
+  shaderc_compilation_result_t result() const { return compiled_result_; }
+
+ private:
+  shaderc_compilation_result_t compiled_result_;
+};
+
 struct CleanupOptions {
   void operator()(shaderc_compile_options_t options) const {
     shaderc_compile_options_release(options);
@@ -145,13 +161,9 @@
          shaderc_compilation_status_success;
 }
 
-// Compiles a shader and returns true if the result is valid SPIR-V.
-bool CompilesToValidSpv(Compiler& compiler, const std::string& shader,
-                        shaderc_shader_kind kind,
-                        const shaderc_compile_options_t options = nullptr) {
-  const Compilation comp(compiler.get_compiler_handle(), shader, kind, "shader",
-                         options, OutputType::SpirvBinary);
-  auto result = comp.result();
+// Returns true if the given result contains a SPIR-V module that contains
+// at least the number of bytes of the header and the correct magic number.
+bool ResultContainsValidSpv(shaderc_compilation_result_t result) {
   if (!CompilationResultIsSuccess(result)) return false;
   size_t length = shaderc_result_get_length(result);
   if (length < 20) return false;
@@ -160,6 +172,15 @@
   return bytes[0] == spv::MagicNumber;
 }
 
+// Compiles a shader and returns true if the result is valid SPIR-V.
+bool CompilesToValidSpv(Compiler& compiler, const std::string& shader,
+                        shaderc_shader_kind kind,
+                        const shaderc_compile_options_t options = nullptr) {
+  const Compilation comp(compiler.get_compiler_handle(), shader, kind, "shader",
+                         options, OutputType::SpirvBinary);
+  return ResultContainsValidSpv(comp.result());
+}
+
 // A testing class to test the compilation of a string with or without options.
 // This class wraps the initailization of compiler and compiler options and
 // groups the result checking methods. Subclass tests can access the compiler
@@ -194,11 +215,13 @@
   const std::string CompilationErrors(
       const std::string& shader, shaderc_shader_kind kind,
       const shaderc_compile_options_t options = nullptr,
-      OutputType output_type = OutputType::SpirvBinary) {
+      OutputType output_type = OutputType::SpirvBinary,
+      const char* source_name = "shader") {
     const Compilation comp(compiler_.get_compiler_handle(), shader, kind,
-                           "shader", options, output_type);
+                           source_name, options, output_type);
     EXPECT_FALSE(CompilationResultIsSuccess(comp.result())) << kind << '\n'
                                                             << shader;
+    EXPECT_EQ(0u, shaderc_result_get_length(comp.result()));
     return shaderc_result_get_error_message(comp.result());
   };
 
@@ -237,6 +260,27 @@
   CompileStringTest() : options_(shaderc_compile_options_initialize()) {}
 };
 
+// A testing class to test the assembling of a string.
+// This class wraps the initailization of compiler and groups the result
+// checking methods. Subclass tests can access the compiler object to set their
+// properties.
+class AssembleStringTest : public testing::Test {
+ protected:
+  // Assembles the given assembly and returns true on success.
+  bool AssemblingSuccess(const std::string& assembly) {
+    return CompilationResultIsSuccess(
+        Assembling(compiler_.get_compiler_handle(), assembly).result());
+  }
+
+  bool AssemblingValid(const std::string& assembly) {
+    const auto assembling =
+        Assembling(compiler_.get_compiler_handle(), assembly);
+    return ResultContainsValidSpv(assembling.result());
+  }
+
+  Compiler compiler_;
+};
+
 // Name holders so that we have test cases being grouped with only one real
 // compilation class.
 using CompileStringWithOptionsTest = CompileStringTest;
@@ -248,12 +292,25 @@
   EXPECT_FALSE(CompilationSuccess("", shaderc_glsl_fragment_shader));
 }
 
+TEST_F(AssembleStringTest, EmptyString) {
+  ASSERT_NE(nullptr, compiler_.get_compiler_handle());
+  EXPECT_TRUE(AssemblingSuccess(""));
+}
+
 TEST_F(CompileStringTest, GarbageString) {
   ASSERT_NE(nullptr, compiler_.get_compiler_handle());
   EXPECT_FALSE(CompilationSuccess("jfalkds", shaderc_glsl_vertex_shader));
   EXPECT_FALSE(CompilationSuccess("jfalkds", shaderc_glsl_fragment_shader));
 }
 
+TEST_F(AssembleStringTest, GarbageString) {
+  ASSERT_NE(nullptr, compiler_.get_compiler_handle());
+  auto assembling = Assembling(compiler_.get_compiler_handle(), "jfalkds");
+  EXPECT_FALSE(CompilationResultIsSuccess(assembling.result()));
+  EXPECT_EQ(1u, shaderc_result_get_num_errors(assembling.result()));
+  EXPECT_EQ(0u, shaderc_result_get_num_warnings(assembling.result()));
+}
+
 TEST_F(CompileStringTest, ReallyLongShader) {
   ASSERT_NE(nullptr, compiler_.get_compiler_handle());
   std::string minimal_shader = "";
@@ -275,6 +332,11 @@
                                  shaderc_glsl_fragment_shader));
 }
 
+TEST_F(AssembleStringTest, MinimalShader) {
+  ASSERT_NE(nullptr, compiler_.get_compiler_handle());
+  EXPECT_TRUE(AssemblingValid(kMinimalShaderAssembly));
+}
+
 TEST_F(CompileStringTest, WorksWithCompileOptions) {
   ASSERT_NE(nullptr, compiler_.get_compiler_handle());
   EXPECT_TRUE(CompilesToValidSpv(compiler_, kMinimalShader,
@@ -404,7 +466,6 @@
                         options_.get(), OutputType::SpirvAssemblyText);
   EXPECT_THAT(disassembly_text, HasSubstr("Capability Shader"));
   EXPECT_THAT(disassembly_text, HasSubstr("MemoryModel"));
-
 }
 
 TEST_F(CompileStringWithOptionsTest, DisassembleMinimalShader) {
@@ -680,8 +741,8 @@
 
   // Wrapper for the corresponding member function.
   static shaderc_include_result* GetIncluderResponseWrapper(
-      void* user_data, const char* filename, int,
-      const char* includer, size_t include_depth) {
+      void* user_data, const char* filename, int, const char* includer,
+      size_t include_depth) {
     return static_cast<TestIncluder*>(user_data)->GetInclude(filename);
   }
 
@@ -1116,4 +1177,23 @@
         ParseVersionProfileTestCase("", false),
     }));
 
+TEST_F(CompileStringTest, NullSourceNameFailsCompilingToBinary) {
+  EXPECT_THAT(CompilationErrors(kEmpty310ESShader, shaderc_glsl_vertex_shader,
+                                nullptr, OutputType::SpirvBinary, nullptr),
+              HasSubstr("Input file name string was null."));
+}
+
+TEST_F(CompileStringTest, NullSourceNameFailsCompilingToAssemblyText) {
+  EXPECT_THAT(
+      CompilationErrors(kEmpty310ESShader, shaderc_glsl_vertex_shader, nullptr,
+                        OutputType::SpirvAssemblyText, nullptr),
+      HasSubstr("Input file name string was null."));
+}
+
+TEST_F(CompileStringTest, NullSourceNameFailsCompilingToPreprocessedText) {
+  EXPECT_THAT(CompilationErrors(kEmpty310ESShader, shaderc_glsl_vertex_shader,
+                                nullptr, OutputType::PreprocessedText, nullptr),
+              HasSubstr("Input file name string was null."));
+}
+
 }  // anonymous namespace
diff --git a/libshaderc_util/Android.mk b/libshaderc_util/Android.mk
index fb82701..e561588 100644
--- a/libshaderc_util/Android.mk
+++ b/libshaderc_util/Android.mk
@@ -10,6 +10,7 @@
 		src/message.cc \
 		src/resources.cc \
 		src/shader_stage.cc \
+		src/spirv_tools_wrapper.cc \
 		src/version_profile.cc
 LOCAL_STATIC_LIBRARIES:=glslang SPIRV-Tools
 LOCAL_C_INCLUDES:=$(LOCAL_PATH)/include
diff --git a/libshaderc_util/CMakeLists.txt b/libshaderc_util/CMakeLists.txt
index bb32520..284645b 100644
--- a/libshaderc_util/CMakeLists.txt
+++ b/libshaderc_util/CMakeLists.txt
@@ -8,6 +8,7 @@
   include/libshaderc_util/mutex.h
   include/libshaderc_util/message.h
   include/libshaderc_util/resources.h
+  include/libshaderc_util/spirv_tools_wrapper.h
   include/libshaderc_util/string_piece.h
   include/libshaderc_util/universal_unistd.h
   include/libshaderc_util/version_profile.h
@@ -17,6 +18,7 @@
   src/message.cc
   src/resources.cc
   src/shader_stage.cc
+  src/spirv_tools_wrapper.cc
   src/version_profile.cc
 )
 
@@ -54,7 +56,8 @@
 
 # This target copies content of testdata into the build directory.
 add_custom_target(testdata COMMAND
-  ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/testdata/copy-to-build.cmake)
+  ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/testdata/copy-to-build.cmake
+  COMMENT "Copy testdata into build directory")
 
 if(${SHADERC_ENABLE_TESTS})
   add_dependencies(shaderc_util_file_finder_test testdata)
diff --git a/libshaderc_util/include/libshaderc_util/spirv_tools_wrapper.h b/libshaderc_util/include/libshaderc_util/spirv_tools_wrapper.h
new file mode 100644
index 0000000..83a31e1
--- /dev/null
+++ b/libshaderc_util/include/libshaderc_util/spirv_tools_wrapper.h
@@ -0,0 +1,39 @@
+// Copyright 2016 The Shaderc Authors. All rights reserved.
+//
+// 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 LIBSHADERC_UTIL_INC_SPIRV_TOOLS_WRAPPER_H
+#define LIBSHADERC_UTIL_INC_SPIRV_TOOLS_WRAPPER_H
+
+#include <string>
+#include <vector>
+
+#include "libshaderc_util/string_piece.h"
+
+#include "spirv-tools/libspirv.h"
+
+namespace shaderc_util {
+// Assembles the given assembly. On success, returns true, writes the assembled
+// binary to *binary, and clears *errors. Otherwise, writes the error message
+// into *errors.
+bool SpirvToolsAssemble(const string_piece assembly, spv_binary* binary,
+                        std::string* errors);
+
+// Disassembles the given binary. Returns true and writes the disassembled text
+// to *text_or_error if successful. Otherwise, writes the error message to
+// *text_or_error.
+bool SpirvToolsDisassemble(const std::vector<uint32_t>& binary,
+                           std::string* text_or_error);
+}  // namespace shaderc_util
+
+#endif  // LIBSHADERC_UTIL_INC_SPIRV_TOOLS_WRAPPER_H
diff --git a/libshaderc_util/src/compiler.cc b/libshaderc_util/src/compiler.cc
index 7f24aa5..b7743eb 100644
--- a/libshaderc_util/src/compiler.cc
+++ b/libshaderc_util/src/compiler.cc
@@ -15,8 +15,6 @@
 #include "libshaderc_util/compiler.h"
 
 #include <cstdint>
-#include <fstream>
-#include <iostream>
 #include <tuple>
 
 #include "libshaderc_util/format.h"
@@ -24,11 +22,10 @@
 #include "libshaderc_util/message.h"
 #include "libshaderc_util/resources.h"
 #include "libshaderc_util/shader_stage.h"
+#include "libshaderc_util/spirv_tools_wrapper.h"
 #include "libshaderc_util/string_piece.h"
 #include "libshaderc_util/version_profile.h"
 
-#include "spirv-tools/libspirv.h"
-
 #include "SPIRV/GlslangToSpv.h"
 
 namespace {
@@ -67,43 +64,6 @@
   directive = directive.strip("\" \n");
   return std::make_pair(line, directive);
 }
-
-// Writes the message contained in the diagnostic parameter to *dest. Assumes
-// the diagnostic message is reported for a binary location.
-void OutputSpvToolsDiagnostic(spv_diagnostic diagnostic, std::string* dest) {
-  assert(!diagnostic->isTextSource);
-
-  std::ostringstream os;
-  os << diagnostic->position.index << ": " << diagnostic->error;
-  *dest = os.str();
-}
-
-// Disassembles the given binary. Returns SPV_SUCCESS and writes the
-// disassembled text to *text_or_error if successful. Otherwise, writes the
-// error message to *text_or_error.
-spv_result_t DisassembleBinary(const std::vector<uint32_t>& binary,
-                               std::string* text_or_error) {
-  auto spvtools_context = spvContextCreate(SPV_ENV_UNIVERSAL_1_0);
-  spv_text disassembled_text = nullptr;
-  spv_diagnostic spvtools_diagnostic = nullptr;
-
-  spv_result_t result =
-      spvBinaryToText(spvtools_context, binary.data(), binary.size(),
-                      SPV_BINARY_TO_TEXT_OPTION_INDENT, &disassembled_text,
-                      &spvtools_diagnostic);
-  if (result == SPV_SUCCESS) {
-    text_or_error->assign(disassembled_text->str, disassembled_text->length);
-  } else {
-    OutputSpvToolsDiagnostic(spvtools_diagnostic, text_or_error);
-  }
-
-  spvDiagnosticDestroy(spvtools_diagnostic);
-  spvTextDestroy(disassembled_text);
-  spvContextDestroy(spvtools_context);
-
-  return result;
-}
-
 }  // anonymous namespace
 
 namespace shaderc_util {
@@ -224,7 +184,7 @@
   glslang::GlslangToSpv(*program.getIntermediate(used_shader_stage), spirv);
   if (output_type == OutputType::SpirvAssemblyText) {
     std::string text_or_error;
-    if (DisassembleBinary(spirv, &text_or_error) != SPV_SUCCESS) {
+    if (!SpirvToolsDisassemble(spirv, &text_or_error)) {
       *error_stream << "shaderc: internal error: compilation succeeded but "
                        "failed to disassemble: "
                     << text_or_error << "\n";
diff --git a/libshaderc_util/src/spirv_tools_wrapper.cc b/libshaderc_util/src/spirv_tools_wrapper.cc
new file mode 100644
index 0000000..96a40b0
--- /dev/null
+++ b/libshaderc_util/src/spirv_tools_wrapper.cc
@@ -0,0 +1,82 @@
+// Copyright 2016 The Shaderc Authors. All rights reserved.
+//
+// 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 "libshaderc_util/spirv_tools_wrapper.h"
+
+#include <cassert>
+#include <sstream>
+
+namespace {
+
+// Writes the message contained in the diagnostic parameter to *dest. Assumes
+// the diagnostic message is reported for a binary location.
+void SpirvToolsOutputDiagnostic(spv_diagnostic diagnostic, std::string* dest) {
+  std::ostringstream os;
+  if (diagnostic->isTextSource) {
+    os << diagnostic->position.line + 1 << ":"
+       << diagnostic->position.column + 1;
+  } else {
+    os << diagnostic->position.index;
+  }
+  os << ": " << diagnostic->error;
+  *dest = os.str();
+}
+
+}  // anonymous namespace
+
+namespace shaderc_util {
+
+bool SpirvToolsDisassemble(const std::vector<uint32_t>& binary,
+                           std::string* text_or_error) {
+  auto spvtools_context = spvContextCreate(SPV_ENV_VULKAN_1_0);
+  spv_text disassembled_text = nullptr;
+  spv_diagnostic spvtools_diagnostic = nullptr;
+
+  const bool result =
+      spvBinaryToText(spvtools_context, binary.data(), binary.size(),
+                      SPV_BINARY_TO_TEXT_OPTION_INDENT, &disassembled_text,
+                      &spvtools_diagnostic) == SPV_SUCCESS;
+  if (result) {
+    text_or_error->assign(disassembled_text->str, disassembled_text->length);
+  } else {
+    SpirvToolsOutputDiagnostic(spvtools_diagnostic, text_or_error);
+  }
+
+  spvDiagnosticDestroy(spvtools_diagnostic);
+  spvTextDestroy(disassembled_text);
+  spvContextDestroy(spvtools_context);
+
+  return result;
+}
+
+bool SpirvToolsAssemble(const string_piece assembly, spv_binary* binary,
+                        std::string* errors) {
+  auto spvtools_context = spvContextCreate(SPV_ENV_VULKAN_1_0);
+  spv_diagnostic spvtools_diagnostic = nullptr;
+
+  *binary = nullptr;
+  errors->clear();
+
+  const bool result =
+      spvTextToBinary(spvtools_context, assembly.data(), assembly.size(),
+                      binary, &spvtools_diagnostic) == SPV_SUCCESS;
+  if (!result) SpirvToolsOutputDiagnostic(spvtools_diagnostic, errors);
+
+  spvDiagnosticDestroy(spvtools_diagnostic);
+  spvContextDestroy(spvtools_context);
+
+  return result;
+}
+
+}  // namespace shaderc_util
diff --git a/third_party/Android.mk b/third_party/Android.mk
index ed07147..d19c025 100644
--- a/third_party/Android.mk
+++ b/third_party/Android.mk
@@ -12,6 +12,7 @@
 LOCAL_SRC_FILES:= \
 	SPIRV/GlslangToSpv.cpp \
 	SPIRV/InReadableOrder.cpp \
+	SPIRV/Logger.cpp \
 	SPIRV/SPVRemapper.cpp \
 	SPIRV/SpvBuilder.cpp \
 	SPIRV/disassemble.cpp \
@@ -46,8 +47,11 @@
 LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti
 LOCAL_SRC_FILES:= \
 		hlsl/hlslGrammar.cpp \
+		hlsl/hlslOpMap.cpp \
+		hlsl/hlslParseables.cpp \
 		hlsl/hlslParseHelper.cpp \
-		hlsl/hlslScanContext.cpp
+		hlsl/hlslScanContext.cpp \
+		hlsl/hlslTokenStream.cpp
 LOCAL_C_INCLUDES:=$(GLSLANG_LOCAL_PATH) \
 	$(GLSLANG_LOCAL_PATH)/hlsl
 include $(BUILD_STATIC_LIBRARY)
@@ -76,6 +80,7 @@
 		glslang/MachineIndependent/parseConst.cpp \
 		glslang/MachineIndependent/ParseHelper.cpp \
 		glslang/MachineIndependent/PoolAlloc.cpp \
+		glslang/MachineIndependent/propagateNoContraction.cpp \
 		glslang/MachineIndependent/reflection.cpp \
 		glslang/MachineIndependent/RemoveTree.cpp \
 		glslang/MachineIndependent/Scan.cpp \
@@ -100,34 +105,63 @@
 SPVTOOLS_LOCAL_PATH := $(THIRD_PARTY_PATH)/spirv-tools
 LOCAL_PATH := $(SPVTOOLS_LOCAL_PATH)
 SPVTOOLS_OUT_PATH=$(abspath $(TARGET_OUT))
+SPVHEADERS_LOCAL_PATH := $(THIRD_PARTY_PATH)/spirv-tools/external/spirv-headers
+
+# Locations of grammar files.
+SPV_CORE10_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/1.0/spirv.core.grammar.json
+SPV_CORE11_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/1.1/spirv.core.grammar.json
+SPV_GLSL_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/1.0/extinst.glsl.std.450.grammar.json
+# OpenCL grammar has not yet been published to SPIRV-Headers
+SPV_OPENCL_GRAMMAR=$(SPVTOOLS_LOCAL_PATH)/source/extinst-1.0.opencl.std.grammar.json
 
 define gen_spvtools_grammar_tables
-$(call generate-file-dir,$(1)/core.insts.inc)
-$(1)/core.insts.inc $(1)/operand.kinds.inc $(1)/glsl.std.450.insts.inc $(1)/opencl.std.insts.inc: \
+$(call generate-file-dir,$(1)/core.insts-1.0.inc)
+$(1)/core.insts-1.0.inc $(1)/operand.kinds-1.0.inc $(1)/glsl.std.450.insts-1.0.inc $(1)/opencl.std.insts-1.0.inc: \
         $(SPVTOOLS_LOCAL_PATH)/utils/generate_grammar_tables.py \
-        $(SPVTOOLS_LOCAL_PATH)/source/spirv.core.grammar.json \
-        $(SPVTOOLS_LOCAL_PATH)/source/extinst.glsl.std.450.grammar.json \
-        $(SPVTOOLS_LOCAL_PATH)/source/extinst.opencl.std.grammar.json
+        $(SPV_CORE10_GRAMMAR) \
+        $(SPV_GLSL_GRAMMAR) \
+        $(SPV_OPENCL_GRAMMAR)
 		@$(HOST_PYTHON) $(SPVTOOLS_LOCAL_PATH)/utils/generate_grammar_tables.py \
-		                --spirv-core-grammar=$(SPVTOOLS_LOCAL_PATH)/source/spirv.core.grammar.json \
-		                --extinst-glsl-grammar=$(SPVTOOLS_LOCAL_PATH)/source/extinst.glsl.std.450.grammar.json \
-		                --extinst-opencl-grammar=$(SPVTOOLS_LOCAL_PATH)/source/extinst.opencl.std.grammar.json \
-		                --core-insts-output=$(1)/core.insts.inc \
-		                --glsl-insts-output=$(1)/glsl.std.450.insts.inc \
-		                --opencl-insts-output=$(1)/opencl.std.insts.inc \
-		                --operand-kinds-output=$(1)/operand.kinds.inc
-		@echo "[$(TARGET_ARCH_ABI)] Grammar        : instructions & operands <= grammar JSON files"
-$(SPVTOOLS_LOCAL_PATH)/source/opcode.cpp: $(1)/core.insts.inc
-$(SPVTOOLS_LOCAL_PATH)/source/operand.cpp: $(1)/operand.kinds.inc
-$(SPVTOOLS_LOCAL_PATH)/source/ext_inst.cpp: $(1)/glsl.std.450.insts.inc $(1)/opencl.std.insts.inc
+		                --spirv-core-grammar=$(SPV_CORE10_GRAMMAR) \
+		                --extinst-glsl-grammar=$(SPV_GLSL_GRAMMAR) \
+		                --extinst-opencl-grammar=$(SPV_OPENCL_GRAMMAR) \
+		                --core-insts-output=$(1)/core.insts-1.0.inc \
+		                --glsl-insts-output=$(1)/glsl.std.450.insts-1.0.inc \
+		                --opencl-insts-output=$(1)/opencl.std.insts-1.0.inc \
+		                --operand-kinds-output=$(1)/operand.kinds-1.0.inc
+		@echo "[$(TARGET_ARCH_ABI)] Grammar v1.0   : instructions & operands <= grammar JSON files"
+$(1)/core.insts-1.1.inc $(1)/operand.kinds-1.1.inc: \
+        $(SPVTOOLS_LOCAL_PATH)/utils/generate_grammar_tables.py \
+        $(SPV_CORE11_GRAMMAR)
+		@$(HOST_PYTHON) $(SPVTOOLS_LOCAL_PATH)/utils/generate_grammar_tables.py \
+		                --spirv-core-grammar=$(SPV_CORE11_GRAMMAR) \
+		                --core-insts-output=$(1)/core.insts-1.1.inc \
+		                --operand-kinds-output=$(1)/operand.kinds-1.1.inc
+		@echo "[$(TARGET_ARCH_ABI)] Grammar v1.1   : instructions & operands <= grammar JSON files"
+$(SPVTOOLS_LOCAL_PATH)/source/opcode.cpp: $(1)/core.insts-1.0.inc $(1)/core.insts-1.1.inc
+$(SPVTOOLS_LOCAL_PATH)/source/operand.cpp: $(1)/operand.kinds-1.0.inc $(1)/operand.kinds-1.1.inc
+$(SPVTOOLS_LOCAL_PATH)/source/ext_inst.cpp: $(1)/glsl.std.450.insts-1.0.inc $(1)/opencl.std.insts-1.0.inc
 endef
 $(eval $(call gen_spvtools_grammar_tables,$(SPVTOOLS_OUT_PATH)))
 
+define gen_spvtools_build_version_inc
+$(call generate-file-dir,$(1)/dummy_filename)
+$(1)/build-version.inc: \
+        $(SPVTOOLS_LOCAL_PATH)/utils/update_build_version.py \
+        $(SPVTOOLS_LOCAL_PATH)/CHANGES
+		@$(HOST_PYTHON) $(SPVTOOLS_LOCAL_PATH)/utils/update_build_version.py \
+		                $(SPVTOOLS_LOCAL_PATH) $(1)/build-version.inc
+		@echo "[$(TARGET_ARCH_ABI)] Generate       : build-version.inc <= CHANGES"
+$(SPVTOOLS_LOCAL_PATH)/source/software_version.cpp: $(1)/build-version.inc
+endef
+$(eval $(call gen_spvtools_build_version_inc,$(SPVTOOLS_OUT_PATH)))
+
 include $(CLEAR_VARS)
 LOCAL_MODULE := SPIRV-Tools
 LOCAL_C_INCLUDES := \
 		$(SPVTOOLS_LOCAL_PATH)/include \
 		$(SPVTOOLS_LOCAL_PATH)/source \
+		$(SPVTOOLS_LOCAL_PATH)/external/spirv-headers/include \
 		$(SPVTOOLS_OUT_PATH)
 LOCAL_EXPORT_C_INCLUDES := \
 		$(SPVTOOLS_LOCAL_PATH)/include
@@ -142,16 +176,20 @@
 		source/opcode.cpp \
 		source/operand.cpp \
 		source/print.cpp \
+		source/software_version.cpp \
 		source/spirv_endian.cpp \
 		source/spirv_target_env.cpp \
 		source/table.cpp \
 		source/text.cpp \
 		source/text_handler.cpp \
-		source/validate.cpp \
+		source/val/BasicBlock.cpp \
+		source/val/Construct.cpp \
+		source/val/Function.cpp \
+		source/val/ValidationState.cpp \
 		source/validate_cfg.cpp \
+		source/validate.cpp \
 		source/validate_id.cpp \
 		source/validate_instruction.cpp \
 		source/validate_layout.cpp \
-		source/validate_ssa.cpp \
-		source/validate_types.cpp
+		source/validate_ssa.cpp
 include $(BUILD_STATIC_LIBRARY)
diff --git a/utils/add_copyright.py b/utils/add_copyright.py
index b6caee4..63d725a 100755
--- a/utils/add_copyright.py
+++ b/utils/add_copyright.py
@@ -128,7 +128,7 @@
 
 def main():
     glob_comment_pairs = [('*.h', '//'), ('*.hpp', '//'), ('*.cc', '//'),
-                          ('*.py', '#')]
+                          ('*.py', '#'), ('*.cpp', '//')]
     if '--check' in sys.argv:
         count = 0
         for pair in glob_comment_pairs:
diff --git a/utils/update_build_version.py b/utils/update_build_version.py
index d79c616..e223646 100755
--- a/utils/update_build_version.py
+++ b/utils/update_build_version.py
@@ -27,6 +27,7 @@
 
 import datetime
 import os.path
+import re
 import subprocess
 import sys
 
@@ -50,6 +51,23 @@
     return stdout
 
 
+def deduce_software_version(dir):
+    """Returns a software version number parsed from the CHANGES file
+    in the given dir.
+
+    The CHANGES file describes most recent versions first.
+    """
+
+    pattern = re.compile('(v\d+\.\d+(-dev)?) \d\d\d\d-\d\d-\d\d$')
+    changes_file = os.path.join(dir, 'CHANGES')
+    with open(changes_file) as f:
+        for line in f.readlines():
+            match = pattern.match(line)
+            if match:
+                return match.group(1)
+    raise Exception('No version number found in {}'.format(changes_file))
+
+
 def describe(dir):
     """Returns a string describing the current Git HEAD version as descriptively
     as possible.
@@ -71,21 +89,32 @@
             return 'unknown hash, ' + datetime.date.today().isoformat()
 
 
+def get_version_string(project, dir):
+    """Returns a detailed version string for a given project with its directory,
+    which consists of software version string and git description string."""
+    detailed_version_string_lst = [project]
+    if project != 'glslang':
+        detailed_version_string_lst.append(deduce_software_version(dir))
+    detailed_version_string_lst.append(describe(dir).replace('"', '\\"'))
+    return ' '.join(detailed_version_string_lst)
+
+
 def main():
     if len(sys.argv) != 4:
         print(
-            'usage: {0} <shaderc_dir> <spirv-tools_dir> <glslang_dir>'.format(sys.argv[0]))
+            'usage: {0} <shaderc_dir> <spirv-tools_dir> <glslang_dir>'.format(
+                sys.argv[0]))
         sys.exit(1)
 
     projects = ['shaderc', 'spirv-tools', 'glslang']
-    tags = [describe(p).replace('"', '\\"')
-            for p in sys.argv[1:]]
     new_content = ''.join([
-        '"{} {}\\n"\n'.format(p, t)
-        for (p, t) in zip(projects, tags)])
+        '"{}\\n"\n'.format(get_version_string(p, d))
+        for (p, d) in zip(projects, sys.argv[1:])
+    ])
     if os.path.isfile(OUTFILE) and new_content == open(OUTFILE, 'r').read():
         sys.exit(0)
     open(OUTFILE, 'w').write(new_content)
 
+
 if __name__ == '__main__':
     main()