SPV compression: Remove file/path manipulation stuff, setting up for that to be a separate tool.  Added copyright messages as well.


git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@31201 e7fa87d3-cd2b-0410-9028-fcbf551c1848
diff --git a/SPIRV/SPVRemapper.cpp b/SPIRV/SPVRemapper.cpp
index 8147a28..97eb4a5 100644
--- a/SPIRV/SPVRemapper.cpp
+++ b/SPIRV/SPVRemapper.cpp
@@ -1,29 +1,50 @@
+//

+//Copyright (C) 2015 LunarG, Inc.

+//

+//All rights reserved.

+//

+//Redistribution and use in source and binary forms, with or without

+//modification, are permitted provided that the following conditions

+//are met:

+//

+//    Redistributions of source code must retain the above copyright

+//    notice, this list of conditions and the following disclaimer.

+//

+//    Redistributions in binary form must reproduce the above

+//    copyright notice, this list of conditions and the following

+//    disclaimer in the documentation and/or other materials provided

+//    with the distribution.

+//

+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

+//    contributors may be used to endorse or promote products derived

+//    from this software without specific prior written permission.

+//

+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

+//POSSIBILITY OF SUCH DAMAGE.

+//

+
 #include "SPVRemapper.h"
 #include "doc.h"
-
-/* -*-mode:c++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
-
-// Poor man's basename: given a complete path, return file portion.
-// E.g:
-//      Linux:  /foo/bar/test  -> test
-//      Win:   c:\foo\bar\test -> test
-// It's not very efficient, but that doesn't matter for our minimal-duty use.
-// Using boost::filesystem would be better in many ways, but want to avoid that dependency.
-const std::string spv::spirvbin_base_t::basename(const std::string& filename)
-{
-   const size_t sepLoc = filename.find_last_of(path_sep_char());
-
-   return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1);
-}
-
-#if !defined (use_cpp11)
-// ... not supported before C++11
-#else // defined (use_cpp11)
-
-#include <fstream>
-#include <algorithm>
-#include <cassert>
-
+

+/* -*-mode:c++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 3 -*- */

+

+#if !defined (use_cpp11)

+// ... not supported before C++11

+#else // defined (use_cpp11)

+

+#include <algorithm>

+#include <cassert>

+

 namespace spv {
 
 // By default, just abort on error.  Can be overridden via RegisterErrorHandler
@@ -201,20 +222,20 @@
    
    if (id >= idMapL.size())
       idMapL.resize(id+1, unused);
-
-   if (newId != unmapped && newId != unused) {
-      if (isOldIdUnused(id))
-         ferror(std::string("ID unused in module: ") + std::to_string(id));
-
-      if (!isOldIdUnmapped(id))
-         ferror(std::string("ID already mapped: ") + std::to_string(id) + " -> "
-                + std::to_string(localId(id)));
-
-      if (isNewIdMapped(newId))
-         ferror(std::string("ID already used in module: ") + std::to_string(newId));
-
-      msg(4, 4, std::string("map: ") + std::to_string(id) + " -> " + std::to_string(newId));
-      setMapped(newId);
+

+   if (newId != unmapped && newId != unused) {

+      if (isOldIdUnused(id))

+          error(std::string("ID unused in module: ") + std::to_string(id));

+

+      if (!isOldIdUnmapped(id))

+         error(std::string("ID already mapped: ") + std::to_string(id) + " -> "

+                + std::to_string(localId(id)));

+

+      if (isNewIdMapped(newId))

+         error(std::string("ID already used in module: ") + std::to_string(newId));

+

+      msg(4, 4, std::string("map: ") + std::to_string(id) + " -> " + std::to_string(newId));

+      setMapped(newId);

       largestNewId = std::max(largestNewId, newId);
    }
 
@@ -235,45 +256,15 @@
       literal += *bytes++;
    
    return literal;
-}
-
-
-// Write word stream to disk, in outputDir, with same filename used to read it.
-void spirvbin_t::write(const std::string& outputDir) const
-{
-   if (filename.empty())
-      error("missing filename");
-
-   if (outputDir.empty())
-      error("missing output directory");
-
-   const std::string outfile = outputDir + path_sep_char() + basename(filename);
-
-   std::ofstream fp;
-
-   msg(2, 2, std::string("writing: ") + outfile);
-
-   fp.open(outfile, std::fstream::out | std::fstream::binary);
-
-   if (fp.fail())
-      error(std::string("error opening file for write: ") + outfile);
-
-   for (auto word : spv) {
-      fp.write((char *)&word, sizeof(word));
-      if (fp.fail())
-         error(std::string("error writing file: ") + outfile);
-   }
-
-   // file is closed by destructor
-}
-
-
-void spirvbin_t::applyMap()
-{
-   msg(3, 2, std::string("Applying map: ") + basename(filename));
-   
-   // Map local IDs through the ID map
-   process(inst_fn_nop, // ignore instructions
+}

+

+

+void spirvbin_t::applyMap()

+{

+   msg(3, 2, std::string("Applying map: "));

+   

+   // Map local IDs through the ID map

+   process(inst_fn_nop, // ignore instructions

            [this](spv::Id& id) {
               id = localId(id);
               assert(id != unused && id != unmapped);
@@ -282,13 +273,13 @@
 }
 
 
-// Find free IDs for anything we haven't mapped
-void spirvbin_t::mapRemainder()
-{
-   msg(3, 2, std::string("Remapping remainder: ") + basename(filename));
-
-   spv::Id     unusedId  = 1;  // can't use 0: that's NoResult
-   spirword_t  maxBound  = 0;
+// Find free IDs for anything we haven't mapped

+void spirvbin_t::mapRemainder()

+{

+   msg(3, 2, std::string("Remapping remainder: "));

+

+   spv::Id     unusedId  = 1;  // can't use 0: that's NoResult

+   spirword_t  maxBound  = 0;

 
    for (spv::Id id = 0; id < idMapL.size(); ++id) {
       if (isOldIdUnused(id))
@@ -296,13 +287,13 @@
 
       // Find a new mapping for any used but unmapped IDs
       if (isOldIdUnmapped(id))
-         localId(id, unusedId = nextUnusedId(unusedId));
-
-      if (isOldIdUnmapped(id))
-         ferror(std::string("old ID not mapped: ") + std::to_string(id));
-
-      // Track max bound
-      maxBound = std::max(maxBound, localId(id) + 1);
+         localId(id, unusedId = nextUnusedId(unusedId));

+

+      if (isOldIdUnmapped(id))

+         error(std::string("old ID not mapped: ") + std::to_string(id));

+

+      // Track max bound

+      maxBound = std::max(maxBound, localId(id) + 1);

    }
 
    bound(maxBound); // reset header ID bound to as big as it now needs to be
@@ -323,13 +314,13 @@
       },
       op_fn_nop);
 }
-
-void spirvbin_t::buildLocalMaps()
-{
-   msg(2, 2, std::string("build local maps: ") + filename);
-
-   mapped.clear();
-   idMapL.clear();
+

+void spirvbin_t::buildLocalMaps()

+{

+   msg(2, 2, std::string("build local maps: "));

+

+   mapped.clear();

+   idMapL.clear();

    nameMap.clear();
    fnPos.clear();
    fnPosDCE.clear();
@@ -359,19 +350,19 @@
          } else if (opCode == spv::Op::OpFunctionCall) {
             ++fnCalls[asId(start + 3)];
          } else if (opCode == spv::Op::OpEntryPoint) {
-            entryPoint = asId(start + 2);
-         } else if (opCode == spv::Op::OpFunction) {
-            if (fnStart != 0)
-               ferror("nested function found");
-            fnStart = start;
-            fnRes   = asId(start + 2);
-         } else if (opCode == spv::Op::OpFunctionEnd) {
-            assert(fnRes != spv::NoResult);
-            if (fnStart == 0)
-               ferror("function end without function start");
-            fnPos[fnRes] = {fnStart, start + asWordCount(start)};
-            fnStart = 0;
-         } else if (isConstOp(opCode)) {
+            entryPoint = asId(start + 2);

+         } else if (opCode == spv::Op::OpFunction) {

+            if (fnStart != 0)

+               error("nested function found");

+            fnStart = start;

+            fnRes   = asId(start + 2);

+         } else if (opCode == spv::Op::OpFunctionEnd) {

+            assert(fnRes != spv::NoResult);

+            if (fnStart == 0)

+               error("function end without function start");

+            fnPos[fnRes] = {fnStart, start + asWordCount(start)};

+            fnStart = 0;

+         } else if (isConstOp(opCode)) {

             assert(asId(start + 2) != spv::NoResult);
             typeConstPos.insert(start);
             typeConstPosR[asId(start + 2)] = start;
@@ -385,79 +376,45 @@
       },
 
       [this](spv::Id& id) { localId(id, unmapped); }
-      );
-}
-
-// Read word stream from disk
-void spirvbin_t::read(const std::string& inFilename)
-{
-   std::ifstream fp;
-   filename = inFilename;
-
-   msg(2, 2, std::string("reading: ") + filename);
-
-   spv.clear();
-   fp.open(filename, std::fstream::in | std::fstream::binary);
-
-   if (fp.fail())
-      ferror("error opening file for read: ");
-
-   // Reserve space (for efficiency, not for correctness)
-   fp.seekg(0, fp.end);
-   spv.reserve(size_t(fp.tellg()) / sizeof(spirword_t));
-   fp.seekg(0, fp.beg);
-
-   while (!fp.eof()) {
-      spirword_t inWord;
-      fp.read((char *)&inWord, sizeof(inWord));
-
-      if (!fp.eof()) {
-         spv.push_back(inWord);
-         if (fp.fail())
-            ferror("error reading file: ");
-      }
-   }
-}
-
-
-// Validate the SPIR header
-void spirvbin_t::validate() const
-{
-   msg(2, 2, std::string("validating: ") + filename);
-
-   if (spv.size() < header_size)
-      ferror("file too short: ");
-
-   if (magic() != spv::MagicNumber)
-      ferror("bad magic number");
-
-   // 1 = version:            TODO: print for verbose output
-   // 2 = generator magic:    TODO: print for verbose output
-   // 3 = result <id> bound:  TODO: print for verbose output
-
-   if (schemaNum() != 0)
-      ferror("bad schema, must be 0");
-}
-
-
+      );

+}

+

+// Validate the SPIR header

+void spirvbin_t::validate() const

+{

+   msg(2, 2, std::string("validating: "));

+

+   if (spv.size() < header_size)

+      error("file too short: ");

+

+   if (magic() != spv::MagicNumber)

+      error("bad magic number");

+

+   // field 1 = version

+   // field 2 = generator magic

+   // field 3 = result <id> bound

+

+   if (schemaNum() != 0)

+      error("bad schema, must be 0");

+}

+

+

 int spirvbin_t::processInstruction(int word, instfn_t instFn, idfn_t idFn)
 {
    const auto     instructionStart = word;
    const unsigned wordCount = asWordCount(instructionStart);
    const spv::Op  opCode    = asOpCode(instructionStart);
-   const int      nextInst  = word++ + wordCount;
-
-   if (nextInst > int(spv.size()))
-      ferror("spir instruction terminated too early");
-
-   // Base for computing number of operands; will be updated as more is learned
-   unsigned numOperands = wordCount - 1;
-
-   // msg(5, 4, std::string("opcode: ") + spv::InstructionDesc[opCode].opName);
-
-   if (instFn(opCode, instructionStart))
-      return nextInst;
-
+   const int      nextInst  = word++ + wordCount;

+

+   if (nextInst > int(spv.size()))

+      error("spir instruction terminated too early");

+

+   // Base for computing number of operands; will be updated as more is learned

+   unsigned numOperands = wordCount - 1;

+

+   if (instFn(opCode, instructionStart))

+      return nextInst;

+

    // Read type and result ID from instruction desc table
    if (spv::InstructionDesc[opCode].hasType()) {
       idFn(asId(word++));
@@ -903,13 +860,13 @@
    buildLocalMaps(); // rebuild ID mapping data
 }
 
-// remove bodies of uncalled functions
-void spirvbin_t::dceFuncs()
-{
-   msg(3, 2, std::string("Removing Dead Functions: ") + filename);
-
-   // TODO: There are more efficient ways to do this.
-   bool changed = true;
+// remove bodies of uncalled functions

+void spirvbin_t::dceFuncs()

+{

+   msg(3, 2, std::string("Removing Dead Functions: "));

+

+   // TODO: There are more efficient ways to do this.

+   bool changed = true;

 
    while (changed) {
       changed = false;
@@ -920,13 +877,12 @@
             continue;
          }
          
-         const auto call_it = fnCalls.find(fn->first);
-         
-         if (call_it == fnCalls.end() || call_it->second == 0) {
-            // msg(3, 4, std::string("removing dead function: ") + std::to_string(fn->first));
-            changed = true;
-            stripRange.push_back(fn->second);
-            fnPosDCE.insert(*fn);
+         const auto call_it = fnCalls.find(fn->first);

+         

+         if (call_it == fnCalls.end() || call_it->second == 0) {

+            changed = true;

+            stripRange.push_back(fn->second);

+            fnPosDCE.insert(*fn);

 
             // decrease counts of called functions
             process(
@@ -951,13 +907,13 @@
    }
 }
 
-// remove unused function variables + decorations
-void spirvbin_t::dceVars()
-{
-   msg(3, 2, std::string("DCE Vars: ") + basename(filename));
-
-   std::unordered_map<spv::Id, int> varUseCount;
-
+// remove unused function variables + decorations

+void spirvbin_t::dceVars()

+{

+   msg(3, 2, std::string("DCE Vars: "));

+

+   std::unordered_map<spv::Id, int> varUseCount;

+

    // Count function variable use
    process(
       [&](spv::Op opCode, int start) {
@@ -1088,13 +1044,13 @@
 
 // Return start position in SPV of given type.  error if not found.
 int spirvbin_t::typePos(spv::Id id) const
-{
-   const auto tid_it = typeConstPosR.find(id);
-   if (tid_it == typeConstPosR.end())
-      ferror("type ID not found");
-
-   return tid_it->second;
-}
+{

+   const auto tid_it = typeConstPosR.find(id);

+   if (tid_it == typeConstPosR.end())

+      error("type ID not found");

+

+   return tid_it->second;

+}

 
 // Hash types to canonical values.  This can return ID collisions (it's a bit
 // inevitable): it's up to the caller to handle that gracefully.
@@ -1168,22 +1124,22 @@
             for (unsigned w=3; w < wordCount; ++w)
                hash += w * spv[typeStart+w];
             return hash;
-         }
-
-      default:
-         ferror("unknown type opcode");
-         return 0;
-   }
-}
+         }

+

+      default:

+         error("unknown type opcode");

+         return 0;

+   }

+}

 
 void spirvbin_t::mapTypeConst()
-{
-   globaltypes_t globalTypeMap;
-
-   msg(3, 2, std::string("Remapping Consts & Types: ") + basename(filename));
-
-   static const std::uint32_t softTypeIdLimit = 3011; // small prime.  TODO: get from options
-   static const std::uint32_t firstMappedID   = 8;    // offset into ID space
+{

+   globaltypes_t globalTypeMap;

+

+   msg(3, 2, std::string("Remapping Consts & Types: "));

+

+   static const std::uint32_t softTypeIdLimit = 3011; // small prime.  TODO: get from options

+   static const std::uint32_t firstMappedID   = 8;    // offset into ID space

    
    for (auto& typeStart : typeConstPos) {
       const spv::Id       resId     = asTypeConstId(typeStart);
@@ -1257,19 +1213,10 @@
 {
    spv.swap(in_spv);
    remap(opts);
-   spv.swap(in_spv);
-}
-
-// remap from a disk file
-void spirvbin_t::remap(const std::string& file, const std::string& outputDir,
-                       std::uint32_t opts)
-{
-   read(file);
-   remap(opts);
-   write(outputDir);
-}
-
-} // namespace SPV
-    
-#endif // defined (use_cpp11)
+   spv.swap(in_spv);

+}

+

+} // namespace SPV

+    

+#endif // defined (use_cpp11)

 
diff --git a/SPIRV/SPVRemapper.h b/SPIRV/SPVRemapper.h
index 4d63410..73b09ec 100644
--- a/SPIRV/SPVRemapper.h
+++ b/SPIRV/SPVRemapper.h
@@ -1,281 +1,286 @@
-
-#ifndef SPIRVREMAPPER_H
-#define SPIRVREMAPPER_H
-
-#include <string>
-#include <vector>
-
-namespace spv {
-
-// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.
-// We handle that here by making our own symbol.
-#if __cplusplus >= 201103L || _MSC_VER >= 1800
-#   define use_cpp11 1
-#endif
-
-class spirvbin_base_t
-{
-public:
-   enum Options {
-      NONE          = 0,
-      STRIP         = (1<<0),
-      MAP_TYPES     = (1<<1),
-      MAP_NAMES     = (1<<2),
-      MAP_FUNCS     = (1<<3),
-      DCE_FUNCS     = (1<<4),
-      DCE_VARS      = (1<<5),
-      DCE_TYPES     = (1<<6),
-      OPT_LOADSTORE = (1<<7),
-      OPT_FWD_LS    = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV
-      MAP_ALL       = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),
-      DCE_ALL       = (DCE_FUNCS | DCE_VARS | DCE_TYPES),
-      OPT_ALL       = (OPT_LOADSTORE),
-
-      ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),
-      DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
-   };
-   
-// OS dependent path separator (avoiding boost::filesystem dependency)
-#if defined(_WIN32)
-   static const char path_sep_char() { return '\\'; }
-#else
-   static const char path_sep_char() { return '/';  }
-#endif
-
-   // Poor man's basename, to avoid external dependencies
-   static const std::string basename(const std::string& filename);
-};
-
-} // namespace SPV
-
-#if !defined (use_cpp11)
-#include <stdio.h>
-
-namespace spv {
-
-class spirvbin_t : public spirvbin_base_t
-{
-public:
-    spirvbin_t(int verbose = 0) { }
-
-    void remap(std::vector<unsigned int>& spv, unsigned int opts = 0)
-    {
-        printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
-    }
-
-   void remap(const std::string& filename, const std::string& outputDir, unsigned int opts = 0)
-   {
-       printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
-   }
-};
-
-} // namespace SPV
-
-#else // defined (use_cpp11)
-
-#include <functional>
-#include <cstdint>
-#include <unordered_map>
-#include <unordered_set>
-#include <map>
-#include <set>
-#include <cassert>
-
-#include "../../glslang/SPIRV/spirv.h"
-#include "../../glslang/SPIRV/spvIR.h"
-
-namespace spv {
-
-// class to hold SPIRV binary data for remapping, DCE, and debug stripping
-class spirvbin_t : public spirvbin_base_t
-{
-public:
-   spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }
-   
-   // remap on an existing binary in memory
-   void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = Options::DO_EVERYTHING);
-
-   // load binary from disk file, and remap that.
-   void remap(const std::string& filename, const std::string& outputDir,
-              std::uint32_t opts = Options::DO_EVERYTHING);
-
-   // Type for error/log handler functions
-   typedef std::function<void(const std::string&)> errorfn_t;
-   typedef std::function<void(const std::string&)> logfn_t;
-
-   // Register error/log handling functions (can be lambda fn / functor / etc)
-   static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
-   static void registerLogHandler(logfn_t handler)     { logHandler   = handler; }
-
-protected:
-   // This can be overridden to provide other message behavior if needed
-   virtual void msg(int minVerbosity, int indent, const std::string& txt) const;
-
-private:
-   // write SPV to given directory using filename passed to remap(filename...)
-   void write(const std::string& outputDir) const;
-
-   // Local to global, or global to local ID map
-   typedef std::unordered_map<spv::Id, spv::Id> idmap_t;
-   typedef std::unordered_set<spv::Id>          idset_t;
-
-   void read(const std::string& filename);          // read SPV from disk file
-   void remap(std::uint32_t opts = Options::DO_EVERYTHING);
-
-   // Map of names to IDs
-   typedef std::unordered_map<std::string, spv::Id> namemap_t;
-
-   typedef std::uint32_t spirword_t;
-
-   typedef std::pair<int, int> range_t;
-   typedef std::function<void(spv::Id&)>           idfn_t;
-   typedef std::function<bool(spv::Op, int start)> instfn_t;
-
-   // Special Values for ID map:
-   static const spv::Id unmapped;     // unchanged from default value
-   static const spv::Id unused;       // unused ID
-   static const int     header_size;  // SPIR header = 5 words
-
-   class id_iterator_t;
-
-   // For mapping type entries between different shaders
-   typedef std::vector<spirword_t>        typeentry_t;
-   typedef std::map<spv::Id, typeentry_t> globaltypes_t;
-
-   // A set that preserves position order, and a reverse map
-   typedef std::set<int>                    posmap_t;
-   typedef std::unordered_map<spv::Id, int> posmap_rev_t;
-
-   // handle error
-   void error(const std::string& txt) const { errorHandler(txt); }
-   // handle error with our filename appended to the string
-   void ferror(const std::string& txt) const {
-      error(std::string("\nERROR processing file ") + filename + ":\n" + txt);
-   }
-
-   bool    isConstOp(spv::Op opCode)       const;
-   bool    isTypeOp(spv::Op opCode)        const;
-   bool    isStripOp(spv::Op opCode)       const;
-   bool    isFlowCtrlOpen(spv::Op opCode)  const;
-   bool    isFlowCtrlClose(spv::Op opCode) const;
-   range_t literalRange(spv::Op opCode)    const;
-   range_t typeRange(spv::Op opCode)       const;
-   range_t constRange(spv::Op opCode)      const;
-   
-   spv::Id&        asId(int word)                { return spv[word]; }
-   const spv::Id&  asId(int word)          const { return spv[word]; }
-   spv::Op         asOpCode(int word)      const { return opOpCode(spv[word]); }
-   std::uint32_t   asOpCodeHash(int word);
-   spv::Decoration asDecoration(int word)  const { return spv::Decoration(spv[word]); }
-   unsigned        asWordCount(int word)   const { return opWordCount(spv[word]); }
-   spv::Id         asTypeConstId(int word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
-   int             typePos(spv::Id id)     const;
-
-   static unsigned    opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
-   static spv::Op     opOpCode(spirword_t data)    { return spv::Op(data & spv::OpCodeMask); }
-
-   // Header access & set methods
-   spirword_t  magic()    const       { return spv[0]; } // return magic number
-   spirword_t  bound()    const       { return spv[3]; } // return Id bound from header
-   spirword_t  bound(spirword_t b)    { return spv[3] = b; };
-   spirword_t  genmagic() const       { return spv[2]; } // generator magic
-   spirword_t  genmagic(spirword_t m) { return spv[2] = m; }
-   spirword_t  schemaNum() const      { return spv[4]; } // schema number from header
-
-   // Mapping fns: get
-   spv::Id     localId(spv::Id id) const { return idMapL[id]; }
-
-   // Mapping fns: set
-   inline spv::Id   localId(spv::Id id, spv::Id newId);
-   void             countIds(spv::Id id);
-
-   // Return next unused new local ID.
-   // NOTE: boost::dynamic_bitset would be more efficient due to find_next(),
-   // which std::vector<bool> doens't have.
-   inline spv::Id   nextUnusedId(spv::Id id);
-
-   void buildLocalMaps();
-   std::string literalString(int word) const; // Return literal as a std::string
-   int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }
-
-   bool isNewIdMapped(spv::Id newId)   const { return isMapped(newId);            }
-   bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }
-   bool isOldIdUnused(spv::Id oldId)   const { return localId(oldId) == unused;   }
-   bool isOldIdMapped(spv::Id oldId)   const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }
-   bool isFunction(spv::Id oldId)      const { return fnPos.find(oldId) != fnPos.end(); }
-
-   // bool    matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;
-   // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;
-   std::uint32_t hashType(int typeStart) const;
-
-   spirvbin_t& process(instfn_t, idfn_t, int begin = 0, int end = 0);
-   int         processInstruction(int word, instfn_t, idfn_t);
-
-   void        validate() const;
-   void        mapTypeConst();
-   void        mapFnBodies();
-   void        optLoadStore();
-   void        dceFuncs();
-   void        dceVars();
-   void        dceTypes();
-   void        mapNames();
-   void        foldIds();  // fold IDs to smallest space
-   void        forwardLoadStores(); // load store forwarding (EXPERIMENTAL)
-   void        offsetIds(); // create relative offset IDs
-
-   void        applyMap();            // remap per local name map
-   void        mapRemainder();        // map any IDs we haven't touched yet
-   void        stripDebug();          // strip debug info
-   void        strip();               // remove debug symbols
-   
-   std::vector<spirword_t> spv;      // SPIR words
-   std::string             filename; // the file this came from
-
-   namemap_t               nameMap;  // ID names from OpName
-
-   // Since we want to also do binary ops, we can't use std::vector<bool>.  we could use
-   // boost::dynamic_bitset, but we're trying to avoid a boost dependency.
-   typedef std::uint64_t bits_t;
-   std::vector<bits_t> mapped; // which new IDs have been mapped
-   static const int mBits = sizeof(bits_t) * 4;
-
-   bool isMapped(spv::Id id) const  { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }
-   void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }
-   void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }
-   size_t maxMappedId() const { return mapped.size() * mBits; }
-
-   // Add a strip range for a given instruction starting at 'start'
-   // Note: avoiding brace initializers to please older versions os MSVC.
-   void stripInst(int start) { stripRange.push_back(std::pair<unsigned, unsigned>(start, start + asWordCount(start))); }
-
-   // Function start and end.  use unordered_map because we'll have
-   // many fewer functions than IDs.
-   std::unordered_map<spv::Id, std::pair<int, int>> fnPos;
-   std::unordered_map<spv::Id, std::pair<int, int>> fnPosDCE; // deleted functions
-
-   // Which functions are called, anywhere in the module, with a call count
-   std::unordered_map<spv::Id, int> fnCalls;
-   
-   posmap_t     typeConstPos;   // word positions that define types & consts (ordered)
-   posmap_rev_t typeConstPosR;  // reverse map from IDs to positions
-   
-   std::vector<spv::Id>  idMapL;   // ID {M}ap from {L}ocal to {G}lobal IDs
-
-   spv::Id entryPoint;      // module entry point
-   spv::Id largestNewId;    // biggest new ID we have mapped anything to
-
-   // Sections of the binary to strip, given as [begin,end)
-   std::vector<std::pair<unsigned, unsigned>> stripRange;
-
-   // processing options:
-   std::uint32_t options;
-   int           verbose;     // verbosity level
-
-   static errorfn_t errorHandler;
-   static logfn_t   logHandler;
-};
-
-} // namespace SPV
-
-#endif // defined (use_cpp11)
-#endif // SPIRVREMAPPER_H
+//

+//Copyright (C) 2015 LunarG, Inc.

+//

+//All rights reserved.

+//

+//Redistribution and use in source and binary forms, with or without

+//modification, are permitted provided that the following conditions

+//are met:

+//

+//    Redistributions of source code must retain the above copyright

+//    notice, this list of conditions and the following disclaimer.

+//

+//    Redistributions in binary form must reproduce the above

+//    copyright notice, this list of conditions and the following

+//    disclaimer in the documentation and/or other materials provided

+//    with the distribution.

+//

+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

+//    contributors may be used to endorse or promote products derived

+//    from this software without specific prior written permission.

+//

+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

+//POSSIBILITY OF SUCH DAMAGE.

+//

+

+#ifndef SPIRVREMAPPER_H

+#define SPIRVREMAPPER_H

+

+#include <string>

+#include <vector>

+

+namespace spv {

+

+// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.

+// We handle that here by making our own symbol.

+#if __cplusplus >= 201103L || _MSC_VER >= 1800

+#   define use_cpp11 1

+#endif

+

+class spirvbin_base_t

+{

+public:

+   enum Options {

+      NONE          = 0,

+      STRIP         = (1<<0),

+      MAP_TYPES     = (1<<1),

+      MAP_NAMES     = (1<<2),

+      MAP_FUNCS     = (1<<3),

+      DCE_FUNCS     = (1<<4),

+      DCE_VARS      = (1<<5),

+      DCE_TYPES     = (1<<6),

+      OPT_LOADSTORE = (1<<7),

+      OPT_FWD_LS    = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV

+      MAP_ALL       = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),

+      DCE_ALL       = (DCE_FUNCS | DCE_VARS | DCE_TYPES),

+      OPT_ALL       = (OPT_LOADSTORE),

+

+      ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),

+      DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)

+   };

+};

+

+} // namespace SPV

+

+#if !defined (use_cpp11)

+#include <stdio.h>

+

+namespace spv {

+class spirvbin_t : public spirvbin_base_t

+{

+public:

+    spirvbin_t(int verbose = 0) { }

+

+    void remap(std::vector<unsigned int>& spv, unsigned int opts = 0)

+    {

+        printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");

+    }

+};

+

+} // namespace SPV

+

+#else // defined (use_cpp11)

+

+#include <functional>

+#include <cstdint>

+#include <unordered_map>

+#include <unordered_set>

+#include <map>

+#include <set>

+#include <cassert>

+

+#include "../../glslang/SPIRV/spirv.h"

+#include "../../glslang/SPIRV/spvIR.h"

+

+namespace spv {

+

+// class to hold SPIRV binary data for remapping, DCE, and debug stripping

+class spirvbin_t : public spirvbin_base_t

+{

+public:

+   spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }

+   

+   // remap on an existing binary in memory

+   void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = Options::DO_EVERYTHING);

+

+   // Type for error/log handler functions

+   typedef std::function<void(const std::string&)> errorfn_t;

+   typedef std::function<void(const std::string&)> logfn_t;

+

+   // Register error/log handling functions (can be lambda fn / functor / etc)

+   static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }

+   static void registerLogHandler(logfn_t handler)     { logHandler   = handler; }

+

+protected:

+   // This can be overridden to provide other message behavior if needed

+   virtual void msg(int minVerbosity, int indent, const std::string& txt) const;

+

+private:

+   // Local to global, or global to local ID map

+   typedef std::unordered_map<spv::Id, spv::Id> idmap_t;

+   typedef std::unordered_set<spv::Id>          idset_t;

+

+   void remap(std::uint32_t opts = Options::DO_EVERYTHING);

+

+   // Map of names to IDs

+   typedef std::unordered_map<std::string, spv::Id> namemap_t;

+

+   typedef std::uint32_t spirword_t;

+

+   typedef std::pair<int, int> range_t;

+   typedef std::function<void(spv::Id&)>           idfn_t;

+   typedef std::function<bool(spv::Op, int start)> instfn_t;

+

+   // Special Values for ID map:

+   static const spv::Id unmapped;     // unchanged from default value

+   static const spv::Id unused;       // unused ID

+   static const int     header_size;  // SPIR header = 5 words

+

+   class id_iterator_t;

+

+   // For mapping type entries between different shaders

+   typedef std::vector<spirword_t>        typeentry_t;

+   typedef std::map<spv::Id, typeentry_t> globaltypes_t;

+

+   // A set that preserves position order, and a reverse map

+   typedef std::set<int>                    posmap_t;

+   typedef std::unordered_map<spv::Id, int> posmap_rev_t;

+

+   // handle error

+   void error(const std::string& txt) const { errorHandler(txt); }

+

+   bool    isConstOp(spv::Op opCode)       const;

+   bool    isTypeOp(spv::Op opCode)        const;

+   bool    isStripOp(spv::Op opCode)       const;

+   bool    isFlowCtrlOpen(spv::Op opCode)  const;

+   bool    isFlowCtrlClose(spv::Op opCode) const;

+   range_t literalRange(spv::Op opCode)    const;

+   range_t typeRange(spv::Op opCode)       const;

+   range_t constRange(spv::Op opCode)      const;

+   

+   spv::Id&        asId(int word)                { return spv[word]; }

+   const spv::Id&  asId(int word)          const { return spv[word]; }

+   spv::Op         asOpCode(int word)      const { return opOpCode(spv[word]); }

+   std::uint32_t   asOpCodeHash(int word);

+   spv::Decoration asDecoration(int word)  const { return spv::Decoration(spv[word]); }

+   unsigned        asWordCount(int word)   const { return opWordCount(spv[word]); }

+   spv::Id         asTypeConstId(int word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }

+   int             typePos(spv::Id id)     const;

+

+   static unsigned    opWordCount(spirword_t data) { return data >> spv::WordCountShift; }

+   static spv::Op     opOpCode(spirword_t data)    { return spv::Op(data & spv::OpCodeMask); }

+

+   // Header access & set methods

+   spirword_t  magic()    const       { return spv[0]; } // return magic number

+   spirword_t  bound()    const       { return spv[3]; } // return Id bound from header

+   spirword_t  bound(spirword_t b)    { return spv[3] = b; };

+   spirword_t  genmagic() const       { return spv[2]; } // generator magic

+   spirword_t  genmagic(spirword_t m) { return spv[2] = m; }

+   spirword_t  schemaNum() const      { return spv[4]; } // schema number from header

+

+   // Mapping fns: get

+   spv::Id     localId(spv::Id id) const { return idMapL[id]; }

+

+   // Mapping fns: set

+   inline spv::Id   localId(spv::Id id, spv::Id newId);

+   void             countIds(spv::Id id);

+

+   // Return next unused new local ID.

+   // NOTE: boost::dynamic_bitset would be more efficient due to find_next(),

+   // which std::vector<bool> doens't have.

+   inline spv::Id   nextUnusedId(spv::Id id);

+

+   void buildLocalMaps();

+   std::string literalString(int word) const; // Return literal as a std::string

+   int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }

+

+   bool isNewIdMapped(spv::Id newId)   const { return isMapped(newId);            }

+   bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }

+   bool isOldIdUnused(spv::Id oldId)   const { return localId(oldId) == unused;   }

+   bool isOldIdMapped(spv::Id oldId)   const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }

+   bool isFunction(spv::Id oldId)      const { return fnPos.find(oldId) != fnPos.end(); }

+

+   // bool    matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;

+   // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;

+   std::uint32_t hashType(int typeStart) const;

+

+   spirvbin_t& process(instfn_t, idfn_t, int begin = 0, int end = 0);

+   int         processInstruction(int word, instfn_t, idfn_t);

+

+   void        validate() const;

+   void        mapTypeConst();

+   void        mapFnBodies();

+   void        optLoadStore();

+   void        dceFuncs();

+   void        dceVars();

+   void        dceTypes();

+   void        mapNames();

+   void        foldIds();  // fold IDs to smallest space

+   void        forwardLoadStores(); // load store forwarding (EXPERIMENTAL)

+   void        offsetIds(); // create relative offset IDs

+

+   void        applyMap();            // remap per local name map

+   void        mapRemainder();        // map any IDs we haven't touched yet

+   void        stripDebug();          // strip debug info

+   void        strip();               // remove debug symbols

+   

+   std::vector<spirword_t> spv;      // SPIR words

+

+   namemap_t               nameMap;  // ID names from OpName

+

+   // Since we want to also do binary ops, we can't use std::vector<bool>.  we could use

+   // boost::dynamic_bitset, but we're trying to avoid a boost dependency.

+   typedef std::uint64_t bits_t;

+   std::vector<bits_t> mapped; // which new IDs have been mapped

+   static const int mBits = sizeof(bits_t) * 4;

+

+   bool isMapped(spv::Id id) const  { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }

+   void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }

+   void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }

+   size_t maxMappedId() const { return mapped.size() * mBits; }

+

+   // Add a strip range for a given instruction starting at 'start'

+   // Note: avoiding brace initializers to please older versions os MSVC.

+   void stripInst(int start) { stripRange.push_back(std::pair<unsigned, unsigned>(start, start + asWordCount(start))); }

+

+   // Function start and end.  use unordered_map because we'll have

+   // many fewer functions than IDs.

+   std::unordered_map<spv::Id, std::pair<int, int>> fnPos;

+   std::unordered_map<spv::Id, std::pair<int, int>> fnPosDCE; // deleted functions

+

+   // Which functions are called, anywhere in the module, with a call count

+   std::unordered_map<spv::Id, int> fnCalls;

+   

+   posmap_t     typeConstPos;   // word positions that define types & consts (ordered)

+   posmap_rev_t typeConstPosR;  // reverse map from IDs to positions

+   

+   std::vector<spv::Id>  idMapL;   // ID {M}ap from {L}ocal to {G}lobal IDs

+

+   spv::Id entryPoint;      // module entry point

+   spv::Id largestNewId;    // biggest new ID we have mapped anything to

+

+   // Sections of the binary to strip, given as [begin,end)

+   std::vector<std::pair<unsigned, unsigned>> stripRange;

+

+   // processing options:

+   std::uint32_t options;

+   int           verbose;     // verbosity level

+

+   static errorfn_t errorHandler;

+   static logfn_t   logHandler;

+};

+

+} // namespace SPV

+

+#endif // defined (use_cpp11)

+#endif // SPIRVREMAPPER_H

diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp
index 3cf9deb..4f38566 100644
--- a/StandAlone/StandAlone.cpp
+++ b/StandAlone/StandAlone.cpp
@@ -44,7 +44,6 @@
 #include "../SPIRV/GLSL450Lib.h"
 #include "../SPIRV/doc.h"
 #include "../SPIRV/disassemble.h"
-#include "../SPIRV/SPVRemapper.h"
 #include <string.h>
 #include <stdlib.h>
 #include <math.h>
@@ -72,8 +71,6 @@
     EOptionSpv                = 0x0800,
     EOptionHumanReadableSpv   = 0x1000,
     EOptionDefaultDesktop     = 0x2000,
-    EOptionCanonicalizeSpv    = 0x4000,
-    EOptionStripSpv           = 0x8000,
 };
 
 //
@@ -484,17 +481,11 @@
     for (; argc >= 1; argc--, argv++) {
         Work[argc] = 0;
         if (argv[0][0] == '-') {
-            const char optLetter = argv[0][1];
-
-            switch (optLetter) {
-            case 'S': // fall through to -V
-            case 'C': // fall through to -V
-            case 'H': // fall through to -V
+            switch (argv[0][1]) {
+            case 'H':
+                Options |= EOptionHumanReadableSpv;
+                // fall through to -V
             case 'V':
-                if (optLetter == 'H') Options |= EOptionHumanReadableSpv;
-                if (optLetter == 'S') Options |= EOptionStripSpv;
-                if (optLetter == 'C') Options |= EOptionCanonicalizeSpv;
-                
                 Options |= EOptionSpv;
                 Options |= EOptionLinkProgram;
                 break;
@@ -669,17 +660,7 @@
                     case EShLangCompute:         name = "comp";    break;
                     default:                     name = "unknown"; break;
                     }
-                    if (Options & (EOptionCanonicalizeSpv | EOptionStripSpv)) {
-                        const unsigned int remapOpts =
-                            ((Options & EOptionCanonicalizeSpv) ? (spv::spirvbin_t::ALL_BUT_STRIP) : 0) |
-                            ((Options & EOptionStripSpv)        ? (spv::spirvbin_t::STRIP) : 0);
-
-                        spv::Parameterize();
-                        spv::spirvbin_t().remap(spirv, remapOpts);
-                    }
-
                     glslang::OutputSpv(spirv, name);
-
                     if (Options & EOptionHumanReadableSpv) {
                         spv::Parameterize();
                         GLSL_STD_450::GetDebugNames(GlslStd450DebugNames);
@@ -886,8 +867,6 @@
            "To get other information, use one of the following options:\n"
            "(Each option must be specified separately, but can go anywhere in the command line.)\n"
            "  -V  create SPIR-V in file <stage>.spv\n"
-           "  -C  canonicalize generated SPIR-V: turns on -V\n"
-           "  -S  debug-strip SPIR-V: turns on -V\n"
            "  -H  print human readable form of SPIR-V; turns on -V\n"
            "  -c  configuration dump; use to create default configuration file (redirect to a .conf file)\n"
            "  -d  default to desktop (#version 110) when there is no version in the shader (default is ES version 100)\n"