446 lines
11 KiB
C++
446 lines
11 KiB
C++
//===- 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_ */
|