blob: 3b1058273a22dc4daf9ba03562d67fc1d708d100 [file] [log] [blame]
Andrew Woloszyn71fc0552015-09-24 10:26:51 -04001// Copyright (c) 2015 The Khronos Group Inc.
2//
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
29#include <algorithm>
30#include <cassert>
David Neto78e677b2015-10-05 13:28:46 -040031#include <cstdlib>
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040032#include <cstring>
Andrew Woloszyn537e7762015-09-29 11:28:34 -040033#include <tuple>
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040034
35#include "binary.h"
David Neto78e677b2015-10-05 13:28:46 -040036#include "bitwisecast.h"
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040037#include "ext_inst.h"
David Netob5dc8fc2015-10-06 16:22:00 -040038#include "instruction.h"
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040039#include "opcode.h"
40#include "text.h"
41
42namespace {
43
David Neto78e677b2015-10-05 13:28:46 -040044using spvutils::BitwiseCast;
45
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040046/// @brief Advance text to the start of the next line
47///
48/// @param[in] text to be parsed
49/// @param[in,out] position position text has been advanced to
50///
51/// @return result code
52spv_result_t advanceLine(spv_text text, spv_position position) {
53 while (true) {
54 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
70/// @brief Advance text to first non white space character
71/// If a null terminator is found during the text advance SPV_END_OF_STREAM is
72/// returned, SPV_SUCCESS otherwise. No error checking is performed on the
73/// parameters, its the users responsibility to ensure these are non null.
74///
75/// @param[in] text to be parsed
76/// @param[in,out] position text has been advanced to
77///
78/// @return result code
79spv_result_t advance(spv_text text, spv_position position) {
80 // NOTE: Consume white space, otherwise don't advance.
81 switch (text->str[position->index]) {
82 case '\0':
83 return SPV_END_OF_STREAM;
84 case ';':
85 if (spv_result_t error = advanceLine(text, position)) return error;
86 return advance(text, position);
87 case ' ':
88 case '\t':
89 position->column++;
90 position->index++;
91 return advance(text, position);
92 case '\n':
93 position->column = 0;
94 position->line++;
95 position->index++;
96 return advance(text, position);
97 default:
98 break;
99 }
100 return SPV_SUCCESS;
101}
102
103/// @brief Fetch the next word from the text stream.
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.
107///
108/// @param[in] text stream to read from
109/// @param[in] position current position in text stream
110/// @param[out] word returned word
111/// @param[out] endPosition one past the end of the returned word
112///
113/// @return result code
114spv_result_t getWord(spv_text text, spv_position position, std::string &word,
115 spv_position endPosition) {
116 if (!text->str || !text->length) return SPV_ERROR_INVALID_TEXT;
117 if (!position || !endPosition) return SPV_ERROR_INVALID_POINTER;
118
119 *endPosition = *position;
120
121 bool quoting = false;
122 bool escaping = false;
123
124 // NOTE: Assumes first character is not white space!
125 while (true) {
126 const char ch = text->str[endPosition->index];
127 if (ch == '\\')
128 escaping = !escaping;
129 else {
130 switch (ch) {
131 case '"':
132 if (!escaping) quoting = !quoting;
133 break;
134 case ' ':
135 case ';':
136 case '\t':
137 case '\n':
138 if (escaping || quoting) break;
139 // Fall through.
140 case '\0': { // NOTE: End of word found!
141 word.assign(text->str + position->index,
142 (size_t)(endPosition->index - position->index));
143 return SPV_SUCCESS;
144 }
145 default:
146 break;
147 }
148 escaping = false;
149 }
150
151 endPosition->column++;
152 endPosition->index++;
153 }
154}
155
156// Returns true if the characters in the text as position represent
157// the start of an Opcode.
158bool startsWithOp(spv_text text, spv_position position) {
159 if (text->length < position->index + 3) return false;
160 char ch0 = text->str[position->index];
161 char ch1 = text->str[position->index + 1];
162 char ch2 = text->str[position->index + 2];
163 return ('O' == ch0 && 'p' == ch1 && ('A' <= ch2 && ch2 <= 'Z'));
164}
165
166/// @brief Parses a mask expression string for the given operand type.
167///
168/// A mask expression is a sequence of one or more terms separated by '|',
169/// where each term a named enum value for the given type. No whitespace
170/// is permitted.
171///
172/// On success, the value is written to pValue.
173///
174/// @param[in] operandTable operand lookup table
175/// @param[in] type of the operand
176/// @param[in] textValue word of text to be parsed
177/// @param[out] pValue where the resulting value is written
178///
179/// @return result code
180spv_result_t spvTextParseMaskOperand(const spv_operand_table operandTable,
181 const spv_operand_type_t type,
182 const char *textValue, uint32_t *pValue) {
183 if (textValue == nullptr) return SPV_ERROR_INVALID_TEXT;
184 size_t text_length = strlen(textValue);
185 if (text_length == 0) return SPV_ERROR_INVALID_TEXT;
186 const char *text_end = textValue + text_length;
187
188 // We only support mask expressions in ASCII, so the separator value is a
189 // char.
190 const char separator = '|';
191
192 // Accumulate the result by interpreting one word at a time, scanning
193 // from left to right.
194 uint32_t value = 0;
195 const char *begin = textValue; // The left end of the current word.
196 const char *end = nullptr; // One character past the end of the current word.
197 do {
198 end = std::find(begin, text_end, separator);
199
200 spv_operand_desc entry = nullptr;
201 if (spvOperandTableNameLookup(operandTable, type, begin, end - begin,
202 &entry)) {
203 return SPV_ERROR_INVALID_TEXT;
204 }
205 value |= entry->value;
206
207 // Advance to the next word by skipping over the separator.
208 begin = end + 1;
209 } while (end != text_end);
210
211 *pValue = value;
212 return SPV_SUCCESS;
213}
214
215} // anonymous namespace
216
217namespace libspirv {
218
David Neto78e677b2015-10-05 13:28:46 -0400219const IdType kUnknownType = {0, false, IdTypeClass::kBottom};
220
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400221bool AssemblyGrammar::isValid() const {
222 return operandTable_ && opcodeTable_ && extInstTable_;
223}
224
225spv_result_t AssemblyGrammar::lookupOpcode(const char *name,
226 spv_opcode_desc *desc) const {
227 return spvOpcodeTableNameLookup(opcodeTable_, name, desc);
228}
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400229
230spv_result_t AssemblyGrammar::lookupOpcode(Op opcode,
231 spv_opcode_desc *desc) const {
232 return spvOpcodeTableValueLookup(opcodeTable_, opcode, desc);
233}
234
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400235spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
236 const char *name, size_t name_len,
237 spv_operand_desc *desc) const {
238 return spvOperandTableNameLookup(operandTable_, type, name, name_len, desc);
239}
240
241spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
242 const char *textValue,
243 uint32_t *pValue) const {
244 return spvTextParseMaskOperand(operandTable_, type, textValue, pValue);
245}
246spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
247 const char *textValue,
248 spv_ext_inst_desc *extInst) const {
249 return spvExtInstTableNameLookup(extInstTable_, type, textValue, extInst);
250}
251
252void AssemblyGrammar::prependOperandTypesForMask(
253 const spv_operand_type_t type, const uint32_t mask,
254 spv_operand_pattern_t *pattern) const {
255 spvPrependOperandTypesForMask(operandTable_, type, mask, pattern);
256}
257
David Neto78e677b2015-10-05 13:28:46 -0400258// TODO(dneto): Reorder AssemblyContext definitions to match declaration order.
259
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400260// This represents all of the data that is only valid for the duration of
261// a single compilation.
262uint32_t AssemblyContext::spvNamedIdAssignOrGet(const char *textValue) {
263 if (named_ids_.end() == named_ids_.find(textValue)) {
264 named_ids_[std::string(textValue)] = bound_++;
265 }
266 return named_ids_[textValue];
267}
268uint32_t AssemblyContext::getBound() const { return bound_; }
269
270spv_result_t AssemblyContext::advance() {
271 return ::advance(text_, &current_position_);
272}
273
274spv_result_t AssemblyContext::getWord(std::string &word,
275 spv_position endPosition) {
276 return ::getWord(text_, &current_position_, word, endPosition);
277}
278
279bool AssemblyContext::startsWithOp() {
280 return ::startsWithOp(text_, &current_position_);
281}
282
283bool AssemblyContext::isStartOfNewInst() {
284 spv_position_t nextPosition = current_position_;
285 if (::advance(text_, &nextPosition)) return false;
286 if (::startsWithOp(text_, &nextPosition)) return true;
287
288 std::string word;
289 spv_position_t startPosition = current_position_;
290 if (::getWord(text_, &startPosition, word, &nextPosition)) return false;
291 if ('%' != word.front()) return false;
292
293 if (::advance(text_, &nextPosition)) return false;
294 startPosition = nextPosition;
295 if (::getWord(text_, &startPosition, word, &nextPosition)) return false;
296 if ("=" != word) return false;
297
298 if (::advance(text_, &nextPosition)) return false;
299 startPosition = nextPosition;
300 if (::startsWithOp(text_, &startPosition)) return true;
301 return false;
302}
303char AssemblyContext::peek() const {
304 return text_->str[current_position_.index];
305}
306
307bool AssemblyContext::hasText() const {
308 return text_->length > current_position_.index;
309}
310std::string AssemblyContext::getWord() const {
311 size_t index = current_position_.index;
312 while (true) {
313 switch (text_->str[index]) {
314 case '\0':
315 case '\t':
316 case '\v':
317 case '\r':
318 case '\n':
319 case ' ':
320 return std::string(text_->str, text_->str + index);
321 default:
322 index++;
323 }
324 }
325 assert(0 && "Unreachable");
326 return ""; // Make certain compilers happy.
327}
328
329void AssemblyContext::seekForward(uint32_t size) {
330 current_position_.index += size;
331 current_position_.column += size;
332}
333
334spv_result_t AssemblyContext::binaryEncodeU32(const uint32_t value,
335 spv_instruction_t *pInst) {
David Netob5dc8fc2015-10-06 16:22:00 -0400336 spvInstructionAddWord(pInst, value);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400337 return SPV_SUCCESS;
338}
339
340spv_result_t AssemblyContext::binaryEncodeU64(const uint64_t value,
341 spv_instruction_t *pInst) {
David Neto78e677b2015-10-05 13:28:46 -0400342 uint32_t low = uint32_t(0x00000000ffffffff & value);
343 uint32_t high = uint32_t((0xffffffff00000000 & value) >> 32);
David Netoac508b02015-10-09 15:48:09 -0400344 binaryEncodeU32(low, pInst);
345 binaryEncodeU32(high, pInst);
346 return SPV_SUCCESS;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400347}
348
David Neto78e677b2015-10-05 13:28:46 -0400349spv_result_t AssemblyContext::binaryEncodeNumericLiteral(
David Neto51013d12015-10-14 11:31:51 -0400350 const char *val, spv_result_t error_code, const IdType &type,
David Neto78e677b2015-10-05 13:28:46 -0400351 spv_instruction_t *pInst) {
352 const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
353 const bool is_floating = libspirv::isScalarFloating(type);
354 const bool is_integer = libspirv::isScalarIntegral(type);
355
356 if (!is_bottom && !is_floating && !is_integer) {
357 return diagnostic(SPV_ERROR_INTERNAL)
358 << "The expected type is not a scalar integer or float type";
359 }
360
361 // If this is bottom, but looks like a float, we should treat it like a
362 // float.
363 const bool looks_like_float = is_bottom && strchr(val, '.');
364
365 // If we explicitly expect a floating-point number, we should handle that
366 // first.
367 if (is_floating || looks_like_float)
David Neto51013d12015-10-14 11:31:51 -0400368 return binaryEncodeFloatingPointLiteral(val, error_code, type, pInst);
David Neto78e677b2015-10-05 13:28:46 -0400369
David Neto51013d12015-10-14 11:31:51 -0400370 return binaryEncodeIntegerLiteral(val, error_code, type, pInst);
David Neto78e677b2015-10-05 13:28:46 -0400371}
372
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400373spv_result_t AssemblyContext::binaryEncodeString(
374 const char *value, spv_instruction_t *pInst) {
David Netob5dc8fc2015-10-06 16:22:00 -0400375 const size_t length = strlen(value);
376 const size_t wordCount = (length / 4) + 1;
377 const size_t oldWordCount = pInst->words.size();
378 const size_t newWordCount = oldWordCount + wordCount;
379
380 // TODO(dneto): We can just defer this check until later.
381 if (newWordCount > SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX) {
David Neto78e677b2015-10-05 13:28:46 -0400382 return diagnostic() << "Instruction too long: more than "
383 << SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << " words.";
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400384 }
385
David Netob5dc8fc2015-10-06 16:22:00 -0400386 pInst->words.resize(newWordCount);
387
388 // Make sure all the bytes in the last word are 0, in case we only
389 // write a partial word at the end.
390 pInst->words.back() = 0;
391
392 char *dest = (char *)&pInst->words[oldWordCount];
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400393 strncpy(dest, value, length);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400394
395 return SPV_SUCCESS;
396}
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400397
398spv_result_t AssemblyContext::recordTypeDefinition(
399 const spv_instruction_t *pInst) {
400 uint32_t value = pInst->words[1];
401 if (types_.find(value) != types_.end()) {
David Neto78e677b2015-10-05 13:28:46 -0400402 return diagnostic()
403 << "Value " << value << " has already been used to generate a type";
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400404 }
405
406 if (pInst->opcode == OpTypeInt) {
David Neto78e677b2015-10-05 13:28:46 -0400407 if (pInst->words.size() != 4)
408 return diagnostic() << "Invalid OpTypeInt instruction";
409 types_[value] = {pInst->words[2], pInst->words[3] != 0,
410 IdTypeClass::kScalarIntegerType};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400411 } else if (pInst->opcode == OpTypeFloat) {
David Neto78e677b2015-10-05 13:28:46 -0400412 if (pInst->words.size() != 3)
413 return diagnostic() << "Invalid OpTypeFloat instruction";
414 types_[value] = {pInst->words[2], false, IdTypeClass::kScalarFloatType};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400415 } else {
David Neto78e677b2015-10-05 13:28:46 -0400416 types_[value] = {0, false, IdTypeClass::kOtherType};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400417 }
418 return SPV_SUCCESS;
419}
420
421IdType AssemblyContext::getTypeOfTypeGeneratingValue(uint32_t value) const {
422 auto type = types_.find(value);
423 if (type == types_.end()) {
David Neto78e677b2015-10-05 13:28:46 -0400424 return kUnknownType;
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400425 }
426 return std::get<1>(*type);
427}
428
429IdType AssemblyContext::getTypeOfValueInstruction(uint32_t value) const {
430 auto type_value = value_types_.find(value);
431 if (type_value == value_types_.end()) {
David Neto78e677b2015-10-05 13:28:46 -0400432 return { 0, false, IdTypeClass::kBottom};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400433 }
434 return getTypeOfTypeGeneratingValue(std::get<1>(*type_value));
435}
436
437spv_result_t AssemblyContext::recordTypeIdForValue(uint32_t value,
438 uint32_t type) {
439 bool successfully_inserted = false;
440 std::tie(std::ignore, successfully_inserted) =
441 value_types_.insert(std::make_pair(value, type));
David Neto78e677b2015-10-05 13:28:46 -0400442 if (!successfully_inserted)
443 return diagnostic() << "Value is being defined a second time";
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400444 return SPV_SUCCESS;
445}
446
David Neto78e677b2015-10-05 13:28:46 -0400447spv_result_t AssemblyContext::binaryEncodeFloatingPointLiteral(
David Neto51013d12015-10-14 11:31:51 -0400448 const char *val, spv_result_t error_code, const IdType &type,
David Neto78e677b2015-10-05 13:28:46 -0400449 spv_instruction_t *pInst) {
450 const auto bit_width = assumedBitWidth(type);
451 switch (bit_width) {
452 case 16:
453 return diagnostic(SPV_ERROR_INTERNAL)
454 << "Unsupported yet: 16-bit float constants.";
455 case 32: {
456 float fVal;
David Neto51013d12015-10-14 11:31:51 -0400457 if (auto error = parseNumber(val, error_code, &fVal,
David Neto78e677b2015-10-05 13:28:46 -0400458 "Invalid 32-bit float literal: "))
459 return error;
460 return binaryEncodeU32(BitwiseCast<uint32_t>(fVal), pInst);
461 } break;
462 case 64: {
463 double dVal;
David Neto51013d12015-10-14 11:31:51 -0400464 if (auto error = parseNumber(val, error_code, &dVal,
David Neto78e677b2015-10-05 13:28:46 -0400465 "Invalid 64-bit float literal: "))
466 return error;
467 return binaryEncodeU64(BitwiseCast<uint64_t>(dVal), pInst);
468 } break;
469 default:
470 break;
471 }
472 return diagnostic() << "Unsupported " << bit_width << "-bit float literals";
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400473}
474
David Neto78e677b2015-10-05 13:28:46 -0400475spv_result_t AssemblyContext::binaryEncodeIntegerLiteral(
David Neto51013d12015-10-14 11:31:51 -0400476 const char *val, spv_result_t error_code, const IdType &type,
David Neto78e677b2015-10-05 13:28:46 -0400477 spv_instruction_t *pInst) {
478 const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
479 const auto bit_width = assumedBitWidth(type);
480
481 if (bit_width > 64)
482 return diagnostic(SPV_ERROR_INTERNAL) << "Unsupported " << bit_width
483 << "-bit integer literals";
484
485 // Either we are expecting anything or integer.
486 bool is_negative = val[0] == '-';
487 bool can_be_signed = is_bottom || type.isSigned;
488
489 if (is_negative && !can_be_signed) {
490 return diagnostic()
491 << "Cannot put a negative number in an unsigned literal";
492 }
493
494 const bool is_hex = val[0] == '0' && (val[1] == 'x' || val[1] == 'X');
495
496 uint64_t decoded_bits;
497 if (is_negative) {
498 int64_t decoded_signed = 0;
David Neto51013d12015-10-14 11:31:51 -0400499 if (auto error = parseNumber(val, error_code, &decoded_signed,
David Neto78e677b2015-10-05 13:28:46 -0400500 "Invalid signed integer literal: "))
501 return error;
502 if (auto error = checkRangeAndIfHexThenSignExtend(
David Neto51013d12015-10-14 11:31:51 -0400503 decoded_signed, error_code, type, is_hex, &decoded_signed))
David Neto78e677b2015-10-05 13:28:46 -0400504 return error;
505 decoded_bits = decoded_signed;
506 } else {
507 // There's no leading minus sign, so parse it as an unsigned integer.
David Neto51013d12015-10-14 11:31:51 -0400508 if (auto error = parseNumber(val, error_code, &decoded_bits,
David Neto78e677b2015-10-05 13:28:46 -0400509 "Invalid unsigned integer literal: "))
510 return error;
511 if (auto error = checkRangeAndIfHexThenSignExtend(
David Neto51013d12015-10-14 11:31:51 -0400512 decoded_bits, error_code, type, is_hex, &decoded_bits))
David Neto78e677b2015-10-05 13:28:46 -0400513 return error;
514 }
515 if (bit_width > 32) {
516 return binaryEncodeU64(decoded_bits, pInst);
517 } else {
518 return binaryEncodeU32(uint32_t(decoded_bits), pInst);
519 }
520}
521
522template <typename T>
523spv_result_t AssemblyContext::checkRangeAndIfHexThenSignExtend(
David Neto51013d12015-10-14 11:31:51 -0400524 T value, spv_result_t error_code, const IdType &type, bool is_hex,
David Neto78e677b2015-10-05 13:28:46 -0400525 T *updated_value_for_hex) {
526 // The encoded result has three regions of bits that are of interest, from
527 // least to most significant:
528 // - magnitude bits, where the magnitude of the number would be stored if
529 // we were using a signed-magnitude representation.
530 // - an optional sign bit
531 // - overflow bits, up to bit 63 of a 64-bit number
532 // For example:
533 // Type Overflow Sign Magnitude
534 // --------------- -------- ---- ---------
535 // unsigned 8 bit 8-63 n/a 0-7
536 // signed 8 bit 8-63 7 0-6
537 // unsigned 16 bit 16-63 n/a 0-15
538 // signed 16 bit 16-63 15 0-14
539
540 // We'll use masks to define the three regions.
541 // At first we'll assume the number is unsigned.
542 const uint32_t bit_width = assumedBitWidth(type);
543 uint64_t magnitude_mask =
544 (bit_width == 64) ? -1 : ((uint64_t(1) << bit_width) - 1);
545 uint64_t sign_mask = 0;
546 uint64_t overflow_mask = ~magnitude_mask;
547
548 if (value < 0 || type.isSigned) {
549 // Accommodate the sign bit.
550 magnitude_mask >>= 1;
551 sign_mask = magnitude_mask + 1;
552 }
553
554 bool failed = false;
555 if (value < 0) {
556 // The top bits must all be 1 for a negative signed value.
557 failed = ((value & overflow_mask) != overflow_mask) ||
558 ((value & sign_mask) != sign_mask);
559 } else {
560 if (is_hex) {
561 // Hex values are a bit special. They decode as unsigned values, but
562 // may represent a negative number. In this case, the overflow bits
563 // should be zero.
564 failed = (value & overflow_mask);
565 } else {
566 // Check overflow in the ordinary case.
567 failed = (value & magnitude_mask) != value;
568 }
569 }
570
571 if (failed) {
David Neto51013d12015-10-14 11:31:51 -0400572 return diagnostic(error_code)
573 << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
574 << value << " does not fit in a " << std::dec << bit_width << "-bit "
575 << (type.isSigned ? "signed" : "unsigned") << " integer";
David Neto78e677b2015-10-05 13:28:46 -0400576 }
577
578 // Sign extend hex the number.
579 if (is_hex && (value & sign_mask))
580 *updated_value_for_hex = (value | overflow_mask);
581
582 return SPV_SUCCESS;
583}
584} // namespace libspirv