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