• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- SPIRVUtil.h - SPIR-V Utility Functions --------------------*- C++ -*-===//
2 //
3 //                     The LLVM/SPIRV Translator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal with the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
16 //
17 // Redistributions of source code must retain the above copyright notice,
18 // this list of conditions and the following disclaimers.
19 // Redistributions in binary form must reproduce the above copyright notice,
20 // this list of conditions and the following disclaimers in the documentation
21 // and/or other materials provided with the distribution.
22 // Neither the names of Advanced Micro Devices, Inc., nor the names of its
23 // contributors may be used to endorse or promote products derived from this
24 // Software without specific prior written permission.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
31 // THE SOFTWARE.
32 //
33 //===----------------------------------------------------------------------===//
34 /// \file
35 ///
36 /// This file defines SPIR-V utility functions.
37 ///
38 //===----------------------------------------------------------------------===//
39 
40 #ifndef SPIRVUTIL_H_
41 #define SPIRVUTIL_H_
42 
43 #ifdef _SPIRV_LLVM_API
44 #include "llvm/Support/raw_ostream.h"
45 #define spv_ostream llvm::raw_ostream
46 #else
47 #include <ostream>
48 #define spv_ostream std::ostream
49 #endif
50 
51 #include <algorithm>
52 #include <cassert>
53 #include <cstdint>
54 #include <functional>
55 #include <limits>
56 #include <map>
57 #include <set>
58 #include <sstream>
59 #include <string>
60 #include <unordered_set>
61 #include <vector>
62 
63 // MSVC supports "magic statics" since MSVS 2015.
64 // For the previous version of MSVS we should guard
65 // initialization of local static variables.
66 #if defined (_MSC_VER) && (_MSC_VER < 1900)
67 #include "llvm/Support/Mutex.h"
68 #include "llvm/Support/MutexGuard.h"
69 #endif // LLVM_MSC_PREREQ(1900)
70 
71 namespace SPIRV{
72 #if defined (_MSC_VER) && (_MSC_VER < 1900)
73   static llvm::sys::Mutex MapLock;
74 #endif // LLVM_MSC_PREREQ(1900)
75 
76 #define SPIRV_DEF_NAMEMAP(Type,MapType) \
77 typedef SPIRVMap<Type, std::string> MapType; \
78 inline MapType getNameMap(Type){ MapType MT; return MT;}
79 
80 // A bi-way map
81 template<class Ty1, class Ty2, class Identifier = void>
82 struct SPIRVMap {
83 public:
84   typedef Ty1 KeyTy;
85   typedef Ty2 ValueTy;
86   // Initialize map entries
87   void init();
88 
mapSPIRVMap89   static Ty2 map(Ty1 Key) {
90     Ty2 Val;
91     bool Found = find(Key, &Val);
92     (void) Found;
93     assert (Found && "Invalid key");
94     return Val;
95   }
96 
rmapSPIRVMap97   static Ty1 rmap(Ty2 Key) {
98     Ty1 Val;
99     bool Found = rfind(Key, &Val);
100     (void) Found;
101     assert (Found && "Invalid key");
102     return Val;
103   }
104 
getMapSPIRVMap105   static const SPIRVMap& getMap() {
106 #if defined (_MSC_VER) && (_MSC_VER < 1900)
107     llvm::sys::ScopedLock mapGuard(MapLock);
108 #endif // LLVM_MSC_PREREQ(1900)
109     static const SPIRVMap Map(false);
110     return Map;
111   }
112 
getRMapSPIRVMap113   static const SPIRVMap& getRMap() {
114 #if defined (_MSC_VER) && (_MSC_VER < 1900)
115     llvm::sys::ScopedLock mapGuard(MapLock);
116 #endif // LLVM_MSC_PREREQ(1900)
117     static const SPIRVMap Map(true);
118     return Map;
119   }
120 
foreachSPIRVMap121   static void foreach(std::function<void(Ty1, Ty2)>F) {
122     for (auto &I:getMap().Map)
123       F(I.first, I.second);
124   }
125 
126   // For each key/value in the map executes function \p F.
127   // If \p F returns false break the iteration.
foreach_conditionalSPIRVMap128   static void foreach_conditional(std::function<bool(const Ty1&, Ty2)>F) {
129     for (auto &I:getMap().Map) {
130       if (!F(I.first, I.second))
131         break;
132     }
133   }
134 
135   static bool find(Ty1 Key, Ty2 *Val = nullptr) {
136     const SPIRVMap& Map = getMap();
137     typename MapTy::const_iterator Loc = Map.Map.find(Key);
138     if(Loc == Map.Map.end())
139       return false;
140     if (Val)
141       *Val = Loc->second;
142     return true;
143   }
144 
145   static bool rfind(Ty2 Key, Ty1 *Val = nullptr) {
146     const SPIRVMap& Map = getRMap();
147     typename RevMapTy::const_iterator Loc = Map.RevMap.find(Key);
148     if (Loc == Map.RevMap.end())
149       return false;
150     if (Val)
151       *Val = Loc->second;
152     return true;
153   }
SPIRVMapSPIRVMap154   SPIRVMap():IsReverse(false){}
155 protected:
SPIRVMapSPIRVMap156   SPIRVMap(bool Reverse):IsReverse(Reverse){
157     init();
158   }
159   typedef std::map<Ty1, Ty2> MapTy;
160   typedef std::map<Ty2, Ty1> RevMapTy;
161 
addSPIRVMap162   void add(Ty1 V1, Ty2 V2) {
163     if (IsReverse) {
164       RevMap[V2] = V1;
165       return;
166     }
167     Map[V1] = V2;
168   }
169   MapTy Map;
170   RevMapTy RevMap;
171   bool IsReverse;
172 };
173 
174 inline std::vector<std::string>
getVec(const std::string & S,char Delim)175 getVec(const std::string &S, char Delim) {
176   std::vector<std::string> Strs;
177   std::stringstream SS(S);
178   std::string Item;
179   while (std::getline(SS, Item, Delim))
180     Strs.push_back(Item);
181   return Strs;
182 }
183 
184 inline std::unordered_set<std::string>
185 getUnordSet(const std::string &S, char Delim = ' ') {
186   std::unordered_set<std::string> Strs;
187   std::stringstream SS(S);
188   std::string Item;
189   while (std::getline(SS, Item, Delim))
190     Strs.insert(Item);
191   return Strs;
192 }
193 
194 inline std::set<std::string>
195 getSet(const std::string &S, char Delim = ' ') {
196   std::set<std::string> Strs;
197   std::stringstream SS(S);
198   std::string Item;
199   while (std::getline(SS, Item, Delim))
200     Strs.insert(Item);
201   return Strs;
202 }
203 
204 template<typename VT, typename KT>
map(KT Key)205 VT map(KT Key) {
206   return SPIRVMap<KT, VT>::map(Key);
207 }
208 
209 template<typename KT, typename VT>
rmap(VT V)210 KT rmap(VT V) {
211   return SPIRVMap<KT, VT>::rmap(V);
212 }
213 
214 template<typename VT, typename KT>
215 std::unordered_set<VT>
map(const std::unordered_set<KT> & KSet)216 map(const std::unordered_set<KT> &KSet) {
217   VT V;
218   std::unordered_set<VT> VSet;
219   for (auto &I:KSet)
220     if (SPIRVMap<KT, VT>::find(I, &V))
221       VSet.insert(V);
222   return VSet;
223 }
224 
225 template<typename VT, typename KT>
226 std::set<VT>
map(const std::set<KT> & KSet)227 map(const std::set<KT> &KSet) {
228   VT V;
229   std::set<VT> VSet;
230   for (auto &I:KSet)
231     if (SPIRVMap<KT, VT>::find(I, &V))
232       VSet.insert(V);
233   return VSet;
234 }
235 
236 template<typename KT, typename VT>
237 std::unordered_set<KT>
rmap(const std::unordered_set<VT> & KSet)238 rmap(const std::unordered_set<VT> &KSet) {
239   KT V;
240   std::unordered_set<KT> VSet;
241   for (auto &I:KSet)
242     if (SPIRVMap<KT, VT>::rfind(I, &V))
243       VSet.insert(V);
244   return VSet;
245 }
246 
247 template<typename KT, typename VT>
248 std::set<KT>
rmap(const std::set<VT> & KSet)249 rmap(const std::set<VT> &KSet) {
250   KT V;
251   std::set<KT> VSet;
252   for (auto &I:KSet)
253     if (SPIRVMap<KT, VT>::rfind(I, &V))
254       VSet.insert(V);
255   return VSet;
256 }
257 
258 template<typename KT, typename VT, typename Any>
259 std::set<KT>
rmap(const std::map<VT,Any> & KMap)260 rmap(const std::map<VT, Any>& KMap) {
261   KT V;
262   std::set<KT> VSet;
263   for (auto &I : KMap)
264     if (SPIRVMap<KT, VT>::rfind(I.first, &V))
265       VSet.insert(V);
266 
267   return VSet;
268 }
269 
270 template<typename K>
271 std::string
getName(K Key)272 getName(K Key) {
273   std::string Name;
274   if (SPIRVMap<K, std::string>::find(Key, &Name))
275     return Name;
276   return "";
277 }
278 
279 template<typename K>
getByName(const std::string & Name,K & Key)280 bool getByName(const std::string &Name, K &Key) {
281   return SPIRVMap<K, std::string>::rfind(Name, &Key);
282 }
283 
284 // Add a number as a string to a string
285 template<class T>
286 std::string
concat(const std::string & s,const T & n)287 concat(const std::string& s, const T& n) {
288   std::stringstream ss;
289   ss << s << n;
290   return ss.str();
291 }
292 
293 inline std::string
294 concat(const std::string &S1, const std::string &S2, char Delim = ' ') {
295   std::string S;
296   if (S1.empty())
297     S = S2;
298   else if (!S2.empty())
299     S = S1 + Delim + S2;
300   return S;
301 }
302 
303 inline std::string
304 operator+(const std::string& s, int n) {
305   return concat(s, n);
306 }
307 
308 inline std::string
309 operator+(const std::string& s, unsigned n) {
310   return concat(s, n);
311 }
312 
313 template<typename T>
314 std::string
315 getStr(const T &C, char Delim = ' ') {
316   std::stringstream SS;
317   bool First = true;
318   for (auto &I:C) {
319     if (!First)
320       SS << Delim;
321     else
322       First = false;
323     SS << I;
324   }
325   return SS.str();
326 }
327 
328 template<class MapTy>
mapBitMask(unsigned BM)329 unsigned mapBitMask(unsigned BM) {
330   unsigned Res = 0;
331   MapTy::foreach([&](typename MapTy::KeyTy K, typename MapTy::ValueTy V){
332     Res |= BM & (unsigned)K ? (unsigned)V : 0;
333   });
334   return Res;
335 }
336 
337 template<class MapTy>
rmapBitMask(unsigned BM)338 unsigned rmapBitMask(unsigned BM) {
339   unsigned Res = 0;
340   MapTy::foreach([&](typename MapTy::KeyTy K, typename MapTy::ValueTy V){
341     Res |= BM & (unsigned)V ? (unsigned)K : 0;
342   });
343   return Res;
344 }
345 
346 // Get the number of words used for encoding a string literal in SPIRV
347 inline unsigned
getSizeInWords(const std::string & Str)348 getSizeInWords(const std::string& Str) {
349   assert(Str.length()/4 + 1 <= std::numeric_limits<unsigned>::max());
350   return static_cast<unsigned>(Str.length()/4 + 1);
351 }
352 
353 inline std::string
getString(std::vector<uint32_t>::const_iterator Begin,std::vector<uint32_t>::const_iterator End)354 getString(std::vector<uint32_t>::const_iterator Begin,
355     std::vector<uint32_t>::const_iterator End) {
356   std::string Str = std::string();
357   for (auto I = Begin; I != End; ++I) {
358     uint32_t Word = *I;
359     for (unsigned J = 0u; J < 32u; J += 8u) {
360       char Char = (char)((Word >> J) & 0xff);
361       if (Char == '\0')
362         return Str;
363       Str += Char;
364     }
365   }
366   return Str;
367 }
368 
369 inline std::string
getString(const std::vector<uint32_t> & V)370 getString(const std::vector<uint32_t> &V) {
371   return getString(V.cbegin(), V.cend());
372 }
373 
374 inline std::vector<uint32_t>
getVec(const std::string & Str)375 getVec(const std::string &Str) {
376   std::vector<uint32_t> V;
377   auto StrSize = Str.size();
378   uint32_t CurrentWord = 0u;
379   for (unsigned I = 0u; I < StrSize; ++I) {
380     if (I % 4u == 0u && I != 0u) {
381       V.push_back(CurrentWord);
382       CurrentWord = 0u;
383     }
384     assert(Str[I] && "0 is not allowed in string");
385     CurrentWord += ((uint32_t)Str[I]) << ((I % 4u) * 8u);
386   }
387   if (CurrentWord != 0u)
388     V.push_back(CurrentWord);
389   if (StrSize % 4 == 0)
390     V.push_back(0);
391   return V;
392 }
393 
394 template<typename T>
395 inline std::vector<T>
getVec(T Op1)396 getVec(T Op1) {
397   std::vector<T> V;
398   V.push_back(Op1);
399   return V;
400 }
401 
402 template<typename T>
403 inline std::vector<T>
getVec(T Op1,T Op2)404 getVec(T Op1, T Op2) {
405   std::vector<T> V;
406   V.push_back(Op1);
407   V.push_back(Op2);
408   return V;
409 }
410 
411 template<typename T>
412 inline std::vector<T>
getVec(T Op1,T Op2,T Op3)413 getVec(T Op1, T Op2, T Op3) {
414   std::vector<T> V;
415   V.push_back(Op1);
416   V.push_back(Op2);
417   V.push_back(Op3);
418   return V;
419 }
420 
421 template<typename T>
422 inline std::vector<T>
getVec(T Op1,const std::vector<T> & Ops2)423 getVec(T Op1, const std::vector<T> &Ops2) {
424   std::vector<T> V;
425   V.push_back(Op1);
426   V.insert(V.end(), Ops2.begin(), Ops2.end());
427   return V;
428 }
429 
430 template<typename MapTy, typename FuncTy>
431 typename MapTy::mapped_type
getOrInsert(MapTy & Map,typename MapTy::key_type Key,FuncTy Func)432 getOrInsert(
433     MapTy &Map,
434     typename MapTy::key_type Key,
435     FuncTy Func){
436   typename MapTy::iterator Loc = Map.find(Key);
437   if (Loc != Map.end())
438     return Loc->second;
439   typename MapTy::mapped_type  NF = Func();
440   Map[Key] = NF;
441   return NF;
442 }
443 
444 }
445 
446 #endif /* SPIRVUTIL_HPP_ */
447