blob: 2a302051067e6b2306c658651744579485516765 [file] [log] [blame]
Dejan Mircevskib6fe02f2016-01-07 13:44:22 -05001// Copyright (c) 2015-2016 The Khronos Group Inc.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -04002//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and/or associated documentation files (the
5// "Materials"), to deal in the Materials without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Materials, and to
8// permit persons to whom the Materials are furnished to do so, subject to
9// the following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Materials.
13//
14// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
15// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
16// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
17// https://www.khronos.org/registry/
18//
19// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
26
27#include "text_handler.h"
28
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040029#include <cassert>
David Neto78e677b2015-10-05 13:28:46 -040030#include <cstdlib>
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040031#include <cstring>
Andrew Woloszyn537e7762015-09-29 11:28:34 -040032#include <tuple>
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040033
David Netofcc7d582015-10-27 15:31:10 -040034#include "assembly_grammar.h"
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040035#include "binary.h"
36#include "ext_inst.h"
David Netob5dc8fc2015-10-06 16:22:00 -040037#include "instruction.h"
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040038#include "opcode.h"
39#include "text.h"
Andrew Woloszynf731cbf2015-10-23 09:53:58 -040040#include "util/bitutils.h"
David Neto9e545d72015-11-06 18:08:49 -050041#include "util/hex_float.h"
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040042
43namespace {
44
David Neto78e677b2015-10-05 13:28:46 -040045using spvutils::BitwiseCast;
David Neto9e545d72015-11-06 18:08:49 -050046using spvutils::FloatProxy;
47using spvutils::HexFloat;
David Neto78e677b2015-10-05 13:28:46 -040048
Lei Zhangf2cf7192016-04-21 15:50:23 -040049// Advances |text| to the start of the next line and writes the new position to
50// |position|.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040051spv_result_t advanceLine(spv_text text, spv_position position) {
52 while (true) {
Lei Zhangf2cf7192016-04-21 15:50:23 -040053 if (position->index >= text->length) return SPV_END_OF_STREAM;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040054 switch (text->str[position->index]) {
55 case '\0':
56 return SPV_END_OF_STREAM;
57 case '\n':
58 position->column = 0;
59 position->line++;
60 position->index++;
61 return SPV_SUCCESS;
62 default:
63 position->column++;
64 position->index++;
65 break;
66 }
67 }
68}
69
Lei Zhangf2cf7192016-04-21 15:50:23 -040070// Advances |text| to first non white space character and writes the new
71// position to |position|.
72// If a null terminator is found during the text advance, SPV_END_OF_STREAM is
73// returned, SPV_SUCCESS otherwise. No error checking is performed on the
74// parameters, its the users responsibility to ensure these are non null.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040075spv_result_t advance(spv_text text, spv_position position) {
76 // NOTE: Consume white space, otherwise don't advance.
Lei Zhang8f6ba142015-11-06 15:09:04 -050077 if (position->index >= text->length) return SPV_END_OF_STREAM;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040078 switch (text->str[position->index]) {
79 case '\0':
80 return SPV_END_OF_STREAM;
81 case ';':
82 if (spv_result_t error = advanceLine(text, position)) return error;
83 return advance(text, position);
84 case ' ':
85 case '\t':
Dejan Mircevskia1de2b32016-04-01 00:47:02 -040086 case '\r':
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040087 position->column++;
88 position->index++;
89 return advance(text, position);
90 case '\n':
91 position->column = 0;
92 position->line++;
93 position->index++;
94 return advance(text, position);
95 default:
96 break;
97 }
98 return SPV_SUCCESS;
99}
100
Lei Zhang6032b982016-03-15 16:52:40 -0400101// Fetches the next word from the given text stream starting from the given
102// *position. On success, writes the decoded word into *word and updates
103// *position to the location past the returned word.
104//
105// A word ends at the next comment or whitespace. However, double-quoted
106// strings remain intact, and a backslash always escapes the next character.
107spv_result_t getWord(spv_text text, spv_position position, std::string* word) {
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400108 if (!text->str || !text->length) return SPV_ERROR_INVALID_TEXT;
Lei Zhang6032b982016-03-15 16:52:40 -0400109 if (!position) return SPV_ERROR_INVALID_POINTER;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400110
Lei Zhang6032b982016-03-15 16:52:40 -0400111 const size_t start_index = position->index;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400112
113 bool quoting = false;
114 bool escaping = false;
115
116 // NOTE: Assumes first character is not white space!
117 while (true) {
Lei Zhang6032b982016-03-15 16:52:40 -0400118 if (position->index >= text->length) {
119 word->assign(text->str + start_index, text->str + position->index);
Lei Zhang9413fbb2016-02-22 17:17:25 -0500120 return SPV_SUCCESS;
121 }
Lei Zhang6032b982016-03-15 16:52:40 -0400122 const char ch = text->str[position->index];
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400123 if (ch == '\\')
124 escaping = !escaping;
125 else {
126 switch (ch) {
127 case '"':
128 if (!escaping) quoting = !quoting;
129 break;
130 case ' ':
131 case ';':
132 case '\t':
133 case '\n':
Dejan Mircevskia1de2b32016-04-01 00:47:02 -0400134 case '\r':
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400135 if (escaping || quoting) break;
136 // Fall through.
137 case '\0': { // NOTE: End of word found!
Lei Zhang6032b982016-03-15 16:52:40 -0400138 word->assign(text->str + start_index, text->str + position->index);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400139 return SPV_SUCCESS;
140 }
141 default:
142 break;
143 }
144 escaping = false;
145 }
146
Lei Zhang6032b982016-03-15 16:52:40 -0400147 position->column++;
148 position->index++;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400149 }
150}
151
152// Returns true if the characters in the text as position represent
153// the start of an Opcode.
154bool startsWithOp(spv_text text, spv_position position) {
155 if (text->length < position->index + 3) return false;
156 char ch0 = text->str[position->index];
157 char ch1 = text->str[position->index + 1];
158 char ch2 = text->str[position->index + 2];
159 return ('O' == ch0 && 'p' == ch1 && ('A' <= ch2 && ch2 <= 'Z'));
160}
161
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400162} // anonymous namespace
163
164namespace libspirv {
165
David Neto78e677b2015-10-05 13:28:46 -0400166const IdType kUnknownType = {0, false, IdTypeClass::kBottom};
167
David Neto78e677b2015-10-05 13:28:46 -0400168// TODO(dneto): Reorder AssemblyContext definitions to match declaration order.
169
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400170// This represents all of the data that is only valid for the duration of
171// a single compilation.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500172uint32_t AssemblyContext::spvNamedIdAssignOrGet(const char* textValue) {
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400173 if (named_ids_.end() == named_ids_.find(textValue)) {
174 named_ids_[std::string(textValue)] = bound_++;
175 }
176 return named_ids_[textValue];
177}
178uint32_t AssemblyContext::getBound() const { return bound_; }
179
180spv_result_t AssemblyContext::advance() {
181 return ::advance(text_, &current_position_);
182}
183
Lei Zhang6032b982016-03-15 16:52:40 -0400184spv_result_t AssemblyContext::getWord(std::string* word,
185 spv_position next_position) {
186 *next_position = current_position_;
187 return ::getWord(text_, next_position, word);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400188}
189
190bool AssemblyContext::startsWithOp() {
191 return ::startsWithOp(text_, &current_position_);
192}
193
194bool AssemblyContext::isStartOfNewInst() {
Lei Zhang6032b982016-03-15 16:52:40 -0400195 spv_position_t pos = current_position_;
196 if (::advance(text_, &pos)) return false;
197 if (::startsWithOp(text_, &pos)) return true;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400198
199 std::string word;
Lei Zhang6032b982016-03-15 16:52:40 -0400200 pos = current_position_;
201 if (::getWord(text_, &pos, &word)) return false;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400202 if ('%' != word.front()) return false;
203
Lei Zhang6032b982016-03-15 16:52:40 -0400204 if (::advance(text_, &pos)) return false;
205 if (::getWord(text_, &pos, &word)) return false;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400206 if ("=" != word) return false;
207
Lei Zhang6032b982016-03-15 16:52:40 -0400208 if (::advance(text_, &pos)) return false;
209 if (::startsWithOp(text_, &pos)) return true;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400210 return false;
211}
Andrew Woloszyn4274f932015-10-20 09:12:32 -0400212
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400213char AssemblyContext::peek() const {
214 return text_->str[current_position_.index];
215}
216
217bool AssemblyContext::hasText() const {
218 return text_->length > current_position_.index;
219}
Andrew Woloszyn4274f932015-10-20 09:12:32 -0400220
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400221void AssemblyContext::seekForward(uint32_t size) {
222 current_position_.index += size;
223 current_position_.column += size;
224}
225
226spv_result_t AssemblyContext::binaryEncodeU32(const uint32_t value,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500227 spv_instruction_t* pInst) {
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500228 pInst->words.insert(pInst->words.end(), value);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400229 return SPV_SUCCESS;
230}
231
232spv_result_t AssemblyContext::binaryEncodeU64(const uint64_t value,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500233 spv_instruction_t* pInst) {
David Neto78e677b2015-10-05 13:28:46 -0400234 uint32_t low = uint32_t(0x00000000ffffffff & value);
235 uint32_t high = uint32_t((0xffffffff00000000 & value) >> 32);
David Netoac508b02015-10-09 15:48:09 -0400236 binaryEncodeU32(low, pInst);
237 binaryEncodeU32(high, pInst);
238 return SPV_SUCCESS;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400239}
240
David Neto78e677b2015-10-05 13:28:46 -0400241spv_result_t AssemblyContext::binaryEncodeNumericLiteral(
Lei Zhang1a0334e2015-11-02 09:41:20 -0500242 const char* val, spv_result_t error_code, const IdType& type,
243 spv_instruction_t* pInst) {
David Neto78e677b2015-10-05 13:28:46 -0400244 const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
245 const bool is_floating = libspirv::isScalarFloating(type);
246 const bool is_integer = libspirv::isScalarIntegral(type);
247
248 if (!is_bottom && !is_floating && !is_integer) {
249 return diagnostic(SPV_ERROR_INTERNAL)
250 << "The expected type is not a scalar integer or float type";
251 }
252
253 // If this is bottom, but looks like a float, we should treat it like a
254 // float.
255 const bool looks_like_float = is_bottom && strchr(val, '.');
256
257 // If we explicitly expect a floating-point number, we should handle that
258 // first.
259 if (is_floating || looks_like_float)
David Neto51013d12015-10-14 11:31:51 -0400260 return binaryEncodeFloatingPointLiteral(val, error_code, type, pInst);
David Neto78e677b2015-10-05 13:28:46 -0400261
David Neto51013d12015-10-14 11:31:51 -0400262 return binaryEncodeIntegerLiteral(val, error_code, type, pInst);
David Neto78e677b2015-10-05 13:28:46 -0400263}
264
Lei Zhang1a0334e2015-11-02 09:41:20 -0500265spv_result_t AssemblyContext::binaryEncodeString(const char* value,
266 spv_instruction_t* pInst) {
David Netob5dc8fc2015-10-06 16:22:00 -0400267 const size_t length = strlen(value);
268 const size_t wordCount = (length / 4) + 1;
269 const size_t oldWordCount = pInst->words.size();
270 const size_t newWordCount = oldWordCount + wordCount;
271
272 // TODO(dneto): We can just defer this check until later.
273 if (newWordCount > SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX) {
David Neto78e677b2015-10-05 13:28:46 -0400274 return diagnostic() << "Instruction too long: more than "
275 << SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << " words.";
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400276 }
277
David Netob5dc8fc2015-10-06 16:22:00 -0400278 pInst->words.resize(newWordCount);
279
280 // Make sure all the bytes in the last word are 0, in case we only
281 // write a partial word at the end.
282 pInst->words.back() = 0;
283
Lei Zhang1a0334e2015-11-02 09:41:20 -0500284 char* dest = (char*)&pInst->words[oldWordCount];
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400285 strncpy(dest, value, length);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400286
287 return SPV_SUCCESS;
288}
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400289
290spv_result_t AssemblyContext::recordTypeDefinition(
Lei Zhang1a0334e2015-11-02 09:41:20 -0500291 const spv_instruction_t* pInst) {
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400292 uint32_t value = pInst->words[1];
293 if (types_.find(value) != types_.end()) {
Lei Zhang1a0334e2015-11-02 09:41:20 -0500294 return diagnostic() << "Value " << value
295 << " has already been used to generate a type";
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400296 }
297
Lei Zhangb36e7042015-10-28 13:40:52 -0400298 if (pInst->opcode == SpvOpTypeInt) {
David Neto78e677b2015-10-05 13:28:46 -0400299 if (pInst->words.size() != 4)
300 return diagnostic() << "Invalid OpTypeInt instruction";
301 types_[value] = {pInst->words[2], pInst->words[3] != 0,
302 IdTypeClass::kScalarIntegerType};
Lei Zhangb36e7042015-10-28 13:40:52 -0400303 } else if (pInst->opcode == SpvOpTypeFloat) {
David Neto78e677b2015-10-05 13:28:46 -0400304 if (pInst->words.size() != 3)
305 return diagnostic() << "Invalid OpTypeFloat instruction";
306 types_[value] = {pInst->words[2], false, IdTypeClass::kScalarFloatType};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400307 } else {
David Neto78e677b2015-10-05 13:28:46 -0400308 types_[value] = {0, false, IdTypeClass::kOtherType};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400309 }
310 return SPV_SUCCESS;
311}
312
313IdType AssemblyContext::getTypeOfTypeGeneratingValue(uint32_t value) const {
314 auto type = types_.find(value);
315 if (type == types_.end()) {
David Neto78e677b2015-10-05 13:28:46 -0400316 return kUnknownType;
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400317 }
318 return std::get<1>(*type);
319}
320
321IdType AssemblyContext::getTypeOfValueInstruction(uint32_t value) const {
322 auto type_value = value_types_.find(value);
323 if (type_value == value_types_.end()) {
Lei Zhang1a0334e2015-11-02 09:41:20 -0500324 return {0, false, IdTypeClass::kBottom};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400325 }
326 return getTypeOfTypeGeneratingValue(std::get<1>(*type_value));
327}
328
329spv_result_t AssemblyContext::recordTypeIdForValue(uint32_t value,
330 uint32_t type) {
331 bool successfully_inserted = false;
332 std::tie(std::ignore, successfully_inserted) =
333 value_types_.insert(std::make_pair(value, type));
David Neto78e677b2015-10-05 13:28:46 -0400334 if (!successfully_inserted)
335 return diagnostic() << "Value is being defined a second time";
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400336 return SPV_SUCCESS;
337}
338
David Neto2ae4a682015-11-09 18:55:42 -0500339spv_result_t AssemblyContext::recordIdAsExtInstImport(
340 uint32_t id, spv_ext_inst_type_t type) {
341 bool successfully_inserted = false;
342 std::tie(std::ignore, successfully_inserted) =
343 import_id_to_ext_inst_type_.insert(std::make_pair(id, type));
344 if (!successfully_inserted)
345 return diagnostic() << "Import Id is being defined a second time";
346 return SPV_SUCCESS;
347}
348
349spv_ext_inst_type_t AssemblyContext::getExtInstTypeForId(uint32_t id) const {
350 auto type = import_id_to_ext_inst_type_.find(id);
351 if (type == import_id_to_ext_inst_type_.end()) {
352 return SPV_EXT_INST_TYPE_NONE;
353 }
354 return std::get<1>(*type);
355}
356
David Neto78e677b2015-10-05 13:28:46 -0400357spv_result_t AssemblyContext::binaryEncodeFloatingPointLiteral(
Lei Zhang1a0334e2015-11-02 09:41:20 -0500358 const char* val, spv_result_t error_code, const IdType& type,
359 spv_instruction_t* pInst) {
David Neto78e677b2015-10-05 13:28:46 -0400360 const auto bit_width = assumedBitWidth(type);
361 switch (bit_width) {
Andrew Woloszyn43401d22016-01-08 09:54:42 -0500362 case 16: {
363 spvutils::HexFloat<FloatProxy<spvutils::Float16>> hVal(0);
364 if (auto error = parseNumber(val, error_code, &hVal,
365 "Invalid 16-bit float literal: "))
366 return error;
367 // getAsFloat will return the spvutils::Float16 value, and get_value
368 // will return a uint16_t representing the bits of the float.
369 // The encoding is therefore correct from the perspective of the SPIR-V
370 // spec since the top 16 bits will be 0.
371 return binaryEncodeU32(
372 static_cast<uint32_t>(hVal.value().getAsFloat().get_value()), pInst);
373 } break;
David Neto78e677b2015-10-05 13:28:46 -0400374 case 32: {
David Neto9e545d72015-11-06 18:08:49 -0500375 spvutils::HexFloat<FloatProxy<float>> fVal(0.0f);
David Neto51013d12015-10-14 11:31:51 -0400376 if (auto error = parseNumber(val, error_code, &fVal,
David Neto78e677b2015-10-05 13:28:46 -0400377 "Invalid 32-bit float literal: "))
378 return error;
379 return binaryEncodeU32(BitwiseCast<uint32_t>(fVal), pInst);
380 } break;
381 case 64: {
David Neto9e545d72015-11-06 18:08:49 -0500382 spvutils::HexFloat<FloatProxy<double>> dVal(0.0);
David Neto51013d12015-10-14 11:31:51 -0400383 if (auto error = parseNumber(val, error_code, &dVal,
David Neto78e677b2015-10-05 13:28:46 -0400384 "Invalid 64-bit float literal: "))
385 return error;
386 return binaryEncodeU64(BitwiseCast<uint64_t>(dVal), pInst);
387 } break;
388 default:
389 break;
390 }
391 return diagnostic() << "Unsupported " << bit_width << "-bit float literals";
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400392}
393
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500394// Returns SPV_SUCCESS if the given value fits within the target scalar
395// integral type. The target type may have an unusual bit width.
396// If the value was originally specified as a hexadecimal number, then
397// the overflow bits should be zero. If it was hex and the target type is
398// signed, then return the sign-extended value through the
399// updated_value_for_hex pointer argument.
400// On failure, return the given error code and emit a diagnostic if that error
401// code is not SPV_FAILED_MATCH.
David Neto78e677b2015-10-05 13:28:46 -0400402template <typename T>
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500403spv_result_t checkRangeAndIfHexThenSignExtend(T value, spv_result_t error_code,
404 const IdType& type, bool is_hex,
405 T* updated_value_for_hex) {
David Neto78e677b2015-10-05 13:28:46 -0400406 // The encoded result has three regions of bits that are of interest, from
407 // least to most significant:
408 // - magnitude bits, where the magnitude of the number would be stored if
409 // we were using a signed-magnitude representation.
410 // - an optional sign bit
411 // - overflow bits, up to bit 63 of a 64-bit number
412 // For example:
413 // Type Overflow Sign Magnitude
414 // --------------- -------- ---- ---------
415 // unsigned 8 bit 8-63 n/a 0-7
416 // signed 8 bit 8-63 7 0-6
417 // unsigned 16 bit 16-63 n/a 0-15
418 // signed 16 bit 16-63 15 0-14
419
420 // We'll use masks to define the three regions.
421 // At first we'll assume the number is unsigned.
422 const uint32_t bit_width = assumedBitWidth(type);
423 uint64_t magnitude_mask =
424 (bit_width == 64) ? -1 : ((uint64_t(1) << bit_width) - 1);
425 uint64_t sign_mask = 0;
426 uint64_t overflow_mask = ~magnitude_mask;
427
428 if (value < 0 || type.isSigned) {
429 // Accommodate the sign bit.
430 magnitude_mask >>= 1;
431 sign_mask = magnitude_mask + 1;
432 }
433
434 bool failed = false;
435 if (value < 0) {
436 // The top bits must all be 1 for a negative signed value.
437 failed = ((value & overflow_mask) != overflow_mask) ||
438 ((value & sign_mask) != sign_mask);
439 } else {
440 if (is_hex) {
441 // Hex values are a bit special. They decode as unsigned values, but
442 // may represent a negative number. In this case, the overflow bits
443 // should be zero.
Ben Vanik01c8d7a2015-11-22 08:32:53 -0800444 failed = (value & overflow_mask) != 0;
David Neto78e677b2015-10-05 13:28:46 -0400445 } else {
Lei Zhang8bd75d62015-11-18 09:22:10 -0500446 const uint64_t value_as_u64 = static_cast<uint64_t>(value);
David Neto78e677b2015-10-05 13:28:46 -0400447 // Check overflow in the ordinary case.
Lei Zhang8bd75d62015-11-18 09:22:10 -0500448 failed = (value_as_u64 & magnitude_mask) != value_as_u64;
David Neto78e677b2015-10-05 13:28:46 -0400449 }
450 }
451
452 if (failed) {
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500453 return error_code;
David Neto78e677b2015-10-05 13:28:46 -0400454 }
455
456 // Sign extend hex the number.
457 if (is_hex && (value & sign_mask))
458 *updated_value_for_hex = (value | overflow_mask);
459
460 return SPV_SUCCESS;
461}
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500462
463spv_result_t AssemblyContext::binaryEncodeIntegerLiteral(
464 const char* val, spv_result_t error_code, const IdType& type,
465 spv_instruction_t* pInst) {
466 const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
467 const uint32_t bit_width = assumedBitWidth(type);
468
469 if (bit_width > 64)
470 return diagnostic(SPV_ERROR_INTERNAL) << "Unsupported " << bit_width
471 << "-bit integer literals";
472
473 // Either we are expecting anything or integer.
474 bool is_negative = val[0] == '-';
475 bool can_be_signed = is_bottom || type.isSigned;
476
477 if (is_negative && !can_be_signed) {
478 return diagnostic()
479 << "Cannot put a negative number in an unsigned literal";
480 }
481
482 const bool is_hex = val[0] == '0' && (val[1] == 'x' || val[1] == 'X');
483
484 uint64_t decoded_bits;
485 if (is_negative) {
486 int64_t decoded_signed = 0;
487
488 if (auto error = parseNumber(val, error_code, &decoded_signed,
489 "Invalid signed integer literal: "))
490 return error;
491 if (auto error = checkRangeAndIfHexThenSignExtend(
492 decoded_signed, error_code, type, is_hex, &decoded_signed)) {
493 diagnostic(error_code)
494 << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
495 << decoded_signed << " does not fit in a " << std::dec << bit_width
496 << "-bit " << (type.isSigned ? "signed" : "unsigned") << " integer";
497 return error;
498 }
499 decoded_bits = decoded_signed;
500 } else {
501 // There's no leading minus sign, so parse it as an unsigned integer.
502 if (auto error = parseNumber(val, error_code, &decoded_bits,
503 "Invalid unsigned integer literal: "))
504 return error;
505 if (auto error = checkRangeAndIfHexThenSignExtend(
506 decoded_bits, error_code, type, is_hex, &decoded_bits)) {
507 diagnostic(error_code)
508 << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
509 << decoded_bits << " does not fit in a " << std::dec << bit_width
510 << "-bit " << (type.isSigned ? "signed" : "unsigned") << " integer";
511 return error;
512 }
513 }
514 if (bit_width > 32) {
515 return binaryEncodeU64(decoded_bits, pInst);
516 } else {
517 return binaryEncodeU32(uint32_t(decoded_bits), pInst);
518 }
519}
Lei Zhang1a0334e2015-11-02 09:41:20 -0500520} // namespace libspirv