Home | History | Annotate | Download | only in libSPIRV
      1 //===- SPIRVStream.cpp  Class to represent a SPIR-V Stream ------*- 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 implements SPIR-V stream class.
     37 ///
     38 //===----------------------------------------------------------------------===//
     39 #include "SPIRVDebug.h"
     40 #include "SPIRVStream.h"
     41 #include "SPIRVFunction.h"
     42 #include "SPIRVOpCode.h"
     43 #include "SPIRVNameMapEnum.h"
     44 
     45 namespace SPIRV{
     46 
     47 /// Write string with quote. Replace " with \".
     48 static void writeQuotedString(spv_ostream& O, const std::string& Str) {
     49   O << '"';
     50   for (auto I : Str) {
     51     if (I == '"')
     52       O << '\\';
     53     O << I;
     54   }
     55   O << '"';
     56 }
     57 
     58 /// Read quoted string. Replace \" with ".
     59 static void readQuotedString(std::istream &IS, std::string& Str) {
     60   char Ch = ' ';
     61   char PreCh = ' ';
     62   while (IS >> Ch && Ch != '"')
     63     ;
     64 
     65   if (IS >> PreCh && PreCh != '"') {
     66     while (IS >> Ch) {
     67       if (Ch == '"') {
     68         if (PreCh != '\\') {
     69           Str += PreCh;
     70           break;
     71         }
     72         else
     73           PreCh = Ch;
     74       } else {
     75         Str += PreCh;
     76         PreCh = Ch;
     77       }
     78     }
     79   }
     80 }
     81 
     82 #ifdef _SPIRV_SUPPORT_TEXT_FMT
     83 bool SPIRVUseTextFormat = false;
     84 #endif
     85 
     86 SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVFunction &F)
     87   :IS(InputStream), M(*F.getModule()), WordCount(0), OpCode(OpNop),
     88    Scope(&F){}
     89 
     90 SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVBasicBlock &BB)
     91   :IS(InputStream), M(*BB.getModule()), WordCount(0), OpCode(OpNop),
     92    Scope(&BB){}
     93 
     94 void
     95 SPIRVDecoder::setScope(SPIRVEntry *TheScope) {
     96   assert(TheScope && (TheScope->getOpCode() == OpFunction ||
     97       TheScope->getOpCode() == OpLabel));
     98   Scope = TheScope;
     99 }
    100 
    101 template<class T>
    102 const SPIRVDecoder&
    103 decode(const SPIRVDecoder& I, T &V) {
    104 #ifdef _SPIRV_SUPPORT_TEXT_FMT
    105   if (SPIRVUseTextFormat) {
    106     std::string W;
    107     I.IS >> W;
    108     V = getNameMap(V).rmap(W);
    109     SPIRVDBG(spvdbgs() << "Read word: W = " << W << " V = " << V << '\n');
    110     return I;
    111   }
    112 #endif
    113   return DecodeBinary(I, V);
    114 }
    115 
    116 template<class T>
    117 const SPIRVEncoder&
    118 encode(const SPIRVEncoder& O, T V) {
    119 #ifdef _SPIRV_SUPPORT_TEXT_FMT
    120   if (SPIRVUseTextFormat) {
    121     O.OS << getNameMap(V).map(V) << " ";
    122     return O;
    123   }
    124 #endif
    125   return O << static_cast<SPIRVWord>(V);
    126 }
    127 
    128 #define SPIRV_DEF_ENCDEC(Type) \
    129 const SPIRVDecoder& \
    130 operator>>(const SPIRVDecoder& I, Type &V) { \
    131   return decode(I, V); \
    132 }\
    133 const SPIRVEncoder& \
    134 operator<<(const SPIRVEncoder& O, Type V) { \
    135   return encode(O, V); \
    136 }
    137 
    138 SPIRV_DEF_ENCDEC(Op)
    139 SPIRV_DEF_ENCDEC(Capability)
    140 SPIRV_DEF_ENCDEC(Decoration)
    141 SPIRV_DEF_ENCDEC(OCLExtOpKind)
    142 SPIRV_DEF_ENCDEC(LinkageType)
    143 
    144 // Read a string with padded 0's at the end so that they form a stream of
    145 // words.
    146 const SPIRVDecoder&
    147 operator>>(const SPIRVDecoder&I, std::string& Str) {
    148 #ifdef _SPIRV_SUPPORT_TEXT_FMT
    149   if (SPIRVUseTextFormat) {
    150     readQuotedString(I.IS, Str);
    151     SPIRVDBG(spvdbgs() << "Read string: \"" << Str << "\"\n");
    152     return I;
    153   }
    154 #endif
    155 
    156   uint64_t Count = 0;
    157   char Ch;
    158   while (I.IS.get(Ch) && Ch != '\0') {
    159     Str += Ch;
    160     ++Count;
    161   }
    162   Count = (Count + 1) % 4;
    163   Count = Count ? 4 - Count : 0;
    164   for (;Count; --Count) {
    165     I.IS >> Ch;
    166     assert(Ch == '\0' && "Invalid string in SPIRV");
    167   }
    168   SPIRVDBG(spvdbgs() << "Read string: \"" << Str << "\"\n");
    169   return I;
    170 }
    171 
    172 // Write a string with padded 0's at the end so that they form a stream of
    173 // words.
    174 const SPIRVEncoder&
    175 operator<<(const SPIRVEncoder&O, const std::string& Str) {
    176 #ifdef _SPIRV_SUPPORT_TEXT_FMT
    177   if (SPIRVUseTextFormat) {
    178     writeQuotedString(O.OS, Str);
    179     return O;
    180   }
    181 #endif
    182 
    183   size_t L = Str.length();
    184   O.OS.write(Str.c_str(), L);
    185   char Zeros[4] = {0, 0, 0, 0};
    186   O.OS.write(Zeros, 4-L%4);
    187   return O;
    188 }
    189 
    190 bool
    191 SPIRVDecoder::getWordCountAndOpCode() {
    192   if (IS.eof()) {
    193     WordCount = 0;
    194     OpCode = OpNop;
    195     SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode EOF " <<
    196         WordCount << " " << OpCode << '\n');
    197     return false;
    198   }
    199 #ifdef _SPIRV_SUPPORT_TEXT_FMT
    200   if (SPIRVUseTextFormat) {
    201     *this >> WordCount;
    202     assert(!IS.bad() && "SPIRV stream is bad");
    203     if (IS.fail()) {
    204       WordCount = 0;
    205       OpCode = OpNop;
    206       SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode FAIL " <<
    207           WordCount << " " << OpCode << '\n');
    208       return false;
    209     }
    210     *this >> OpCode;
    211   } else {
    212 #endif
    213   SPIRVWord WordCountAndOpCode;
    214   *this >> WordCountAndOpCode;
    215   WordCount = WordCountAndOpCode >> 16;
    216   OpCode = static_cast<Op>(WordCountAndOpCode & 0xFFFF);
    217 #ifdef _SPIRV_SUPPORT_TEXT_FMT
    218   }
    219 #endif
    220   assert(!IS.bad() && "SPIRV stream is bad");
    221   if (IS.fail()) {
    222     WordCount = 0;
    223     OpCode = OpNop;
    224     SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode FAIL " <<
    225         WordCount << " " << OpCode << '\n');
    226     return false;
    227   }
    228   SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode " << WordCount <<
    229       " " << OpCodeNameMap::map(OpCode) << '\n');
    230   return true;
    231 }
    232 
    233 SPIRVEntry *
    234 SPIRVDecoder::getEntry() {
    235   if (WordCount == 0 || OpCode == OpNop)
    236     return NULL;
    237   SPIRVEntry *Entry = SPIRVEntry::create(OpCode);
    238   assert(Entry);
    239   Entry->setModule(&M);
    240   if (isModuleScopeAllowedOpCode(OpCode) && !Scope) {}
    241   else
    242     Entry->setScope(Scope);
    243   Entry->setWordCount(WordCount);
    244   IS >> *Entry;
    245   assert(!IS.bad() && !IS.fail() && "SPIRV stream fails");
    246   M.add(Entry);
    247   return Entry;
    248 }
    249 
    250 void
    251 SPIRVDecoder::validate()const {
    252   assert(OpCode != OpNop && "Invalid op code");
    253   assert(WordCount && "Invalid word count");
    254   assert(!IS.bad() && "Bad iInput stream");
    255 }
    256 
    257 spv_ostream &
    258 operator<<(spv_ostream &O, const SPIRVNL &E) {
    259 #ifdef _SPIRV_SUPPORT_TEXT_FMT
    260   if (SPIRVUseTextFormat)
    261     O << '\n';
    262 #endif
    263   return O;
    264 }
    265 
    266 } // end of SPIRV namespace
    267 
    268