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