blob: 851d1b13410f1b01f62e9cd4fcbec0e8c9affd1f [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
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040049/// @brief Advance text to the start of the next line
50///
51/// @param[in] text to be parsed
52/// @param[in,out] position position text has been advanced to
53///
54/// @return result code
55spv_result_t advanceLine(spv_text text, spv_position position) {
56 while (true) {
57 switch (text->str[position->index]) {
58 case '\0':
59 return SPV_END_OF_STREAM;
60 case '\n':
61 position->column = 0;
62 position->line++;
63 position->index++;
64 return SPV_SUCCESS;
65 default:
66 position->column++;
67 position->index++;
68 break;
69 }
70 }
71}
72
73/// @brief Advance text to first non white space character
74/// If a null terminator is found during the text advance SPV_END_OF_STREAM is
75/// returned, SPV_SUCCESS otherwise. No error checking is performed on the
76/// parameters, its the users responsibility to ensure these are non null.
77///
78/// @param[in] text to be parsed
79/// @param[in,out] position text has been advanced to
80///
81/// @return result code
82spv_result_t advance(spv_text text, spv_position position) {
83 // NOTE: Consume white space, otherwise don't advance.
Lei Zhang8f6ba142015-11-06 15:09:04 -050084 if (position->index >= text->length) return SPV_END_OF_STREAM;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040085 switch (text->str[position->index]) {
86 case '\0':
87 return SPV_END_OF_STREAM;
88 case ';':
89 if (spv_result_t error = advanceLine(text, position)) return error;
90 return advance(text, position);
91 case ' ':
92 case '\t':
93 position->column++;
94 position->index++;
95 return advance(text, position);
96 case '\n':
97 position->column = 0;
98 position->line++;
99 position->index++;
100 return advance(text, position);
101 default:
102 break;
103 }
104 return SPV_SUCCESS;
105}
106
107/// @brief Fetch the next word from the text stream.
108///
109/// A word ends at the next comment or whitespace. However, double-quoted
110/// strings remain intact, and a backslash always escapes the next character.
111///
112/// @param[in] text stream to read from
113/// @param[in] position current position in text stream
114/// @param[out] word returned word
115/// @param[out] endPosition one past the end of the returned word
116///
117/// @return result code
Lei Zhang1a0334e2015-11-02 09:41:20 -0500118spv_result_t getWord(spv_text text, spv_position position, std::string& word,
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400119 spv_position endPosition) {
120 if (!text->str || !text->length) return SPV_ERROR_INVALID_TEXT;
121 if (!position || !endPosition) return SPV_ERROR_INVALID_POINTER;
122
123 *endPosition = *position;
124
125 bool quoting = false;
126 bool escaping = false;
127
128 // NOTE: Assumes first character is not white space!
129 while (true) {
Lei Zhang9413fbb2016-02-22 17:17:25 -0500130 if (endPosition->index >= text->length) {
131 word.assign(text->str + position->index,
132 static_cast<size_t>(endPosition->index - position->index));
133 return SPV_SUCCESS;
134 }
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400135 const char ch = text->str[endPosition->index];
136 if (ch == '\\')
137 escaping = !escaping;
138 else {
139 switch (ch) {
140 case '"':
141 if (!escaping) quoting = !quoting;
142 break;
143 case ' ':
144 case ';':
145 case '\t':
146 case '\n':
147 if (escaping || quoting) break;
148 // Fall through.
149 case '\0': { // NOTE: End of word found!
Lei Zhang9413fbb2016-02-22 17:17:25 -0500150 word.assign(
151 text->str + position->index,
152 static_cast<size_t>(endPosition->index - position->index));
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400153 return SPV_SUCCESS;
154 }
155 default:
156 break;
157 }
158 escaping = false;
159 }
160
161 endPosition->column++;
162 endPosition->index++;
163 }
164}
165
166// Returns true if the characters in the text as position represent
167// the start of an Opcode.
168bool startsWithOp(spv_text text, spv_position position) {
169 if (text->length < position->index + 3) return false;
170 char ch0 = text->str[position->index];
171 char ch1 = text->str[position->index + 1];
172 char ch2 = text->str[position->index + 2];
173 return ('O' == ch0 && 'p' == ch1 && ('A' <= ch2 && ch2 <= 'Z'));
174}
175
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400176} // anonymous namespace
177
178namespace libspirv {
179
David Neto78e677b2015-10-05 13:28:46 -0400180const IdType kUnknownType = {0, false, IdTypeClass::kBottom};
181
David Neto78e677b2015-10-05 13:28:46 -0400182// TODO(dneto): Reorder AssemblyContext definitions to match declaration order.
183
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400184// This represents all of the data that is only valid for the duration of
185// a single compilation.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500186uint32_t AssemblyContext::spvNamedIdAssignOrGet(const char* textValue) {
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400187 if (named_ids_.end() == named_ids_.find(textValue)) {
188 named_ids_[std::string(textValue)] = bound_++;
189 }
190 return named_ids_[textValue];
191}
192uint32_t AssemblyContext::getBound() const { return bound_; }
193
194spv_result_t AssemblyContext::advance() {
195 return ::advance(text_, &current_position_);
196}
197
Lei Zhang1a0334e2015-11-02 09:41:20 -0500198spv_result_t AssemblyContext::getWord(std::string& word,
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400199 spv_position endPosition) {
200 return ::getWord(text_, &current_position_, word, endPosition);
201}
202
203bool AssemblyContext::startsWithOp() {
204 return ::startsWithOp(text_, &current_position_);
205}
206
207bool AssemblyContext::isStartOfNewInst() {
208 spv_position_t nextPosition = current_position_;
209 if (::advance(text_, &nextPosition)) return false;
210 if (::startsWithOp(text_, &nextPosition)) return true;
211
212 std::string word;
213 spv_position_t startPosition = current_position_;
214 if (::getWord(text_, &startPosition, word, &nextPosition)) return false;
215 if ('%' != word.front()) return false;
216
217 if (::advance(text_, &nextPosition)) return false;
218 startPosition = nextPosition;
219 if (::getWord(text_, &startPosition, word, &nextPosition)) return false;
220 if ("=" != word) return false;
221
222 if (::advance(text_, &nextPosition)) return false;
223 startPosition = nextPosition;
224 if (::startsWithOp(text_, &startPosition)) return true;
225 return false;
226}
Andrew Woloszyn4274f932015-10-20 09:12:32 -0400227
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400228char AssemblyContext::peek() const {
229 return text_->str[current_position_.index];
230}
231
232bool AssemblyContext::hasText() const {
233 return text_->length > current_position_.index;
234}
Andrew Woloszyn4274f932015-10-20 09:12:32 -0400235
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400236std::string AssemblyContext::getWord() const {
Andrew Woloszyn4274f932015-10-20 09:12:32 -0400237 uint64_t index = current_position_.index;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400238 while (true) {
239 switch (text_->str[index]) {
240 case '\0':
241 case '\t':
242 case '\v':
243 case '\r':
244 case '\n':
245 case ' ':
246 return std::string(text_->str, text_->str + index);
247 default:
248 index++;
249 }
250 }
251 assert(0 && "Unreachable");
252 return ""; // Make certain compilers happy.
253}
254
255void AssemblyContext::seekForward(uint32_t size) {
256 current_position_.index += size;
257 current_position_.column += size;
258}
259
260spv_result_t AssemblyContext::binaryEncodeU32(const uint32_t value,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500261 spv_instruction_t* pInst) {
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500262 pInst->words.insert(pInst->words.end(), value);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400263 return SPV_SUCCESS;
264}
265
266spv_result_t AssemblyContext::binaryEncodeU64(const uint64_t value,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500267 spv_instruction_t* pInst) {
David Neto78e677b2015-10-05 13:28:46 -0400268 uint32_t low = uint32_t(0x00000000ffffffff & value);
269 uint32_t high = uint32_t((0xffffffff00000000 & value) >> 32);
David Netoac508b02015-10-09 15:48:09 -0400270 binaryEncodeU32(low, pInst);
271 binaryEncodeU32(high, pInst);
272 return SPV_SUCCESS;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400273}
274
David Neto78e677b2015-10-05 13:28:46 -0400275spv_result_t AssemblyContext::binaryEncodeNumericLiteral(
Lei Zhang1a0334e2015-11-02 09:41:20 -0500276 const char* val, spv_result_t error_code, const IdType& type,
277 spv_instruction_t* pInst) {
David Neto78e677b2015-10-05 13:28:46 -0400278 const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
279 const bool is_floating = libspirv::isScalarFloating(type);
280 const bool is_integer = libspirv::isScalarIntegral(type);
281
282 if (!is_bottom && !is_floating && !is_integer) {
283 return diagnostic(SPV_ERROR_INTERNAL)
284 << "The expected type is not a scalar integer or float type";
285 }
286
287 // If this is bottom, but looks like a float, we should treat it like a
288 // float.
289 const bool looks_like_float = is_bottom && strchr(val, '.');
290
291 // If we explicitly expect a floating-point number, we should handle that
292 // first.
293 if (is_floating || looks_like_float)
David Neto51013d12015-10-14 11:31:51 -0400294 return binaryEncodeFloatingPointLiteral(val, error_code, type, pInst);
David Neto78e677b2015-10-05 13:28:46 -0400295
David Neto51013d12015-10-14 11:31:51 -0400296 return binaryEncodeIntegerLiteral(val, error_code, type, pInst);
David Neto78e677b2015-10-05 13:28:46 -0400297}
298
Lei Zhang1a0334e2015-11-02 09:41:20 -0500299spv_result_t AssemblyContext::binaryEncodeString(const char* value,
300 spv_instruction_t* pInst) {
David Netob5dc8fc2015-10-06 16:22:00 -0400301 const size_t length = strlen(value);
302 const size_t wordCount = (length / 4) + 1;
303 const size_t oldWordCount = pInst->words.size();
304 const size_t newWordCount = oldWordCount + wordCount;
305
306 // TODO(dneto): We can just defer this check until later.
307 if (newWordCount > SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX) {
David Neto78e677b2015-10-05 13:28:46 -0400308 return diagnostic() << "Instruction too long: more than "
309 << SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << " words.";
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400310 }
311
David Netob5dc8fc2015-10-06 16:22:00 -0400312 pInst->words.resize(newWordCount);
313
314 // Make sure all the bytes in the last word are 0, in case we only
315 // write a partial word at the end.
316 pInst->words.back() = 0;
317
Lei Zhang1a0334e2015-11-02 09:41:20 -0500318 char* dest = (char*)&pInst->words[oldWordCount];
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400319 strncpy(dest, value, length);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400320
321 return SPV_SUCCESS;
322}
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400323
324spv_result_t AssemblyContext::recordTypeDefinition(
Lei Zhang1a0334e2015-11-02 09:41:20 -0500325 const spv_instruction_t* pInst) {
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400326 uint32_t value = pInst->words[1];
327 if (types_.find(value) != types_.end()) {
Lei Zhang1a0334e2015-11-02 09:41:20 -0500328 return diagnostic() << "Value " << value
329 << " has already been used to generate a type";
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400330 }
331
Lei Zhangb36e7042015-10-28 13:40:52 -0400332 if (pInst->opcode == SpvOpTypeInt) {
David Neto78e677b2015-10-05 13:28:46 -0400333 if (pInst->words.size() != 4)
334 return diagnostic() << "Invalid OpTypeInt instruction";
335 types_[value] = {pInst->words[2], pInst->words[3] != 0,
336 IdTypeClass::kScalarIntegerType};
Lei Zhangb36e7042015-10-28 13:40:52 -0400337 } else if (pInst->opcode == SpvOpTypeFloat) {
David Neto78e677b2015-10-05 13:28:46 -0400338 if (pInst->words.size() != 3)
339 return diagnostic() << "Invalid OpTypeFloat instruction";
340 types_[value] = {pInst->words[2], false, IdTypeClass::kScalarFloatType};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400341 } else {
David Neto78e677b2015-10-05 13:28:46 -0400342 types_[value] = {0, false, IdTypeClass::kOtherType};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400343 }
344 return SPV_SUCCESS;
345}
346
347IdType AssemblyContext::getTypeOfTypeGeneratingValue(uint32_t value) const {
348 auto type = types_.find(value);
349 if (type == types_.end()) {
David Neto78e677b2015-10-05 13:28:46 -0400350 return kUnknownType;
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400351 }
352 return std::get<1>(*type);
353}
354
355IdType AssemblyContext::getTypeOfValueInstruction(uint32_t value) const {
356 auto type_value = value_types_.find(value);
357 if (type_value == value_types_.end()) {
Lei Zhang1a0334e2015-11-02 09:41:20 -0500358 return {0, false, IdTypeClass::kBottom};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400359 }
360 return getTypeOfTypeGeneratingValue(std::get<1>(*type_value));
361}
362
363spv_result_t AssemblyContext::recordTypeIdForValue(uint32_t value,
364 uint32_t type) {
365 bool successfully_inserted = false;
366 std::tie(std::ignore, successfully_inserted) =
367 value_types_.insert(std::make_pair(value, type));
David Neto78e677b2015-10-05 13:28:46 -0400368 if (!successfully_inserted)
369 return diagnostic() << "Value is being defined a second time";
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400370 return SPV_SUCCESS;
371}
372
David Neto2ae4a682015-11-09 18:55:42 -0500373spv_result_t AssemblyContext::recordIdAsExtInstImport(
374 uint32_t id, spv_ext_inst_type_t type) {
375 bool successfully_inserted = false;
376 std::tie(std::ignore, successfully_inserted) =
377 import_id_to_ext_inst_type_.insert(std::make_pair(id, type));
378 if (!successfully_inserted)
379 return diagnostic() << "Import Id is being defined a second time";
380 return SPV_SUCCESS;
381}
382
383spv_ext_inst_type_t AssemblyContext::getExtInstTypeForId(uint32_t id) const {
384 auto type = import_id_to_ext_inst_type_.find(id);
385 if (type == import_id_to_ext_inst_type_.end()) {
386 return SPV_EXT_INST_TYPE_NONE;
387 }
388 return std::get<1>(*type);
389}
390
David Neto78e677b2015-10-05 13:28:46 -0400391spv_result_t AssemblyContext::binaryEncodeFloatingPointLiteral(
Lei Zhang1a0334e2015-11-02 09:41:20 -0500392 const char* val, spv_result_t error_code, const IdType& type,
393 spv_instruction_t* pInst) {
David Neto78e677b2015-10-05 13:28:46 -0400394 const auto bit_width = assumedBitWidth(type);
395 switch (bit_width) {
Andrew Woloszyn43401d22016-01-08 09:54:42 -0500396 case 16: {
397 spvutils::HexFloat<FloatProxy<spvutils::Float16>> hVal(0);
398 if (auto error = parseNumber(val, error_code, &hVal,
399 "Invalid 16-bit float literal: "))
400 return error;
401 // getAsFloat will return the spvutils::Float16 value, and get_value
402 // will return a uint16_t representing the bits of the float.
403 // The encoding is therefore correct from the perspective of the SPIR-V
404 // spec since the top 16 bits will be 0.
405 return binaryEncodeU32(
406 static_cast<uint32_t>(hVal.value().getAsFloat().get_value()), pInst);
407 } break;
David Neto78e677b2015-10-05 13:28:46 -0400408 case 32: {
David Neto9e545d72015-11-06 18:08:49 -0500409 spvutils::HexFloat<FloatProxy<float>> fVal(0.0f);
David Neto51013d12015-10-14 11:31:51 -0400410 if (auto error = parseNumber(val, error_code, &fVal,
David Neto78e677b2015-10-05 13:28:46 -0400411 "Invalid 32-bit float literal: "))
412 return error;
413 return binaryEncodeU32(BitwiseCast<uint32_t>(fVal), pInst);
414 } break;
415 case 64: {
David Neto9e545d72015-11-06 18:08:49 -0500416 spvutils::HexFloat<FloatProxy<double>> dVal(0.0);
David Neto51013d12015-10-14 11:31:51 -0400417 if (auto error = parseNumber(val, error_code, &dVal,
David Neto78e677b2015-10-05 13:28:46 -0400418 "Invalid 64-bit float literal: "))
419 return error;
420 return binaryEncodeU64(BitwiseCast<uint64_t>(dVal), pInst);
421 } break;
422 default:
423 break;
424 }
425 return diagnostic() << "Unsupported " << bit_width << "-bit float literals";
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400426}
427
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500428// Returns SPV_SUCCESS if the given value fits within the target scalar
429// integral type. The target type may have an unusual bit width.
430// If the value was originally specified as a hexadecimal number, then
431// the overflow bits should be zero. If it was hex and the target type is
432// signed, then return the sign-extended value through the
433// updated_value_for_hex pointer argument.
434// On failure, return the given error code and emit a diagnostic if that error
435// code is not SPV_FAILED_MATCH.
David Neto78e677b2015-10-05 13:28:46 -0400436template <typename T>
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500437spv_result_t checkRangeAndIfHexThenSignExtend(T value, spv_result_t error_code,
438 const IdType& type, bool is_hex,
439 T* updated_value_for_hex) {
David Neto78e677b2015-10-05 13:28:46 -0400440 // The encoded result has three regions of bits that are of interest, from
441 // least to most significant:
442 // - magnitude bits, where the magnitude of the number would be stored if
443 // we were using a signed-magnitude representation.
444 // - an optional sign bit
445 // - overflow bits, up to bit 63 of a 64-bit number
446 // For example:
447 // Type Overflow Sign Magnitude
448 // --------------- -------- ---- ---------
449 // unsigned 8 bit 8-63 n/a 0-7
450 // signed 8 bit 8-63 7 0-6
451 // unsigned 16 bit 16-63 n/a 0-15
452 // signed 16 bit 16-63 15 0-14
453
454 // We'll use masks to define the three regions.
455 // At first we'll assume the number is unsigned.
456 const uint32_t bit_width = assumedBitWidth(type);
457 uint64_t magnitude_mask =
458 (bit_width == 64) ? -1 : ((uint64_t(1) << bit_width) - 1);
459 uint64_t sign_mask = 0;
460 uint64_t overflow_mask = ~magnitude_mask;
461
462 if (value < 0 || type.isSigned) {
463 // Accommodate the sign bit.
464 magnitude_mask >>= 1;
465 sign_mask = magnitude_mask + 1;
466 }
467
468 bool failed = false;
469 if (value < 0) {
470 // The top bits must all be 1 for a negative signed value.
471 failed = ((value & overflow_mask) != overflow_mask) ||
472 ((value & sign_mask) != sign_mask);
473 } else {
474 if (is_hex) {
475 // Hex values are a bit special. They decode as unsigned values, but
476 // may represent a negative number. In this case, the overflow bits
477 // should be zero.
Ben Vanik01c8d7a2015-11-22 08:32:53 -0800478 failed = (value & overflow_mask) != 0;
David Neto78e677b2015-10-05 13:28:46 -0400479 } else {
Lei Zhang8bd75d62015-11-18 09:22:10 -0500480 const uint64_t value_as_u64 = static_cast<uint64_t>(value);
David Neto78e677b2015-10-05 13:28:46 -0400481 // Check overflow in the ordinary case.
Lei Zhang8bd75d62015-11-18 09:22:10 -0500482 failed = (value_as_u64 & magnitude_mask) != value_as_u64;
David Neto78e677b2015-10-05 13:28:46 -0400483 }
484 }
485
486 if (failed) {
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500487 return error_code;
David Neto78e677b2015-10-05 13:28:46 -0400488 }
489
490 // Sign extend hex the number.
491 if (is_hex && (value & sign_mask))
492 *updated_value_for_hex = (value | overflow_mask);
493
494 return SPV_SUCCESS;
495}
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500496
497spv_result_t AssemblyContext::binaryEncodeIntegerLiteral(
498 const char* val, spv_result_t error_code, const IdType& type,
499 spv_instruction_t* pInst) {
500 const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
501 const uint32_t bit_width = assumedBitWidth(type);
502
503 if (bit_width > 64)
504 return diagnostic(SPV_ERROR_INTERNAL) << "Unsupported " << bit_width
505 << "-bit integer literals";
506
507 // Either we are expecting anything or integer.
508 bool is_negative = val[0] == '-';
509 bool can_be_signed = is_bottom || type.isSigned;
510
511 if (is_negative && !can_be_signed) {
512 return diagnostic()
513 << "Cannot put a negative number in an unsigned literal";
514 }
515
516 const bool is_hex = val[0] == '0' && (val[1] == 'x' || val[1] == 'X');
517
518 uint64_t decoded_bits;
519 if (is_negative) {
520 int64_t decoded_signed = 0;
521
522 if (auto error = parseNumber(val, error_code, &decoded_signed,
523 "Invalid signed integer literal: "))
524 return error;
525 if (auto error = checkRangeAndIfHexThenSignExtend(
526 decoded_signed, error_code, type, is_hex, &decoded_signed)) {
527 diagnostic(error_code)
528 << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
529 << decoded_signed << " does not fit in a " << std::dec << bit_width
530 << "-bit " << (type.isSigned ? "signed" : "unsigned") << " integer";
531 return error;
532 }
533 decoded_bits = decoded_signed;
534 } else {
535 // There's no leading minus sign, so parse it as an unsigned integer.
536 if (auto error = parseNumber(val, error_code, &decoded_bits,
537 "Invalid unsigned integer literal: "))
538 return error;
539 if (auto error = checkRangeAndIfHexThenSignExtend(
540 decoded_bits, error_code, type, is_hex, &decoded_bits)) {
541 diagnostic(error_code)
542 << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
543 << decoded_bits << " does not fit in a " << std::dec << bit_width
544 << "-bit " << (type.isSigned ? "signed" : "unsigned") << " integer";
545 return error;
546 }
547 }
548 if (bit_width > 32) {
549 return binaryEncodeU64(decoded_bits, pInst);
550 } else {
551 return binaryEncodeU32(uint32_t(decoded_bits), pInst);
552 }
553}
Lei Zhang1a0334e2015-11-02 09:41:20 -0500554} // namespace libspirv