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 71namespace 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) \ 77typedef SPIRVMap<Type, std::string> MapType; \ 78inline MapType getNameMap(Type){ MapType MT; return MT;} 79 80// A bi-way map 81template<class Ty1, class Ty2, class Identifier = void> 82struct SPIRVMap { 83public: 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){} 155protected: 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 174inline std::vector<std::string> 175getVec(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 184inline std::unordered_set<std::string> 185getUnordSet(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 194inline std::set<std::string> 195getSet(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 204template<typename VT, typename KT> 205VT map(KT Key) { 206 return SPIRVMap<KT, VT>::map(Key); 207} 208 209template<typename KT, typename VT> 210KT rmap(VT V) { 211 return SPIRVMap<KT, VT>::rmap(V); 212} 213 214template<typename VT, typename KT> 215std::unordered_set<VT> 216map(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 225template<typename VT, typename KT> 226std::set<VT> 227map(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 236template<typename KT, typename VT> 237std::unordered_set<KT> 238rmap(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 247template<typename KT, typename VT> 248std::set<KT> 249rmap(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 258template<typename KT, typename VT, typename Any> 259std::set<KT> 260rmap(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 270template<typename K> 271std::string 272getName(K Key) { 273 std::string Name; 274 if (SPIRVMap<K, std::string>::find(Key, &Name)) 275 return Name; 276 return ""; 277} 278 279template<typename K> 280bool 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 285template<class T> 286std::string 287concat(const std::string& s, const T& n) { 288 std::stringstream ss; 289 ss << s << n; 290 return ss.str(); 291} 292 293inline std::string 294concat(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 303inline std::string 304operator+(const std::string& s, int n) { 305 return concat(s, n); 306} 307 308inline std::string 309operator+(const std::string& s, unsigned n) { 310 return concat(s, n); 311} 312 313template<typename T> 314std::string 315getStr(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 328template<class MapTy> 329unsigned 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 337template<class MapTy> 338unsigned 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 347inline unsigned 348getSizeInWords(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 353inline std::string 354getString(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 369inline std::string 370getString(const std::vector<uint32_t> &V) { 371 return getString(V.cbegin(), V.cend()); 372} 373 374inline std::vector<uint32_t> 375getVec(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 394template<typename T> 395inline std::vector<T> 396getVec(T Op1) { 397 std::vector<T> V; 398 V.push_back(Op1); 399 return V; 400} 401 402template<typename T> 403inline std::vector<T> 404getVec(T Op1, T Op2) { 405 std::vector<T> V; 406 V.push_back(Op1); 407 V.push_back(Op2); 408 return V; 409} 410 411template<typename T> 412inline std::vector<T> 413getVec(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 421template<typename T> 422inline std::vector<T> 423getVec(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 430template<typename MapTy, typename FuncTy> 431typename MapTy::mapped_type 432getOrInsert( 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