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 89 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 97 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 105 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 113 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 121 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. 128 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 } 154 SPIRVMap():IsReverse(false){} 155 protected: 156 SPIRVMap(bool Reverse):IsReverse(Reverse){ 157 init(); 158 } 159 typedef std::map<Ty1, Ty2> MapTy; 160 typedef std::map<Ty2, Ty1> RevMapTy; 161 162 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> 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> 205 VT map(KT Key) { 206 return SPIRVMap<KT, VT>::map(Key); 207 } 208 209 template<typename KT, typename VT> 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> 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> 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> 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> 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> 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 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> 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 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> 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> 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 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 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 370 getString(const std::vector<uint32_t> &V) { 371 return getString(V.cbegin(), V.cend()); 372 } 373 374 inline std::vector<uint32_t> 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> 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> 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> 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> 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 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