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