SPV compression: Final check-in enabling this on MSVC 2012. All compression submissi...
authorJohn Kessenich <cepheus@frii.com>
Wed, 20 May 2015 16:04:17 +0000 (16:04 +0000)
committerJohn Kessenich <cepheus@frii.com>
Wed, 20 May 2015 16:04:17 +0000 (16:04 +0000)
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@31236 e7fa87d3-cd2b-0410-9028-fcbf551c1848

README-spirv-remap.txt
SPIRV/SPVRemapper.cpp
SPIRV/SPVRemapper.h
StandAlone/spirv-remap.cpp

index abd924e..691c312 100644 (file)
@@ -48,11 +48,11 @@ for Linux.  Command line arguments can be provided in any order.
 Perform ID remapping on all shaders in "*.spv", writing new files with
 the same basenames to /tmp/out_dir.
 
-  spirv-remap --map all --input *.spv --output /tmp/out_dir
+  spirv-remap -v --map all --input *.spv --output /tmp/out_dir
 
 2. Perform all possible size reductions
 
-  spirv-remap-linux-64 --do-everything --input *.spv --output /tmp/out_dir
+  spirv-remap-linux-64 -v --do-everything --input *.spv --output /tmp/out_dir
 
 Note that --do-everything is a synonym for:
 
index d390c77..e6f13ae 100644 (file)
@@ -58,7 +58,7 @@ namespace spv {
     }\r
 \r
     // hash opcode, with special handling for OpExtInst\r
-    std::uint32_t spirvbin_t::asOpCodeHash(int word)\r
+    std::uint32_t spirvbin_t::asOpCodeHash(unsigned word)\r
     {\r
         const spv::Op opCode = asOpCode(word);\r
 \r
@@ -196,8 +196,8 @@ namespace spv {
         }\r
     }\r
 \r
-    const auto inst_fn_nop = [](spv::Op, int) { return false; };\r
-    const auto op_fn_nop   = [](spv::Id&)     { };\r
+    const auto inst_fn_nop = [](spv::Op, unsigned) { return false; };\r
+    const auto op_fn_nop   = [](spv::Id&)          { };\r
 \r
     // g++ doesn't like these defined in the class proper in an anonymous namespace.\r
     // Dunno why.  Also MSVC doesn't like the constexpr keyword.  Also dunno why.\r
@@ -242,7 +242,7 @@ namespace spv {
 \r
     // Parse a literal string from the SPIR binary and return it as an std::string\r
     // Due to C++11 RValue references, this doesn't copy the result string.\r
-    std::string spirvbin_t::literalString(int word) const\r
+    std::string spirvbin_t::literalString(unsigned word) const\r
     {\r
         std::string literal;\r
 \r
@@ -304,7 +304,7 @@ namespace spv {
 \r
         // build local Id and name maps\r
         process(\r
-            [&](spv::Op opCode, int start) {\r
+            [&](spv::Op opCode, unsigned start) {\r
                 // remember opcodes we want to strip later\r
                 if (isStripOp(opCode))\r
                     stripInst(start);\r
@@ -335,7 +335,7 @@ namespace spv {
 \r
         // build local Id and name maps\r
         process(\r
-            [&](spv::Op opCode, int start) {\r
+            [&](spv::Op opCode, unsigned start) {\r
                 // remember opcodes we want to strip later\r
                 if ((options & Options::STRIP) && isStripOp(opCode))\r
                     stripInst(start);\r
@@ -358,7 +358,7 @@ namespace spv {
                     assert(fnRes != spv::NoResult);\r
                     if (fnStart == 0)\r
                         error("function end without function start");\r
-                    fnPos[fnRes] = {fnStart, start + asWordCount(start)};\r
+                    fnPos[fnRes] = range_t(fnStart, start + asWordCount(start));\r
                     fnStart = 0;\r
                 } else if (isConstOp(opCode)) {\r
                     assert(asId(start + 2) != spv::NoResult);\r
@@ -397,7 +397,7 @@ namespace spv {
     }\r
 \r
 \r
-    int spirvbin_t::processInstruction(int word, instfn_t instFn, idfn_t idFn)\r
+    int spirvbin_t::processInstruction(unsigned word, instfn_t instFn, idfn_t idFn)\r
     {\r
         const auto     instructionStart = word;\r
         const unsigned wordCount = asWordCount(instructionStart);\r
@@ -501,19 +501,19 @@ namespace spv {
     }\r
 \r
     // Make a pass over all the instructions and process them given appropriate functions\r
-    spirvbin_t& spirvbin_t::process(instfn_t instFn, idfn_t idFn, int begin, int end)\r
+    spirvbin_t& spirvbin_t::process(instfn_t instFn, idfn_t idFn, unsigned begin, unsigned end)\r
     {\r
         // For efficiency, reserve name map space.  It can grow if needed.\r
         nameMap.reserve(32);\r
 \r
         // If begin or end == 0, use defaults\r
-        begin = (begin == 0 ? header_size      : begin);\r
-        end   = (end   == 0 ? int(spv.size()) : end);\r
+        begin = (begin == 0 ? header_size          : begin);\r
+        end   = (end   == 0 ? unsigned(spv.size()) : end);\r
 \r
         // basic parsing and InstructionDesc table borrowed from SpvDisassemble.cpp...\r
-        int nextInst = int(spv.size());\r
+        unsigned nextInst = unsigned(spv.size());\r
 \r
-        for (int word = begin; word < end; word = nextInst)\r
+        for (unsigned word = begin; word < end; word = nextInst)\r
             nextInst = processInstruction(word, instFn, idFn);\r
 \r
         return *this;\r
@@ -544,13 +544,13 @@ namespace spv {
         // Initial approach: go through some high priority opcodes first and assign them\r
         // hash values.\r
 \r
-        spv::Id          fnId       = spv::NoResult;\r
-        std::vector<int> instPos;\r
-        instPos.reserve(int(spv.size()) / 16); // initial estimate; can grow if needed.\r
+        spv::Id               fnId       = spv::NoResult;\r
+        std::vector<unsigned> instPos;\r
+        instPos.reserve(unsigned(spv.size()) / 16); // initial estimate; can grow if needed.\r
 \r
         // Build local table of instruction start positions\r
         process(\r
-            [&](spv::Op, int start) { instPos.push_back(start); return true; },\r
+            [&](spv::Op, unsigned start) { instPos.push_back(start); return true; },\r
             op_fn_nop);\r
 \r
         // Window size for context-sensitive canonicalization values\r
@@ -558,11 +558,11 @@ namespace spv {
         // We essentially performa a little convolution around each instruction,\r
         // to capture the flavor of nearby code, to hopefully match to similar\r
         // code in other modules.\r
-        static const int windowSize = 2;\r
+        static const unsigned windowSize = 2;\r
 \r
-        for (int entry = 0; entry < int(instPos.size()); ++entry) {\r
-            const int     start  = instPos[entry];\r
-            const spv::Op opCode = asOpCode(start);\r
+        for (unsigned entry = 0; entry < unsigned(instPos.size()); ++entry) {\r
+            const unsigned start  = instPos[entry];\r
+            const spv::Op  opCode = asOpCode(start);\r
 \r
             if (opCode == spv::OpFunction)\r
                 fnId   = asId(start + 2);\r
@@ -571,20 +571,18 @@ namespace spv {
                 fnId = spv::NoResult;\r
 \r
             if (fnId != spv::NoResult) { // if inside a function\r
-                const int word   = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);\r
-                const int result = spv::InstructionDesc[opCode].hasResult() ? word : -1;\r
+                if (spv::InstructionDesc[opCode].hasResult()) {\r
+                    const unsigned word    = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);\r
+                    const spv::Id  resId   = asId(word);\r
+                    std::uint32_t  hashval = fnId * 17; // small prime\r
 \r
-                if (result > 0) {\r
-                    const spv::Id resId = asId(result);\r
-                    std::uint32_t hashval = fnId * 17; // small prime\r
-\r
-                    for (int i = entry-1; i >= entry-windowSize; --i) {\r
+                    for (unsigned i = entry-1; i >= entry-windowSize; --i) {\r
                         if (asOpCode(instPos[i]) == spv::OpFunction)\r
                             break;\r
                         hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime\r
                     }\r
 \r
-                    for (int i = entry; i <= entry + windowSize; ++i) {\r
+                    for (unsigned i = entry; i <= entry + windowSize; ++i) {\r
                         if (asOpCode(instPos[i]) == spv::OpFunctionEnd)\r
                             break;\r
                         hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime\r
@@ -602,7 +600,7 @@ namespace spv {
         fnId = spv::NoResult;\r
 \r
         process(\r
-            [&](spv::Op opCode, int start) {\r
+            [&](spv::Op opCode, unsigned start) {\r
                 switch (opCode) {\r
                 case spv::OpFunction:\r
                     // Reset counters at each function\r
@@ -645,7 +643,7 @@ namespace spv {
                 }\r
 \r
                 return false;\r
-        },\r
+            },\r
 \r
             [&](spv::Id& id) {\r
                 if (thisOpCode != spv::OpNop) {\r
@@ -655,63 +653,9 @@ namespace spv {
                     if (isOldIdUnmapped(id))\r
                         localId(id, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));\r
                 }\r
-        });\r
+            });\r
     }\r
 \r
-#ifdef NOTDEF\r
-    // remove bodies of uncalled functions\r
-    void spirvbin_t::offsetIds()\r
-    {\r
-        // Count of how many functions each ID appears within\r
-        std::unordered_map<spv::Id, int> idFnCount;\r
-        std::unordered_map<spv::Id, int> idDefinedLoc;\r
-        idset_t                          idsUsed;  // IDs used in a given function\r
-\r
-        int instCount = 0;\r
-\r
-        // create a count of how many functions each ID is used within\r
-        process(\r
-            [&](spv::OpCode opCode, int start) {\r
-                ++instCount;\r
-\r
-                switch (opCode) {\r
-                case spv::OpFunction:\r
-                    for (const auto id : idsUsed)\r
-                        ++idFnCount[id];\r
-                    idsUsed.clear();\r
-                    break;\r
-\r
-                default:\r
-                    {\r
-                        const int word   = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);\r
-                        const int result = spv::InstructionDesc[opCode].hasResult() ? word : -1;\r
-\r
-                        if (result > 0)\r
-                            idDefinedLoc[asId(result)] = instCount;\r
-                    }\r
-                    break;\r
-                }\r
-\r
-                return false;\r
-        },\r
-\r
-            [&](spv::Id& id) { idsUsed.insert(id); });\r
-\r
-        // For each ID defined in exactly one function, replace uses by\r
-        // negative offset to definitions in instructions.\r
-\r
-        static const int relOffsetLimit = 64;\r
-\r
-        instCount = 0;\r
-        process([&](spv::OpCode, int) { ++instCount; return false; },\r
-            [&](spv::Id& id) {\r
-                if (idFnCount[id] == 1 && (instCount - idDefinedLoc[id]) < relOffsetLimit)\r
-                    id = idDefinedLoc[id] - instCount;\r
-        });\r
-    }\r
-#endif\r
-\r
-\r
     // EXPERIMENTAL: forward IO and uniform load/stores into operands\r
     // This produces invalid Schema-0 SPIRV\r
     void spirvbin_t::forwardLoadStores()\r
@@ -721,7 +665,7 @@ namespace spv {
 \r
         // EXPERIMENTAL: Forward input and access chain loads into consumptions\r
         process(\r
-            [&](spv::Op opCode, int start) {\r
+            [&](spv::Op opCode, unsigned start) {\r
                 // Add inputs and uniforms to the map\r
                 if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&\r
                     (spv[start+3] == spv::StorageClassUniform ||\r
@@ -738,7 +682,7 @@ namespace spv {
                 }\r
 \r
                 return false;\r
-        },\r
+            },\r
 \r
             [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }\r
         );\r
@@ -748,7 +692,7 @@ namespace spv {
         idMap.clear();\r
 \r
         process(\r
-            [&](spv::Op opCode, int start) {\r
+            [&](spv::Op opCode, unsigned start) {\r
                 // Add inputs and uniforms to the map\r
                 if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&\r
                     (spv[start+3] == spv::StorageClassOutput))\r
@@ -760,7 +704,7 @@ namespace spv {
                 }\r
 \r
                 return false;\r
-        },\r
+            },\r
             op_fn_nop);\r
 \r
         process(\r
@@ -781,7 +725,7 @@ namespace spv {
 \r
         // Find all the function local pointers stored at most once, and not via access chains\r
         process(\r
-            [&](spv::Op opCode, int start) {\r
+            [&](spv::Op opCode, unsigned start) {\r
                 const int wordCount = asWordCount(start);\r
 \r
                 // Add local variables to the map\r
@@ -826,34 +770,33 @@ namespace spv {
                 }\r
 \r
                 return true;\r
-        },\r
+            },\r
             op_fn_nop);\r
 \r
         process(\r
-            [&](spv::Op opCode, int start) {\r
+            [&](spv::Op opCode, unsigned start) {\r
                 if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0)\r
                     idMap[asId(start+2)] = idMap[asId(start+3)];\r
                 return false;\r
-        },\r
+            },\r
             op_fn_nop);\r
 \r
         // Remove the load/store/variables for the ones we've discovered\r
         process(\r
-            [&](spv::Op opCode, int start) {\r
+            [&](spv::Op opCode, unsigned start) {\r
                 if ((opCode == spv::OpLoad  && fnLocalVars.count(asId(start+3)) > 0) ||\r
                     (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) ||\r
                     (opCode == spv::OpVariable && fnLocalVars.count(asId(start+2)) > 0)) {\r
-                        stripInst(start);\r
-                        return true;\r
+                    stripInst(start);\r
+                    return true;\r
                 }\r
 \r
                 return false;\r
-        },\r
+            },\r
 \r
             [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }\r
         );\r
 \r
-\r
         strip();          // strip out data we decided to eliminate\r
         buildLocalMaps(); // rebuild ID mapping data\r
     }\r
@@ -884,7 +827,7 @@ namespace spv {
 \r
                     // decrease counts of called functions\r
                     process(\r
-                        [&](spv::Op opCode, int start) {\r
+                        [&](spv::Op opCode, unsigned start) {\r
                             if (opCode == spv::Op::OpFunctionCall) {\r
                                 const auto call_it = fnCalls.find(asId(start + 3));\r
                                 if (call_it != fnCalls.end()) {\r
@@ -894,7 +837,7 @@ namespace spv {
                             }\r
 \r
                             return true;\r
-                    },\r
+                        },\r
                         op_fn_nop,\r
                         fn->second.first,\r
                         fn->second.second);\r
@@ -914,7 +857,7 @@ namespace spv {
 \r
         // Count function variable use\r
         process(\r
-            [&](spv::Op opCode, int start) {\r
+            [&](spv::Op opCode, unsigned start) {\r
                 if (opCode == spv::OpVariable) { ++varUseCount[asId(start+2)]; return true; }\r
                 return false;\r
         },\r
@@ -924,7 +867,7 @@ namespace spv {
 \r
         // Remove single-use function variables + associated decorations and names\r
         process(\r
-            [&](spv::Op opCode, int start) {\r
+            [&](spv::Op opCode, unsigned start) {\r
                 if ((opCode == spv::OpVariable && varUseCount[asId(start+2)] == 1)  ||\r
                     (opCode == spv::OpDecorate && varUseCount[asId(start+1)] == 1)  ||\r
                     (opCode == spv::OpName     && varUseCount[asId(start+1)] == 1)) {\r
@@ -1041,7 +984,7 @@ namespace spv {
 #endif // NOTDEF\r
 \r
     // Return start position in SPV of given type.  error if not found.\r
-    int spirvbin_t::typePos(spv::Id id) const\r
+    unsigned spirvbin_t::typePos(spv::Id id) const\r
     {\r
         const auto tid_it = typeConstPosR.find(id);\r
         if (tid_it == typeConstPosR.end())\r
@@ -1052,7 +995,7 @@ namespace spv {
 \r
     // Hash types to canonical values.  This can return ID collisions (it's a bit\r
     // inevitable): it's up to the caller to handle that gracefully.\r
-    std::uint32_t spirvbin_t::hashType(int typeStart) const\r
+    std::uint32_t spirvbin_t::hashType(unsigned typeStart) const\r
     {\r
         const unsigned wordCount   = asWordCount(typeStart);\r
         const spv::Op  opCode      = asOpCode(typeStart);\r
@@ -1160,7 +1103,7 @@ namespace spv {
 \r
         // Allocate a new binary big enough to hold old binary\r
         // We'll step this iterator through the strip ranges as we go through the binary\r
-        decltype(stripRange)::const_iterator strip_it = stripRange.begin();\r
+        auto strip_it = stripRange.begin();\r
 \r
         int strippedPos = 0;\r
         for (unsigned word = 0; word < unsigned(spv.size()); ++word) {\r
@@ -1201,12 +1144,6 @@ namespace spv {
         mapRemainder(); // map any unmapped IDs\r
         applyMap();     // Now remap each shader to the new IDs we've come up with\r
         strip();        // strip out data we decided to eliminate\r
-\r
-#define EXPERIMENT3 0\r
-#if (EXPERIMENT3)\r
-        // TODO: ... shortcuts for simple single-const access chains and constants,\r
-        // folded into high half of the ID space.\r
-#endif\r
     }\r
 \r
     // remap from a memory image\r
index 5af95f9..dc41264 100644 (file)
@@ -43,7 +43,7 @@ namespace spv {
 \r
 // MSVC defines __cplusplus as an older value, even when it supports almost all of 11.\r
 // We handle that here by making our own symbol.\r
-#if __cplusplus >= 201103L || _MSC_VER >= 1800\r
+#if __cplusplus >= 201103L || _MSC_VER >= 1700\r
 #   define use_cpp11 1\r
 #endif\r
 \r
@@ -84,6 +84,7 @@ public:
     void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)\r
     {\r
         printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");\r
+        exit(5);\r
     }\r
 };\r
 \r
@@ -137,9 +138,9 @@ private:
 \r
    typedef std::uint32_t spirword_t;\r
 \r
-   typedef std::pair<int, int> range_t;\r
-   typedef std::function<void(spv::Id&)>           idfn_t;\r
-   typedef std::function<bool(spv::Op, int start)> instfn_t;\r
+   typedef std::pair<unsigned, unsigned> range_t;\r
+   typedef std::function<void(spv::Id&)>                idfn_t;\r
+   typedef std::function<bool(spv::Op, unsigned start)> instfn_t;\r
 \r
    // Special Values for ID map:\r
    static const spv::Id unmapped;     // unchanged from default value\r
@@ -168,14 +169,14 @@ private:
    range_t typeRange(spv::Op opCode)       const;\r
    range_t constRange(spv::Op opCode)      const;\r
    \r
-   spv::Id&        asId(int word)                { return spv[word]; }\r
-   const spv::Id&  asId(int word)          const { return spv[word]; }\r
-   spv::Op         asOpCode(int word)      const { return opOpCode(spv[word]); }\r
-   std::uint32_t   asOpCodeHash(int word);\r
-   spv::Decoration asDecoration(int word)  const { return spv::Decoration(spv[word]); }\r
-   unsigned        asWordCount(int word)   const { return opWordCount(spv[word]); }\r
-   spv::Id         asTypeConstId(int word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }\r
-   int             typePos(spv::Id id)     const;\r
+   spv::Id&        asId(unsigned word)                { return spv[word]; }\r
+   const spv::Id&  asId(unsigned word)          const { return spv[word]; }\r
+   spv::Op         asOpCode(unsigned word)      const { return opOpCode(spv[word]); }\r
+   std::uint32_t   asOpCodeHash(unsigned word);\r
+   spv::Decoration asDecoration(unsigned word)  const { return spv::Decoration(spv[word]); }\r
+   unsigned        asWordCount(unsigned word)   const { return opWordCount(spv[word]); }\r
+   spv::Id         asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }\r
+   unsigned        typePos(spv::Id id)          const;\r
 \r
    static unsigned    opWordCount(spirword_t data) { return data >> spv::WordCountShift; }\r
    static spv::Op     opOpCode(spirword_t data)    { return spv::Op(data & spv::OpCodeMask); }\r
@@ -201,7 +202,7 @@ private:
    inline spv::Id   nextUnusedId(spv::Id id);\r
 \r
    void buildLocalMaps();\r
-   std::string literalString(int word) const; // Return literal as a std::string\r
+   std::string literalString(unsigned word) const; // Return literal as a std::string\r
    int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }\r
 \r
    bool isNewIdMapped(spv::Id newId)   const { return isMapped(newId);            }\r
@@ -212,10 +213,10 @@ private:
 \r
    // bool    matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;\r
    // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;\r
-   std::uint32_t hashType(int typeStart) const;\r
+   std::uint32_t hashType(unsigned typeStart) const;\r
 \r
-   spirvbin_t& process(instfn_t, idfn_t, int begin = 0, int end = 0);\r
-   int         processInstruction(int word, instfn_t, idfn_t);\r
+   spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);\r
+   int         processInstruction(unsigned word, instfn_t, idfn_t);\r
 \r
    void        validate() const;\r
    void        mapTypeConst();\r
@@ -251,12 +252,12 @@ private:
 \r
    // Add a strip range for a given instruction starting at 'start'\r
    // Note: avoiding brace initializers to please older versions os MSVC.\r
-   void stripInst(int start) { stripRange.push_back(std::pair<unsigned, unsigned>(start, start + asWordCount(start))); }\r
+   void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }\r
 \r
    // Function start and end.  use unordered_map because we'll have\r
    // many fewer functions than IDs.\r
-   std::unordered_map<spv::Id, std::pair<int, int>> fnPos;\r
-   std::unordered_map<spv::Id, std::pair<int, int>> fnPosDCE; // deleted functions\r
+   std::unordered_map<spv::Id, range_t> fnPos;\r
+   std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions\r
 \r
    // Which functions are called, anywhere in the module, with a call count\r
    std::unordered_map<spv::Id, int> fnCalls;\r
@@ -270,7 +271,7 @@ private:
    spv::Id largestNewId;    // biggest new ID we have mapped anything to\r
 \r
    // Sections of the binary to strip, given as [begin,end)\r
-   std::vector<std::pair<unsigned, unsigned>> stripRange;\r
+   std::vector<range_t> stripRange;\r
 \r
    // processing options:\r
    std::uint32_t options;\r
index e14c8b5..444403b 100644 (file)
 //POSSIBILITY OF SUCH DAMAGE.\r
 //\r
 \r
-#include <iostream>
-#include <fstream>
-#include <cstring>
-#include <stdexcept>
-
-#include "../SPIRV/SPVRemapper.h"
-
-namespace {
-
-    typedef unsigned int SpvWord;
-
-    // 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.
-
-    // OS dependent path separator (avoiding boost::filesystem dependency)
-#if defined(_WIN32)
-    char path_sep_char() { return '\\'; }
-#else
-    char path_sep_char() { return '/';  }
-#endif
-
-    std::string 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);
-    }
-
-    void errHandler(const std::string& str) {
-        std::cout << str << std::endl;
-        exit(5);
-    }
-
-    void logHandler(const std::string& str) {
-        std::cout << str << std::endl;
-    }
-
-    // Read word stream from disk
-    void read(std::vector<SpvWord>& spv, const std::string& inFilename)
-    {
-        std::ifstream fp;
-
-        std::cout << "  reading: " << inFilename << std::endl;
-
-        spv.clear();
-        fp.open(inFilename, std::fstream::in | std::fstream::binary);
-
-        if (fp.fail())
-            errHandler("error opening file for read: ");
-
-        // Reserve space (for efficiency, not for correctness)
-        fp.seekg(0, fp.end);
-        spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord));
-        fp.seekg(0, fp.beg);
-
-        while (!fp.eof()) {
-            SpvWord inWord;
-            fp.read((char *)&inWord, sizeof(inWord));
-
-            if (!fp.eof()) {
-                spv.push_back(inWord);
-                if (fp.fail())
-                    errHandler(std::string("error reading file: ") + inFilename);
-            }
-        }
-    }
-
-    void write(std::vector<SpvWord>& spv, const std::string& outFile)
-    {
-        if (outFile.empty())
-            errHandler("missing output filename.");
-
-        std::ofstream fp;
-
-        std::cout << "  writing: " << outFile << std::endl;
-
-        fp.open(outFile, std::fstream::out | std::fstream::binary);
-
-        if (fp.fail())
-            errHandler(std::string("error opening file for write: ") + outFile);
-
-        for (auto word : spv) {
-            fp.write((char *)&word, sizeof(word));
-            if (fp.fail())
-                errHandler(std::string("error writing file: ") + outFile);
-        }
-
-        // file is closed by destructor
-    }
-
-    // Print helpful usage message to stdout, and exit
-    void usage(const char* const name, const char* const msg = 0)
-    {
-        if (msg)
-            std::cout << msg << std::endl << std::endl;
-
-        std::cout << "Usage: " << std::endl;
-
-        std::cout << "  " << basename(name)
-            << " [-v[v[...]] | --verbose [int]]"
-            << " [--map (all|types|names|funcs)]"
-            << " [--dce (all|types|funcs)]"
-            << " [--opt (all|loadstore)]"
-            << " [--strip-all | --strip all | -s]" 
-            << " [--do-everything]" 
-            << " --input | -i file1 [file2...] --output|-o DESTDIR"
-            << std::endl;
-
-        std::cout << "  " << basename(name) << " [--version | -V]" << std::endl;
-        std::cout << "  " << basename(name) << " [--help | -?]" << std::endl;
-
-        exit(5);
-    }
-
-    // grind through each SPIR in turn
-    void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,
-        int opts, int verbosity)
-    {
-        for (const auto& filename : inputFile) {
-            std::vector<SpvWord> spv;
-            read(spv, filename);
-            spv::spirvbin_t(verbosity).remap(spv, opts);
-
-            const std::string outfile = outputDir + path_sep_char() + basename(filename);
-
-            write(spv, outfile);
-        }
-
-        if (verbosity > 0)
-            std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;
-    }
-
-    // Parse command line options
-    void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,
-        std::string& outputDir,
-        int& options,
-        int& verbosity)
-    {
-        if (argc < 2)
-            usage(argv[0]);
-
-        verbosity  = 0;
-        options    = spv::spirvbin_t::Options::NONE;
-
-        // Parse command line.
-        // boost::program_options would be quite a bit nicer, but we don't want to
-        // introduce a dependency on boost.
-        for (int a=1; a<argc; ) {
-            const std::string arg = argv[a];
-
-            if (arg == "--output" || arg == "-o") {
-                // Output directory
-                if (++a >= argc)
-                    usage(argv[0], "--output requires an argument");
-                if (!outputDir.empty())
-                    usage(argv[0], "--output can be provided only once");
-
-                outputDir = argv[a++];
-
-                // Remove trailing directory separator characters
-                while (!outputDir.empty() && outputDir.back() == path_sep_char())
-                    outputDir.pop_back();
-
-            }
-            else if (arg == "-vv")     { verbosity = 2; ++a; } // verbosity shortcuts
-            else if (arg == "-vvv")    { verbosity = 3; ++a; } // ...
-            else if (arg == "-vvvv")   { verbosity = 4; ++a; } // ...
-            else if (arg == "-vvvvv")  { verbosity = 5; ++a; } // ...
-
-            else if (arg == "--verbose" || arg == "-v") {
-                ++a;
-                verbosity = 1;
-
-                if (a < argc) {
-                    try {
-                        verbosity = std::stoi(argv[a]);
-                        ++a;
-                    } catch (const std::invalid_argument&) { } // ok to have no numeric value
-                }
-            }
-            else if (arg == "--version" || arg == "-V") {
-                std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl;
-                exit(0);
-            } else if (arg == "--input" || arg == "-i") {
-                // Collect input files
-                for (++a; a < argc && argv[a][0] != '-'; ++a)
-                    inputFile.push_back(argv[a]);
-            } else if (arg == "--do-everything") {
-                ++a;
-                options = options | spv::spirvbin_t::Options::DO_EVERYTHING;
-            } else if (arg == "--strip-all" || arg == "-s") {
-                ++a;
-                options = options | spv::spirvbin_t::Options::STRIP;
-            } else if (arg == "--strip") {
-                ++a;
-                if (strncmp(argv[a], "all", 3) == 0) {
-                    options = options | spv::spirvbin_t::Options::STRIP;
-                    ++a;
-                }
-            } else if (arg == "--dce") {
-                // Parse comma (or colon, etc) separated list of things to dce
-                ++a;
-                for (const char* c = argv[a]; *c; ++c) {
-                    if (strncmp(c, "all", 3) == 0) {
-                        options = (options | spv::spirvbin_t::Options::DCE_ALL);
-                        c += 3;
-                    } else if (strncmp(c, "*", 1) == 0) {
-                        options = (options | spv::spirvbin_t::Options::DCE_ALL);
-                        c += 1;
-                    } else if (strncmp(c, "funcs", 5) == 0) {
-                        options = (options | spv::spirvbin_t::Options::DCE_FUNCS);
-                        c += 5;
-                    } else if (strncmp(c, "types", 5) == 0) {
-                        options = (options | spv::spirvbin_t::Options::DCE_TYPES);
-                        c += 5;
-                    }
-                }
-                ++a;
-            } else if (arg == "--map") {
-                // Parse comma (or colon, etc) separated list of things to map
-                ++a;
-                for (const char* c = argv[a]; *c; ++c) {
-                    if (strncmp(c, "all", 3) == 0) {
-                        options = (options | spv::spirvbin_t::Options::MAP_ALL);
-                        c += 3;
-                    } else if (strncmp(c, "*", 1) == 0) {
-                        options = (options | spv::spirvbin_t::Options::MAP_ALL);
-                        c += 1;
-                    } else if (strncmp(c, "types", 5) == 0) {
-                        options = (options | spv::spirvbin_t::Options::MAP_TYPES);
-                        c += 5;
-                    } else if (strncmp(c, "names", 5) == 0) {
-                        options = (options | spv::spirvbin_t::Options::MAP_NAMES);
-                        c += 5;
-                    } else if (strncmp(c, "funcs", 5) == 0) {
-                        options = (options | spv::spirvbin_t::Options::MAP_FUNCS);
-                        c += 5;
-                    }
-                }
-                ++a;
-            } else if (arg == "--opt") {
-                ++a;
-                for (const char* c = argv[a]; *c; ++c) {
-                    if (strncmp(c, "all", 3) == 0) {
-                        options = (options | spv::spirvbin_t::Options::OPT_ALL);
-                        c += 3;
-                    } else if (strncmp(c, "*", 1) == 0) {
-                        options = (options | spv::spirvbin_t::Options::OPT_ALL);
-                        c += 1;
-                    } else if (strncmp(c, "loadstore", 9) == 0) {
-                        options = (options | spv::spirvbin_t::Options::OPT_LOADSTORE);
-                        c += 9;
-                    }
-                }
-                ++a;
-            } else if (arg == "--help" || arg == "-?") {
-                usage(argv[0]);
-            } else {
-                usage(argv[0], "Unknown command line option");
-            }
-        }
-    }
-
-} // namespace
-
-
-int main(int argc, char** argv)
-{
-#ifdef use_cpp11
-    std::vector<std::string> inputFile;
-    std::string              outputDir;
-    int                      opts;
-    int                      verbosity;
-
-    // handle errors by exiting
-    spv::spirvbin_t::registerErrorHandler(errHandler);
-
-    // Log messages to std::cout
-    spv::spirvbin_t::registerLogHandler(logHandler);
-
-    if (argc < 2)
-        usage(argv[0]);
-
-    parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity);
-
-    if (outputDir.empty())
-        usage(argv[0], "Output directory required");
-
-    std::string errmsg;
-
-    // Main operations: read, remap, and write.
-    execute(inputFile, outputDir, opts, verbosity);
-
-#endif
-
-    // If we get here, everything went OK!  Nothing more to be done.
-}
+#include <iostream>\r
+#include <fstream>\r
+#include <cstring>\r
+#include <stdexcept>\r
+\r
+#include "../SPIRV/SPVRemapper.h"\r
+\r
+namespace {\r
+\r
+    typedef unsigned int SpvWord;\r
+\r
+    // Poor man's basename: given a complete path, return file portion.\r
+    // E.g:\r
+    //      Linux:  /foo/bar/test  -> test\r
+    //      Win:   c:\foo\bar\test -> test\r
+    // It's not very efficient, but that doesn't matter for our minimal-duty use.\r
+    // Using boost::filesystem would be better in many ways, but want to avoid that dependency.\r
+\r
+    // OS dependent path separator (avoiding boost::filesystem dependency)\r
+#if defined(_WIN32)\r
+    char path_sep_char() { return '\\'; }\r
+#else\r
+    char path_sep_char() { return '/';  }\r
+#endif\r
+\r
+    std::string basename(const std::string filename)\r
+    {\r
+        const size_t sepLoc = filename.find_last_of(path_sep_char());\r
+\r
+        return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1);\r
+    }\r
+\r
+    void errHandler(const std::string& str) {\r
+        std::cout << str << std::endl;\r
+        exit(5);\r
+    }\r
+\r
+    void logHandler(const std::string& str) {\r
+        std::cout << str << std::endl;\r
+    }\r
+\r
+    // Read word stream from disk\r
+    void read(std::vector<SpvWord>& spv, const std::string& inFilename, int verbosity)\r
+    {\r
+        std::ifstream fp;\r
+\r
+        if (verbosity > 0)\r
+            logHandler(std::string("  reading: ") + inFilename);\r
+\r
+        spv.clear();\r
+        fp.open(inFilename, std::fstream::in | std::fstream::binary);\r
+\r
+        if (fp.fail())\r
+            errHandler("error opening file for read: ");\r
+\r
+        // Reserve space (for efficiency, not for correctness)\r
+        fp.seekg(0, fp.end);\r
+        spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord));\r
+        fp.seekg(0, fp.beg);\r
+\r
+        while (!fp.eof()) {\r
+            SpvWord inWord;\r
+            fp.read((char *)&inWord, sizeof(inWord));\r
+\r
+            if (!fp.eof()) {\r
+                spv.push_back(inWord);\r
+                if (fp.fail())\r
+                    errHandler(std::string("error reading file: ") + inFilename);\r
+            }\r
+        }\r
+    }\r
+\r
+    void write(std::vector<SpvWord>& spv, const std::string& outFile, int verbosity)\r
+    {\r
+        if (outFile.empty())\r
+            errHandler("missing output filename.");\r
+\r
+        std::ofstream fp;\r
+\r
+        if (verbosity > 0)\r
+            logHandler(std::string("  writing: ") + outFile);\r
+\r
+        fp.open(outFile, std::fstream::out | std::fstream::binary);\r
+\r
+        if (fp.fail())\r
+            errHandler(std::string("error opening file for write: ") + outFile);\r
+\r
+        for (auto word : spv) {\r
+            fp.write((char *)&word, sizeof(word));\r
+            if (fp.fail())\r
+                errHandler(std::string("error writing file: ") + outFile);\r
+        }\r
+\r
+        // file is closed by destructor\r
+    }\r
+\r
+    // Print helpful usage message to stdout, and exit\r
+    void usage(const char* const name, const char* const msg = 0)\r
+    {\r
+        if (msg)\r
+            std::cout << msg << std::endl << std::endl;\r
+\r
+        std::cout << "Usage: " << std::endl;\r
+\r
+        std::cout << "  " << basename(name)\r
+            << " [-v[v[...]] | --verbose [int]]"\r
+            << " [--map (all|types|names|funcs)]"\r
+            << " [--dce (all|types|funcs)]"\r
+            << " [--opt (all|loadstore)]"\r
+            << " [--strip-all | --strip all | -s]" \r
+            << " [--do-everything]" \r
+            << " --input | -i file1 [file2...] --output|-o DESTDIR"\r
+            << std::endl;\r
+\r
+        std::cout << "  " << basename(name) << " [--version | -V]" << std::endl;\r
+        std::cout << "  " << basename(name) << " [--help | -?]" << std::endl;\r
+\r
+        exit(5);\r
+    }\r
+\r
+    // grind through each SPIR in turn\r
+    void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,\r
+        int opts, int verbosity)\r
+    {\r
+        for (const auto& filename : inputFile) {\r
+            std::vector<SpvWord> spv;\r
+            read(spv, filename, verbosity);\r
+            spv::spirvbin_t(verbosity).remap(spv, opts);\r
+\r
+            const std::string outfile = outputDir + path_sep_char() + basename(filename);\r
+\r
+            write(spv, outfile, verbosity);\r
+        }\r
+\r
+        if (verbosity > 0)\r
+            std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;\r
+    }\r
+\r
+    // Parse command line options\r
+    void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,\r
+        std::string& outputDir,\r
+        int& options,\r
+        int& verbosity)\r
+    {\r
+        if (argc < 2)\r
+            usage(argv[0]);\r
+\r
+        verbosity  = 0;\r
+        options    = spv::spirvbin_t::Options::NONE;\r
+\r
+        // Parse command line.\r
+        // boost::program_options would be quite a bit nicer, but we don't want to\r
+        // introduce a dependency on boost.\r
+        for (int a=1; a<argc; ) {\r
+            const std::string arg = argv[a];\r
+\r
+            if (arg == "--output" || arg == "-o") {\r
+                // Output directory\r
+                if (++a >= argc)\r
+                    usage(argv[0], "--output requires an argument");\r
+                if (!outputDir.empty())\r
+                    usage(argv[0], "--output can be provided only once");\r
+\r
+                outputDir = argv[a++];\r
+\r
+                // Remove trailing directory separator characters\r
+                while (!outputDir.empty() && outputDir.back() == path_sep_char())\r
+                    outputDir.pop_back();\r
+\r
+            }\r
+            else if (arg == "-vv")     { verbosity = 2; ++a; } // verbosity shortcuts\r
+            else if (arg == "-vvv")    { verbosity = 3; ++a; } // ...\r
+            else if (arg == "-vvvv")   { verbosity = 4; ++a; } // ...\r
+            else if (arg == "-vvvvv")  { verbosity = 5; ++a; } // ...\r
+\r
+            else if (arg == "--verbose" || arg == "-v") {\r
+                ++a;\r
+                verbosity = 1;\r
+\r
+                if (a < argc) {\r
+                    try {\r
+                        verbosity = std::stoi(argv[a]);\r
+                        ++a;\r
+                    } catch (const std::invalid_argument&) { } // ok to have no numeric value\r
+                }\r
+            }\r
+            else if (arg == "--version" || arg == "-V") {\r
+                std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl;\r
+                exit(0);\r
+            } else if (arg == "--input" || arg == "-i") {\r
+                // Collect input files\r
+                for (++a; a < argc && argv[a][0] != '-'; ++a)\r
+                    inputFile.push_back(argv[a]);\r
+            } else if (arg == "--do-everything") {\r
+                ++a;\r
+                options = options | spv::spirvbin_t::Options::DO_EVERYTHING;\r
+            } else if (arg == "--strip-all" || arg == "-s") {\r
+                ++a;\r
+                options = options | spv::spirvbin_t::Options::STRIP;\r
+            } else if (arg == "--strip") {\r
+                ++a;\r
+                if (strncmp(argv[a], "all", 3) == 0) {\r
+                    options = options | spv::spirvbin_t::Options::STRIP;\r
+                    ++a;\r
+                }\r
+            } else if (arg == "--dce") {\r
+                // Parse comma (or colon, etc) separated list of things to dce\r
+                ++a;\r
+                for (const char* c = argv[a]; *c; ++c) {\r
+                    if (strncmp(c, "all", 3) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::DCE_ALL);\r
+                        c += 3;\r
+                    } else if (strncmp(c, "*", 1) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::DCE_ALL);\r
+                        c += 1;\r
+                    } else if (strncmp(c, "funcs", 5) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::DCE_FUNCS);\r
+                        c += 5;\r
+                    } else if (strncmp(c, "types", 5) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::DCE_TYPES);\r
+                        c += 5;\r
+                    }\r
+                }\r
+                ++a;\r
+            } else if (arg == "--map") {\r
+                // Parse comma (or colon, etc) separated list of things to map\r
+                ++a;\r
+                for (const char* c = argv[a]; *c; ++c) {\r
+                    if (strncmp(c, "all", 3) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::MAP_ALL);\r
+                        c += 3;\r
+                    } else if (strncmp(c, "*", 1) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::MAP_ALL);\r
+                        c += 1;\r
+                    } else if (strncmp(c, "types", 5) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::MAP_TYPES);\r
+                        c += 5;\r
+                    } else if (strncmp(c, "names", 5) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::MAP_NAMES);\r
+                        c += 5;\r
+                    } else if (strncmp(c, "funcs", 5) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::MAP_FUNCS);\r
+                        c += 5;\r
+                    }\r
+                }\r
+                ++a;\r
+            } else if (arg == "--opt") {\r
+                ++a;\r
+                for (const char* c = argv[a]; *c; ++c) {\r
+                    if (strncmp(c, "all", 3) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::OPT_ALL);\r
+                        c += 3;\r
+                    } else if (strncmp(c, "*", 1) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::OPT_ALL);\r
+                        c += 1;\r
+                    } else if (strncmp(c, "loadstore", 9) == 0) {\r
+                        options = (options | spv::spirvbin_t::Options::OPT_LOADSTORE);\r
+                        c += 9;\r
+                    }\r
+                }\r
+                ++a;\r
+            } else if (arg == "--help" || arg == "-?") {\r
+                usage(argv[0]);\r
+            } else {\r
+                usage(argv[0], "Unknown command line option");\r
+            }\r
+        }\r
+    }\r
+\r
+} // namespace\r
+\r
+\r
+int main(int argc, char** argv)\r
+{\r
+    std::vector<std::string> inputFile;\r
+    std::string              outputDir;\r
+    int                      opts;\r
+    int                      verbosity;\r
+\r
+#ifdef use_cpp11\r
+    // handle errors by exiting\r
+    spv::spirvbin_t::registerErrorHandler(errHandler);\r
+\r
+    // Log messages to std::cout\r
+    spv::spirvbin_t::registerLogHandler(logHandler);\r
+#endif\r
+\r
+    if (argc < 2)\r
+        usage(argv[0]);\r
+\r
+    parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity);\r
+\r
+    if (outputDir.empty())\r
+        usage(argv[0], "Output directory required");\r
+\r
+    std::string errmsg;\r
+\r
+    // Main operations: read, remap, and write.\r
+    execute(inputFile, outputDir, opts, verbosity);\r
+\r
+    // If we get here, everything went OK!  Nothing more to be done.\r
+}\r