blob: ac1c478c09c549ffe39fe538cf3575ff69f31fad [file] [log] [blame]
//===- 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