Home | History | Annotate | Download | only in libSPIRV
      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