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 \".
writeQuotedString(spv_ostream & O,const std::string & Str)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 ".
readQuotedString(std::istream & IS,std::string & Str)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
SPIRVDecoder(std::istream & InputStream,SPIRVFunction & F)86 SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVFunction &F)
87 :IS(InputStream), M(*F.getModule()), WordCount(0), OpCode(OpNop),
88 Scope(&F){}
89
SPIRVDecoder(std::istream & InputStream,SPIRVBasicBlock & BB)90 SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVBasicBlock &BB)
91 :IS(InputStream), M(*BB.getModule()), WordCount(0), OpCode(OpNop),
92 Scope(&BB){}
93
94 void
setScope(SPIRVEntry * TheScope)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&
decode(const SPIRVDecoder & I,T & V)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&
encode(const SPIRVEncoder & O,T V)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)
SPIRV_DEF_ENCDEC(Capability)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&
operator <<(const SPIRVEncoder & O,const std::string & Str)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
getWordCountAndOpCode()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 *
getEntry()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
validate() const251 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 &
operator <<(spv_ostream & O,const SPIRVNL & E)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