267 lines
7.3 KiB
C++
267 lines
7.3 KiB
C++
//===- SPIRVStream.cpp – Class to represent a SPIR-V Stream ------*- 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 implements SPIR-V stream class.
|
||
///
|
||
//===----------------------------------------------------------------------===//
|
||
#include "SPIRVDebug.h"
|
||
#include "SPIRVStream.h"
|
||
#include "SPIRVFunction.h"
|
||
#include "SPIRVOpCode.h"
|
||
#include "SPIRVNameMapEnum.h"
|
||
|
||
namespace SPIRV{
|
||
|
||
/// Write string with quote. Replace " with \".
|
||
static void writeQuotedString(spv_ostream& O, const std::string& Str) {
|
||
O << '"';
|
||
for (auto I : Str) {
|
||
if (I == '"')
|
||
O << '\\';
|
||
O << I;
|
||
}
|
||
O << '"';
|
||
}
|
||
|
||
/// Read quoted string. Replace \" with ".
|
||
static void readQuotedString(std::istream &IS, std::string& Str) {
|
||
char Ch = ' ';
|
||
char PreCh = ' ';
|
||
while (IS >> Ch && Ch != '"')
|
||
;
|
||
|
||
if (IS >> PreCh && PreCh != '"') {
|
||
while (IS >> Ch) {
|
||
if (Ch == '"') {
|
||
if (PreCh != '\\') {
|
||
Str += PreCh;
|
||
break;
|
||
}
|
||
else
|
||
PreCh = Ch;
|
||
} else {
|
||
Str += PreCh;
|
||
PreCh = Ch;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
||
bool SPIRVUseTextFormat = false;
|
||
#endif
|
||
|
||
SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVFunction &F)
|
||
:IS(InputStream), M(*F.getModule()), WordCount(0), OpCode(OpNop),
|
||
Scope(&F){}
|
||
|
||
SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVBasicBlock &BB)
|
||
:IS(InputStream), M(*BB.getModule()), WordCount(0), OpCode(OpNop),
|
||
Scope(&BB){}
|
||
|
||
void
|
||
SPIRVDecoder::setScope(SPIRVEntry *TheScope) {
|
||
assert(TheScope && (TheScope->getOpCode() == OpFunction ||
|
||
TheScope->getOpCode() == OpLabel));
|
||
Scope = TheScope;
|
||
}
|
||
|
||
template<class T>
|
||
const SPIRVDecoder&
|
||
decode(const SPIRVDecoder& I, T &V) {
|
||
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
||
if (SPIRVUseTextFormat) {
|
||
std::string W;
|
||
I.IS >> W;
|
||
V = getNameMap(V).rmap(W);
|
||
SPIRVDBG(spvdbgs() << "Read word: W = " << W << " V = " << V << '\n');
|
||
return I;
|
||
}
|
||
#endif
|
||
return DecodeBinary(I, V);
|
||
}
|
||
|
||
template<class T>
|
||
const SPIRVEncoder&
|
||
encode(const SPIRVEncoder& O, T V) {
|
||
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
||
if (SPIRVUseTextFormat) {
|
||
O.OS << getNameMap(V).map(V) << " ";
|
||
return O;
|
||
}
|
||
#endif
|
||
return O << static_cast<SPIRVWord>(V);
|
||
}
|
||
|
||
#define SPIRV_DEF_ENCDEC(Type) \
|
||
const SPIRVDecoder& \
|
||
operator>>(const SPIRVDecoder& I, Type &V) { \
|
||
return decode(I, V); \
|
||
}\
|
||
const SPIRVEncoder& \
|
||
operator<<(const SPIRVEncoder& O, Type V) { \
|
||
return encode(O, V); \
|
||
}
|
||
|
||
SPIRV_DEF_ENCDEC(Op)
|
||
SPIRV_DEF_ENCDEC(Capability)
|
||
SPIRV_DEF_ENCDEC(Decoration)
|
||
SPIRV_DEF_ENCDEC(OCLExtOpKind)
|
||
SPIRV_DEF_ENCDEC(LinkageType)
|
||
|
||
// Read a string with padded 0's at the end so that they form a stream of
|
||
// words.
|
||
const SPIRVDecoder&
|
||
operator>>(const SPIRVDecoder&I, std::string& Str) {
|
||
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
||
if (SPIRVUseTextFormat) {
|
||
readQuotedString(I.IS, Str);
|
||
SPIRVDBG(spvdbgs() << "Read string: \"" << Str << "\"\n");
|
||
return I;
|
||
}
|
||
#endif
|
||
|
||
uint64_t Count = 0;
|
||
char Ch;
|
||
while (I.IS.get(Ch) && Ch != '\0') {
|
||
Str += Ch;
|
||
++Count;
|
||
}
|
||
Count = (Count + 1) % 4;
|
||
Count = Count ? 4 - Count : 0;
|
||
for (;Count; --Count) {
|
||
I.IS >> Ch;
|
||
assert(Ch == '\0' && "Invalid string in SPIRV");
|
||
}
|
||
SPIRVDBG(spvdbgs() << "Read string: \"" << Str << "\"\n");
|
||
return I;
|
||
}
|
||
|
||
// Write a string with padded 0's at the end so that they form a stream of
|
||
// words.
|
||
const SPIRVEncoder&
|
||
operator<<(const SPIRVEncoder&O, const std::string& Str) {
|
||
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
||
if (SPIRVUseTextFormat) {
|
||
writeQuotedString(O.OS, Str);
|
||
return O;
|
||
}
|
||
#endif
|
||
|
||
size_t L = Str.length();
|
||
O.OS.write(Str.c_str(), L);
|
||
char Zeros[4] = {0, 0, 0, 0};
|
||
O.OS.write(Zeros, 4-L%4);
|
||
return O;
|
||
}
|
||
|
||
bool
|
||
SPIRVDecoder::getWordCountAndOpCode() {
|
||
if (IS.eof()) {
|
||
WordCount = 0;
|
||
OpCode = OpNop;
|
||
SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode EOF " <<
|
||
WordCount << " " << OpCode << '\n');
|
||
return false;
|
||
}
|
||
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
||
if (SPIRVUseTextFormat) {
|
||
*this >> WordCount;
|
||
assert(!IS.bad() && "SPIRV stream is bad");
|
||
if (IS.fail()) {
|
||
WordCount = 0;
|
||
OpCode = OpNop;
|
||
SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode FAIL " <<
|
||
WordCount << " " << OpCode << '\n');
|
||
return false;
|
||
}
|
||
*this >> OpCode;
|
||
} else {
|
||
#endif
|
||
SPIRVWord WordCountAndOpCode;
|
||
*this >> WordCountAndOpCode;
|
||
WordCount = WordCountAndOpCode >> 16;
|
||
OpCode = static_cast<Op>(WordCountAndOpCode & 0xFFFF);
|
||
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
||
}
|
||
#endif
|
||
assert(!IS.bad() && "SPIRV stream is bad");
|
||
if (IS.fail()) {
|
||
WordCount = 0;
|
||
OpCode = OpNop;
|
||
SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode FAIL " <<
|
||
WordCount << " " << OpCode << '\n');
|
||
return false;
|
||
}
|
||
SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode " << WordCount <<
|
||
" " << OpCodeNameMap::map(OpCode) << '\n');
|
||
return true;
|
||
}
|
||
|
||
SPIRVEntry *
|
||
SPIRVDecoder::getEntry() {
|
||
if (WordCount == 0 || OpCode == OpNop)
|
||
return NULL;
|
||
SPIRVEntry *Entry = SPIRVEntry::create(OpCode);
|
||
assert(Entry);
|
||
Entry->setModule(&M);
|
||
if (isModuleScopeAllowedOpCode(OpCode) && !Scope) {}
|
||
else
|
||
Entry->setScope(Scope);
|
||
Entry->setWordCount(WordCount);
|
||
IS >> *Entry;
|
||
assert(!IS.bad() && !IS.fail() && "SPIRV stream fails");
|
||
M.add(Entry);
|
||
return Entry;
|
||
}
|
||
|
||
void
|
||
SPIRVDecoder::validate()const {
|
||
assert(OpCode != OpNop && "Invalid op code");
|
||
assert(WordCount && "Invalid word count");
|
||
assert(!IS.bad() && "Bad iInput stream");
|
||
}
|
||
|
||
spv_ostream &
|
||
operator<<(spv_ostream &O, const SPIRVNL &E) {
|
||
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
||
if (SPIRVUseTextFormat)
|
||
O << '\n';
|
||
#endif
|
||
return O;
|
||
}
|
||
|
||
} // end of SPIRV namespace
|
||
|