//===- SPIRVUtil.h - SPIR-V Utility Functions --------------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines SPIR-V utility functions. /// //===----------------------------------------------------------------------===// #ifndef SPIRVUTIL_H_ #define SPIRVUTIL_H_ #ifdef _SPIRV_LLVM_API #include "llvm/Support/raw_ostream.h" #define spv_ostream llvm::raw_ostream #else #include <ostream> #define spv_ostream std::ostream #endif #include <algorithm> #include <cassert> #include <cstdint> #include <functional> #include <limits> #include <map> #include <set> #include <sstream> #include <string> #include <unordered_set> #include <vector> // MSVC supports "magic statics" since MSVS 2015. // For the previous version of MSVS we should guard // initialization of local static variables. #if defined (_MSC_VER) && (_MSC_VER < 1900) #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" #endif // LLVM_MSC_PREREQ(1900) namespace SPIRV{ #if defined (_MSC_VER) && (_MSC_VER < 1900) static llvm::sys::Mutex MapLock; #endif // LLVM_MSC_PREREQ(1900) #define SPIRV_DEF_NAMEMAP(Type,MapType) \ typedef SPIRVMap<Type, std::string> MapType; \ inline MapType getNameMap(Type){ MapType MT; return MT;} // A bi-way map template<class Ty1, class Ty2, class Identifier = void> struct SPIRVMap { public: typedef Ty1 KeyTy; typedef Ty2 ValueTy; // Initialize map entries void init(); static Ty2 map(Ty1 Key) { Ty2 Val; bool Found = find(Key, &Val); (void) Found; assert (Found && "Invalid key"); return Val; } static Ty1 rmap(Ty2 Key) { Ty1 Val; bool Found = rfind(Key, &Val); (void) Found; assert (Found && "Invalid key"); return Val; } static const SPIRVMap& getMap() { #if defined (_MSC_VER) && (_MSC_VER < 1900) llvm::sys::ScopedLock mapGuard(MapLock); #endif // LLVM_MSC_PREREQ(1900) static const SPIRVMap Map(false); return Map; } static const SPIRVMap& getRMap() { #if defined (_MSC_VER) && (_MSC_VER < 1900) llvm::sys::ScopedLock mapGuard(MapLock); #endif // LLVM_MSC_PREREQ(1900) static const SPIRVMap Map(true); return Map; } static void foreach(std::function<void(Ty1, Ty2)>F) { for (auto &I:getMap().Map) F(I.first, I.second); } // For each key/value in the map executes function \p F. // If \p F returns false break the iteration. static void foreach_conditional(std::function<bool(const Ty1&, Ty2)>F) { for (auto &I:getMap().Map) { if (!F(I.first, I.second)) break; } } static bool find(Ty1 Key, Ty2 *Val = nullptr) { const SPIRVMap& Map = getMap(); typename MapTy::const_iterator Loc = Map.Map.find(Key); if(Loc == Map.Map.end()) return false; if (Val) *Val = Loc->second; return true; } static bool rfind(Ty2 Key, Ty1 *Val = nullptr) { const SPIRVMap& Map = getRMap(); typename RevMapTy::const_iterator Loc = Map.RevMap.find(Key); if (Loc == Map.RevMap.end()) return false; if (Val) *Val = Loc->second; return true; } SPIRVMap():IsReverse(false){} protected: SPIRVMap(bool Reverse):IsReverse(Reverse){ init(); } typedef std::map<Ty1, Ty2> MapTy; typedef std::map<Ty2, Ty1> RevMapTy; void add(Ty1 V1, Ty2 V2) { if (IsReverse) { RevMap[V2] = V1; return; } Map[V1] = V2; } MapTy Map; RevMapTy RevMap; bool IsReverse; }; inline std::vector<std::string> getVec(const std::string &S, char Delim) { std::vector<std::string> Strs; std::stringstream SS(S); std::string Item; while (std::getline(SS, Item, Delim)) Strs.push_back(Item); return Strs; } inline std::unordered_set<std::string> getUnordSet(const std::string &S, char Delim = ' ') { std::unordered_set<std::string> Strs; std::stringstream SS(S); std::string Item; while (std::getline(SS, Item, Delim)) Strs.insert(Item); return Strs; } inline std::set<std::string> getSet(const std::string &S, char Delim = ' ') { std::set<std::string> Strs; std::stringstream SS(S); std::string Item; while (std::getline(SS, Item, Delim)) Strs.insert(Item); return Strs; } template<typename VT, typename KT> VT map(KT Key) { return SPIRVMap<KT, VT>::map(Key); } template<typename KT, typename VT> KT rmap(VT V) { return SPIRVMap<KT, VT>::rmap(V); } template<typename VT, typename KT> std::unordered_set<VT> map(const std::unordered_set<KT> &KSet) { VT V; std::unordered_set<VT> VSet; for (auto &I:KSet) if (SPIRVMap<KT, VT>::find(I, &V)) VSet.insert(V); return VSet; } template<typename VT, typename KT> std::set<VT> map(const std::set<KT> &KSet) { VT V; std::set<VT> VSet; for (auto &I:KSet) if (SPIRVMap<KT, VT>::find(I, &V)) VSet.insert(V); return VSet; } template<typename KT, typename VT> std::unordered_set<KT> rmap(const std::unordered_set<VT> &KSet) { KT V; std::unordered_set<KT> VSet; for (auto &I:KSet) if (SPIRVMap<KT, VT>::rfind(I, &V)) VSet.insert(V); return VSet; } template<typename KT, typename VT> std::set<KT> rmap(const std::set<VT> &KSet) { KT V; std::set<KT> VSet; for (auto &I:KSet) if (SPIRVMap<KT, VT>::rfind(I, &V)) VSet.insert(V); return VSet; } template<typename KT, typename VT, typename Any> std::set<KT> rmap(const std::map<VT, Any>& KMap) { KT V; std::set<KT> VSet; for (auto &I : KMap) if (SPIRVMap<KT, VT>::rfind(I.first, &V)) VSet.insert(V); return VSet; } template<typename K> std::string getName(K Key) { std::string Name; if (SPIRVMap<K, std::string>::find(Key, &Name)) return Name; return ""; } template<typename K> bool getByName(const std::string &Name, K &Key) { return SPIRVMap<K, std::string>::rfind(Name, &Key); } // Add a number as a string to a string template<class T> std::string concat(const std::string& s, const T& n) { std::stringstream ss; ss << s << n; return ss.str(); } inline std::string concat(const std::string &S1, const std::string &S2, char Delim = ' ') { std::string S; if (S1.empty()) S = S2; else if (!S2.empty()) S = S1 + Delim + S2; return S; } inline std::string operator+(const std::string& s, int n) { return concat(s, n); } inline std::string operator+(const std::string& s, unsigned n) { return concat(s, n); } template<typename T> std::string getStr(const T &C, char Delim = ' ') { std::stringstream SS; bool First = true; for (auto &I:C) { if (!First) SS << Delim; else First = false; SS << I; } return SS.str(); } template<class MapTy> unsigned mapBitMask(unsigned BM) { unsigned Res = 0; MapTy::foreach([&](typename MapTy::KeyTy K, typename MapTy::ValueTy V){ Res |= BM & (unsigned)K ? (unsigned)V : 0; }); return Res; } template<class MapTy> unsigned rmapBitMask(unsigned BM) { unsigned Res = 0; MapTy::foreach([&](typename MapTy::KeyTy K, typename MapTy::ValueTy V){ Res |= BM & (unsigned)V ? (unsigned)K : 0; }); return Res; } // Get the number of words used for encoding a string literal in SPIRV inline unsigned getSizeInWords(const std::string& Str) { assert(Str.length()/4 + 1 <= std::numeric_limits<unsigned>::max()); return static_cast<unsigned>(Str.length()/4 + 1); } inline std::string getString(std::vector<uint32_t>::const_iterator Begin, std::vector<uint32_t>::const_iterator End) { std::string Str = std::string(); for (auto I = Begin; I != End; ++I) { uint32_t Word = *I; for (unsigned J = 0u; J < 32u; J += 8u) { char Char = (char)((Word >> J) & 0xff); if (Char == '\0') return Str; Str += Char; } } return Str; } inline std::string getString(const std::vector<uint32_t> &V) { return getString(V.cbegin(), V.cend()); } inline std::vector<uint32_t> getVec(const std::string &Str) { std::vector<uint32_t> V; auto StrSize = Str.size(); uint32_t CurrentWord = 0u; for (unsigned I = 0u; I < StrSize; ++I) { if (I % 4u == 0u && I != 0u) { V.push_back(CurrentWord); CurrentWord = 0u; } assert(Str[I] && "0 is not allowed in string"); CurrentWord += ((uint32_t)Str[I]) << ((I % 4u) * 8u); } if (CurrentWord != 0u) V.push_back(CurrentWord); if (StrSize % 4 == 0) V.push_back(0); return V; } template<typename T> inline std::vector<T> getVec(T Op1) { std::vector<T> V; V.push_back(Op1); return V; } template<typename T> inline std::vector<T> getVec(T Op1, T Op2) { std::vector<T> V; V.push_back(Op1); V.push_back(Op2); return V; } template<typename T> inline std::vector<T> getVec(T Op1, T Op2, T Op3) { std::vector<T> V; V.push_back(Op1); V.push_back(Op2); V.push_back(Op3); return V; } template<typename T> inline std::vector<T> getVec(T Op1, const std::vector<T> &Ops2) { std::vector<T> V; V.push_back(Op1); V.insert(V.end(), Ops2.begin(), Ops2.end()); return V; } template<typename MapTy, typename FuncTy> typename MapTy::mapped_type getOrInsert( MapTy &Map, typename MapTy::key_type Key, FuncTy Func){ typename MapTy::iterator Loc = Map.find(Key); if (Loc != Map.end()) return Loc->second; typename MapTy::mapped_type NF = Func(); Map[Key] = NF; return NF; } } #endif /* SPIRVUTIL_HPP_ */