glslang: Fix over 100 warnings from MSVC warning level 4.
[platform/upstream/glslang.git] / SPIRV / SPVRemapper.h
1 //\r
2 //Copyright (C) 2015 LunarG, Inc.\r
3 //\r
4 //All rights reserved.\r
5 //\r
6 //Redistribution and use in source and binary forms, with or without\r
7 //modification, are permitted provided that the following conditions\r
8 //are met:\r
9 //\r
10 //    Redistributions of source code must retain the above copyright\r
11 //    notice, this list of conditions and the following disclaimer.\r
12 //\r
13 //    Redistributions in binary form must reproduce the above\r
14 //    copyright notice, this list of conditions and the following\r
15 //    disclaimer in the documentation and/or other materials provided\r
16 //    with the distribution.\r
17 //\r
18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
19 //    contributors may be used to endorse or promote products derived\r
20 //    from this software without specific prior written permission.\r
21 //\r
22 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
23 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
24 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
25 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
26 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
27 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
28 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
29 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
30 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
31 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
32 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
33 //POSSIBILITY OF SUCH DAMAGE.\r
34 //\r
35 \r
36 #ifndef SPIRVREMAPPER_H\r
37 #define SPIRVREMAPPER_H\r
38 \r
39 #include <string>\r
40 #include <vector>\r
41 \r
42 namespace spv {\r
43 \r
44 // MSVC defines __cplusplus as an older value, even when it supports almost all of 11.\r
45 // We handle that here by making our own symbol.\r
46 #if __cplusplus >= 201103L || _MSC_VER >= 1800\r
47 #   define use_cpp11 1\r
48 #endif\r
49 \r
50 class spirvbin_base_t\r
51 {\r
52 public:\r
53    enum Options {\r
54       NONE          = 0,\r
55       STRIP         = (1<<0),\r
56       MAP_TYPES     = (1<<1),\r
57       MAP_NAMES     = (1<<2),\r
58       MAP_FUNCS     = (1<<3),\r
59       DCE_FUNCS     = (1<<4),\r
60       DCE_VARS      = (1<<5),\r
61       DCE_TYPES     = (1<<6),\r
62       OPT_LOADSTORE = (1<<7),\r
63       OPT_FWD_LS    = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV\r
64       MAP_ALL       = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),\r
65       DCE_ALL       = (DCE_FUNCS | DCE_VARS | DCE_TYPES),\r
66       OPT_ALL       = (OPT_LOADSTORE),\r
67 \r
68       ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),\r
69       DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)\r
70    };\r
71 };\r
72 \r
73 } // namespace SPV\r
74 \r
75 #if !defined (use_cpp11)\r
76 #include <stdio.h>\r
77 \r
78 namespace spv {\r
79 class spirvbin_t : public spirvbin_base_t\r
80 {\r
81 public:\r
82     spirvbin_t(int /*verbose = 0*/) { }\r
83 \r
84     void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)\r
85     {\r
86         printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");\r
87     }\r
88 };\r
89 \r
90 } // namespace SPV\r
91 \r
92 #else // defined (use_cpp11)\r
93 \r
94 #include <functional>\r
95 #include <cstdint>\r
96 #include <unordered_map>\r
97 #include <unordered_set>\r
98 #include <map>\r
99 #include <set>\r
100 #include <cassert>\r
101 \r
102 #include "../../glslang/SPIRV/spirv.h"\r
103 #include "../../glslang/SPIRV/spvIR.h"\r
104 \r
105 namespace spv {\r
106 \r
107 // class to hold SPIRV binary data for remapping, DCE, and debug stripping\r
108 class spirvbin_t : public spirvbin_base_t\r
109 {\r
110 public:\r
111    spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }\r
112    \r
113    // remap on an existing binary in memory\r
114    void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = Options::DO_EVERYTHING);\r
115 \r
116    // Type for error/log handler functions\r
117    typedef std::function<void(const std::string&)> errorfn_t;\r
118    typedef std::function<void(const std::string&)> logfn_t;\r
119 \r
120    // Register error/log handling functions (can be lambda fn / functor / etc)\r
121    static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }\r
122    static void registerLogHandler(logfn_t handler)     { logHandler   = handler; }\r
123 \r
124 protected:\r
125    // This can be overridden to provide other message behavior if needed\r
126    virtual void msg(int minVerbosity, int indent, const std::string& txt) const;\r
127 \r
128 private:\r
129    // Local to global, or global to local ID map\r
130    typedef std::unordered_map<spv::Id, spv::Id> idmap_t;\r
131    typedef std::unordered_set<spv::Id>          idset_t;\r
132 \r
133    void remap(std::uint32_t opts = Options::DO_EVERYTHING);\r
134 \r
135    // Map of names to IDs\r
136    typedef std::unordered_map<std::string, spv::Id> namemap_t;\r
137 \r
138    typedef std::uint32_t spirword_t;\r
139 \r
140    typedef std::pair<int, int> range_t;\r
141    typedef std::function<void(spv::Id&)>           idfn_t;\r
142    typedef std::function<bool(spv::Op, int start)> instfn_t;\r
143 \r
144    // Special Values for ID map:\r
145    static const spv::Id unmapped;     // unchanged from default value\r
146    static const spv::Id unused;       // unused ID\r
147    static const int     header_size;  // SPIR header = 5 words\r
148 \r
149    class id_iterator_t;\r
150 \r
151    // For mapping type entries between different shaders\r
152    typedef std::vector<spirword_t>        typeentry_t;\r
153    typedef std::map<spv::Id, typeentry_t> globaltypes_t;\r
154 \r
155    // A set that preserves position order, and a reverse map\r
156    typedef std::set<int>                    posmap_t;\r
157    typedef std::unordered_map<spv::Id, int> posmap_rev_t;\r
158 \r
159    // handle error\r
160    void error(const std::string& txt) const { errorHandler(txt); }\r
161 \r
162    bool    isConstOp(spv::Op opCode)       const;\r
163    bool    isTypeOp(spv::Op opCode)        const;\r
164    bool    isStripOp(spv::Op opCode)       const;\r
165    bool    isFlowCtrlOpen(spv::Op opCode)  const;\r
166    bool    isFlowCtrlClose(spv::Op opCode) const;\r
167    range_t literalRange(spv::Op opCode)    const;\r
168    range_t typeRange(spv::Op opCode)       const;\r
169    range_t constRange(spv::Op opCode)      const;\r
170    \r
171    spv::Id&        asId(int word)                { return spv[word]; }\r
172    const spv::Id&  asId(int word)          const { return spv[word]; }\r
173    spv::Op         asOpCode(int word)      const { return opOpCode(spv[word]); }\r
174    std::uint32_t   asOpCodeHash(int word);\r
175    spv::Decoration asDecoration(int word)  const { return spv::Decoration(spv[word]); }\r
176    unsigned        asWordCount(int word)   const { return opWordCount(spv[word]); }\r
177    spv::Id         asTypeConstId(int word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }\r
178    int             typePos(spv::Id id)     const;\r
179 \r
180    static unsigned    opWordCount(spirword_t data) { return data >> spv::WordCountShift; }\r
181    static spv::Op     opOpCode(spirword_t data)    { return spv::Op(data & spv::OpCodeMask); }\r
182 \r
183    // Header access & set methods\r
184    spirword_t  magic()    const       { return spv[0]; } // return magic number\r
185    spirword_t  bound()    const       { return spv[3]; } // return Id bound from header\r
186    spirword_t  bound(spirword_t b)    { return spv[3] = b; };\r
187    spirword_t  genmagic() const       { return spv[2]; } // generator magic\r
188    spirword_t  genmagic(spirword_t m) { return spv[2] = m; }\r
189    spirword_t  schemaNum() const      { return spv[4]; } // schema number from header\r
190 \r
191    // Mapping fns: get\r
192    spv::Id     localId(spv::Id id) const { return idMapL[id]; }\r
193 \r
194    // Mapping fns: set\r
195    inline spv::Id   localId(spv::Id id, spv::Id newId);\r
196    void             countIds(spv::Id id);\r
197 \r
198    // Return next unused new local ID.\r
199    // NOTE: boost::dynamic_bitset would be more efficient due to find_next(),\r
200    // which std::vector<bool> doens't have.\r
201    inline spv::Id   nextUnusedId(spv::Id id);\r
202 \r
203    void buildLocalMaps();\r
204    std::string literalString(int word) const; // Return literal as a std::string\r
205    int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }\r
206 \r
207    bool isNewIdMapped(spv::Id newId)   const { return isMapped(newId);            }\r
208    bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }\r
209    bool isOldIdUnused(spv::Id oldId)   const { return localId(oldId) == unused;   }\r
210    bool isOldIdMapped(spv::Id oldId)   const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }\r
211    bool isFunction(spv::Id oldId)      const { return fnPos.find(oldId) != fnPos.end(); }\r
212 \r
213    // bool    matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;\r
214    // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;\r
215    std::uint32_t hashType(int typeStart) const;\r
216 \r
217    spirvbin_t& process(instfn_t, idfn_t, int begin = 0, int end = 0);\r
218    int         processInstruction(int word, instfn_t, idfn_t);\r
219 \r
220    void        validate() const;\r
221    void        mapTypeConst();\r
222    void        mapFnBodies();\r
223    void        optLoadStore();\r
224    void        dceFuncs();\r
225    void        dceVars();\r
226    void        dceTypes();\r
227    void        mapNames();\r
228    void        foldIds();  // fold IDs to smallest space\r
229    void        forwardLoadStores(); // load store forwarding (EXPERIMENTAL)\r
230    void        offsetIds(); // create relative offset IDs\r
231 \r
232    void        applyMap();            // remap per local name map\r
233    void        mapRemainder();        // map any IDs we haven't touched yet\r
234    void        stripDebug();          // strip debug info\r
235    void        strip();               // remove debug symbols\r
236    \r
237    std::vector<spirword_t> spv;      // SPIR words\r
238 \r
239    namemap_t               nameMap;  // ID names from OpName\r
240 \r
241    // Since we want to also do binary ops, we can't use std::vector<bool>.  we could use\r
242    // boost::dynamic_bitset, but we're trying to avoid a boost dependency.\r
243    typedef std::uint64_t bits_t;\r
244    std::vector<bits_t> mapped; // which new IDs have been mapped\r
245    static const int mBits = sizeof(bits_t) * 4;\r
246 \r
247    bool isMapped(spv::Id id) const  { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }\r
248    void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }\r
249    void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }\r
250    size_t maxMappedId() const { return mapped.size() * mBits; }\r
251 \r
252    // Add a strip range for a given instruction starting at 'start'\r
253    // Note: avoiding brace initializers to please older versions os MSVC.\r
254    void stripInst(int start) { stripRange.push_back(std::pair<unsigned, unsigned>(start, start + asWordCount(start))); }\r
255 \r
256    // Function start and end.  use unordered_map because we'll have\r
257    // many fewer functions than IDs.\r
258    std::unordered_map<spv::Id, std::pair<int, int>> fnPos;\r
259    std::unordered_map<spv::Id, std::pair<int, int>> fnPosDCE; // deleted functions\r
260 \r
261    // Which functions are called, anywhere in the module, with a call count\r
262    std::unordered_map<spv::Id, int> fnCalls;\r
263    \r
264    posmap_t     typeConstPos;   // word positions that define types & consts (ordered)\r
265    posmap_rev_t typeConstPosR;  // reverse map from IDs to positions\r
266    \r
267    std::vector<spv::Id>  idMapL;   // ID {M}ap from {L}ocal to {G}lobal IDs\r
268 \r
269    spv::Id entryPoint;      // module entry point\r
270    spv::Id largestNewId;    // biggest new ID we have mapped anything to\r
271 \r
272    // Sections of the binary to strip, given as [begin,end)\r
273    std::vector<std::pair<unsigned, unsigned>> stripRange;\r
274 \r
275    // processing options:\r
276    std::uint32_t options;\r
277    int           verbose;     // verbosity level\r
278 \r
279    static errorfn_t errorHandler;\r
280    static logfn_t   logHandler;\r
281 };\r
282 \r
283 } // namespace SPV\r
284 \r
285 #endif // defined (use_cpp11)\r
286 #endif // SPIRVREMAPPER_H\r