blob: 65c5e0d26f4de833bcc8cc36aa0cf60e2c56db41 [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//
David Neto9fc86582016-09-01 15:33:59 -04003// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
Andrew Woloszyn71fc0552015-09-24 10:26:51 -04006//
David Neto9fc86582016-09-01 15:33:59 -04007// http://www.apache.org/licenses/LICENSE-2.0
Andrew Woloszyn71fc0552015-09-24 10:26:51 -04008//
David Neto9fc86582016-09-01 15:33:59 -04009// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040014
15#include "text_handler.h"
16
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040017#include <cassert>
David Neto78e677b2015-10-05 13:28:46 -040018#include <cstdlib>
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040019#include <cstring>
Andrew Woloszyn537e7762015-09-29 11:28:34 -040020#include <tuple>
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040021
David Netofcc7d582015-10-27 15:31:10 -040022#include "assembly_grammar.h"
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040023#include "binary.h"
24#include "ext_inst.h"
David Netob5dc8fc2015-10-06 16:22:00 -040025#include "instruction.h"
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040026#include "opcode.h"
27#include "text.h"
Andrew Woloszynf731cbf2015-10-23 09:53:58 -040028#include "util/bitutils.h"
David Neto9e545d72015-11-06 18:08:49 -050029#include "util/hex_float.h"
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040030
31namespace {
32
David Neto78e677b2015-10-05 13:28:46 -040033using spvutils::BitwiseCast;
David Neto9e545d72015-11-06 18:08:49 -050034using spvutils::FloatProxy;
35using spvutils::HexFloat;
David Neto78e677b2015-10-05 13:28:46 -040036
Lei Zhangf2cf7192016-04-21 15:50:23 -040037// Advances |text| to the start of the next line and writes the new position to
38// |position|.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040039spv_result_t advanceLine(spv_text text, spv_position position) {
40 while (true) {
Lei Zhangf2cf7192016-04-21 15:50:23 -040041 if (position->index >= text->length) return SPV_END_OF_STREAM;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040042 switch (text->str[position->index]) {
43 case '\0':
44 return SPV_END_OF_STREAM;
45 case '\n':
46 position->column = 0;
47 position->line++;
48 position->index++;
49 return SPV_SUCCESS;
50 default:
51 position->column++;
52 position->index++;
53 break;
54 }
55 }
56}
57
Lei Zhangf2cf7192016-04-21 15:50:23 -040058// Advances |text| to first non white space character and writes the new
59// position to |position|.
60// If a null terminator is found during the text advance, SPV_END_OF_STREAM is
61// returned, SPV_SUCCESS otherwise. No error checking is performed on the
62// parameters, its the users responsibility to ensure these are non null.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040063spv_result_t advance(spv_text text, spv_position position) {
64 // NOTE: Consume white space, otherwise don't advance.
Lei Zhang8f6ba142015-11-06 15:09:04 -050065 if (position->index >= text->length) return SPV_END_OF_STREAM;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040066 switch (text->str[position->index]) {
67 case '\0':
68 return SPV_END_OF_STREAM;
69 case ';':
70 if (spv_result_t error = advanceLine(text, position)) return error;
71 return advance(text, position);
72 case ' ':
73 case '\t':
Dejan Mircevskia1de2b32016-04-01 00:47:02 -040074 case '\r':
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040075 position->column++;
76 position->index++;
77 return advance(text, position);
78 case '\n':
79 position->column = 0;
80 position->line++;
81 position->index++;
82 return advance(text, position);
83 default:
84 break;
85 }
86 return SPV_SUCCESS;
87}
88
Lei Zhang6032b982016-03-15 16:52:40 -040089// Fetches the next word from the given text stream starting from the given
90// *position. On success, writes the decoded word into *word and updates
91// *position to the location past the returned word.
92//
93// A word ends at the next comment or whitespace. However, double-quoted
94// strings remain intact, and a backslash always escapes the next character.
95spv_result_t getWord(spv_text text, spv_position position, std::string* word) {
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040096 if (!text->str || !text->length) return SPV_ERROR_INVALID_TEXT;
Lei Zhang6032b982016-03-15 16:52:40 -040097 if (!position) return SPV_ERROR_INVALID_POINTER;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040098
Lei Zhang6032b982016-03-15 16:52:40 -040099 const size_t start_index = position->index;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400100
101 bool quoting = false;
102 bool escaping = false;
103
104 // NOTE: Assumes first character is not white space!
105 while (true) {
Lei Zhang6032b982016-03-15 16:52:40 -0400106 if (position->index >= text->length) {
107 word->assign(text->str + start_index, text->str + position->index);
Lei Zhang9413fbb2016-02-22 17:17:25 -0500108 return SPV_SUCCESS;
109 }
Lei Zhang6032b982016-03-15 16:52:40 -0400110 const char ch = text->str[position->index];
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400111 if (ch == '\\')
112 escaping = !escaping;
113 else {
114 switch (ch) {
115 case '"':
116 if (!escaping) quoting = !quoting;
117 break;
118 case ' ':
119 case ';':
120 case '\t':
121 case '\n':
Dejan Mircevskia1de2b32016-04-01 00:47:02 -0400122 case '\r':
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400123 if (escaping || quoting) break;
124 // Fall through.
125 case '\0': { // NOTE: End of word found!
Lei Zhang6032b982016-03-15 16:52:40 -0400126 word->assign(text->str + start_index, text->str + position->index);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400127 return SPV_SUCCESS;
128 }
129 default:
130 break;
131 }
132 escaping = false;
133 }
134
Lei Zhang6032b982016-03-15 16:52:40 -0400135 position->column++;
136 position->index++;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400137 }
138}
139
140// Returns true if the characters in the text as position represent
141// the start of an Opcode.
142bool startsWithOp(spv_text text, spv_position position) {
143 if (text->length < position->index + 3) return false;
144 char ch0 = text->str[position->index];
145 char ch1 = text->str[position->index + 1];
146 char ch2 = text->str[position->index + 2];
147 return ('O' == ch0 && 'p' == ch1 && ('A' <= ch2 && ch2 <= 'Z'));
148}
149
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400150} // anonymous namespace
151
152namespace libspirv {
153
David Neto78e677b2015-10-05 13:28:46 -0400154const IdType kUnknownType = {0, false, IdTypeClass::kBottom};
155
David Neto78e677b2015-10-05 13:28:46 -0400156// TODO(dneto): Reorder AssemblyContext definitions to match declaration order.
157
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400158// This represents all of the data that is only valid for the duration of
159// a single compilation.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500160uint32_t AssemblyContext::spvNamedIdAssignOrGet(const char* textValue) {
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400161 if (named_ids_.end() == named_ids_.find(textValue)) {
162 named_ids_[std::string(textValue)] = bound_++;
163 }
164 return named_ids_[textValue];
165}
166uint32_t AssemblyContext::getBound() const { return bound_; }
167
168spv_result_t AssemblyContext::advance() {
169 return ::advance(text_, &current_position_);
170}
171
Lei Zhang6032b982016-03-15 16:52:40 -0400172spv_result_t AssemblyContext::getWord(std::string* word,
173 spv_position next_position) {
174 *next_position = current_position_;
175 return ::getWord(text_, next_position, word);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400176}
177
178bool AssemblyContext::startsWithOp() {
179 return ::startsWithOp(text_, &current_position_);
180}
181
182bool AssemblyContext::isStartOfNewInst() {
Lei Zhang6032b982016-03-15 16:52:40 -0400183 spv_position_t pos = current_position_;
184 if (::advance(text_, &pos)) return false;
185 if (::startsWithOp(text_, &pos)) return true;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400186
187 std::string word;
Lei Zhang6032b982016-03-15 16:52:40 -0400188 pos = current_position_;
189 if (::getWord(text_, &pos, &word)) return false;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400190 if ('%' != word.front()) return false;
191
Lei Zhang6032b982016-03-15 16:52:40 -0400192 if (::advance(text_, &pos)) return false;
193 if (::getWord(text_, &pos, &word)) return false;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400194 if ("=" != word) return false;
195
Lei Zhang6032b982016-03-15 16:52:40 -0400196 if (::advance(text_, &pos)) return false;
197 if (::startsWithOp(text_, &pos)) return true;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400198 return false;
199}
Andrew Woloszyn4274f932015-10-20 09:12:32 -0400200
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400201char AssemblyContext::peek() const {
202 return text_->str[current_position_.index];
203}
204
205bool AssemblyContext::hasText() const {
206 return text_->length > current_position_.index;
207}
Andrew Woloszyn4274f932015-10-20 09:12:32 -0400208
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400209void AssemblyContext::seekForward(uint32_t size) {
210 current_position_.index += size;
211 current_position_.column += size;
212}
213
214spv_result_t AssemblyContext::binaryEncodeU32(const uint32_t value,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500215 spv_instruction_t* pInst) {
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500216 pInst->words.insert(pInst->words.end(), value);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400217 return SPV_SUCCESS;
218}
219
220spv_result_t AssemblyContext::binaryEncodeU64(const uint64_t value,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500221 spv_instruction_t* pInst) {
David Neto78e677b2015-10-05 13:28:46 -0400222 uint32_t low = uint32_t(0x00000000ffffffff & value);
223 uint32_t high = uint32_t((0xffffffff00000000 & value) >> 32);
David Netoac508b02015-10-09 15:48:09 -0400224 binaryEncodeU32(low, pInst);
225 binaryEncodeU32(high, pInst);
226 return SPV_SUCCESS;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400227}
228
David Neto78e677b2015-10-05 13:28:46 -0400229spv_result_t AssemblyContext::binaryEncodeNumericLiteral(
Lei Zhang1a0334e2015-11-02 09:41:20 -0500230 const char* val, spv_result_t error_code, const IdType& type,
231 spv_instruction_t* pInst) {
David Neto78e677b2015-10-05 13:28:46 -0400232 const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
233 const bool is_floating = libspirv::isScalarFloating(type);
234 const bool is_integer = libspirv::isScalarIntegral(type);
235
236 if (!is_bottom && !is_floating && !is_integer) {
237 return diagnostic(SPV_ERROR_INTERNAL)
238 << "The expected type is not a scalar integer or float type";
239 }
240
241 // If this is bottom, but looks like a float, we should treat it like a
242 // float.
243 const bool looks_like_float = is_bottom && strchr(val, '.');
244
245 // If we explicitly expect a floating-point number, we should handle that
246 // first.
247 if (is_floating || looks_like_float)
David Neto51013d12015-10-14 11:31:51 -0400248 return binaryEncodeFloatingPointLiteral(val, error_code, type, pInst);
David Neto78e677b2015-10-05 13:28:46 -0400249
David Neto51013d12015-10-14 11:31:51 -0400250 return binaryEncodeIntegerLiteral(val, error_code, type, pInst);
David Neto78e677b2015-10-05 13:28:46 -0400251}
252
Lei Zhang1a0334e2015-11-02 09:41:20 -0500253spv_result_t AssemblyContext::binaryEncodeString(const char* value,
254 spv_instruction_t* pInst) {
David Netob5dc8fc2015-10-06 16:22:00 -0400255 const size_t length = strlen(value);
256 const size_t wordCount = (length / 4) + 1;
257 const size_t oldWordCount = pInst->words.size();
258 const size_t newWordCount = oldWordCount + wordCount;
259
260 // TODO(dneto): We can just defer this check until later.
261 if (newWordCount > SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX) {
David Neto78e677b2015-10-05 13:28:46 -0400262 return diagnostic() << "Instruction too long: more than "
263 << SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << " words.";
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400264 }
265
David Netob5dc8fc2015-10-06 16:22:00 -0400266 pInst->words.resize(newWordCount);
267
268 // Make sure all the bytes in the last word are 0, in case we only
269 // write a partial word at the end.
270 pInst->words.back() = 0;
271
Lei Zhang1a0334e2015-11-02 09:41:20 -0500272 char* dest = (char*)&pInst->words[oldWordCount];
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400273 strncpy(dest, value, length);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400274
275 return SPV_SUCCESS;
276}
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400277
278spv_result_t AssemblyContext::recordTypeDefinition(
Lei Zhang1a0334e2015-11-02 09:41:20 -0500279 const spv_instruction_t* pInst) {
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400280 uint32_t value = pInst->words[1];
281 if (types_.find(value) != types_.end()) {
Lei Zhang1a0334e2015-11-02 09:41:20 -0500282 return diagnostic() << "Value " << value
283 << " has already been used to generate a type";
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400284 }
285
Lei Zhangb36e7042015-10-28 13:40:52 -0400286 if (pInst->opcode == SpvOpTypeInt) {
David Neto78e677b2015-10-05 13:28:46 -0400287 if (pInst->words.size() != 4)
288 return diagnostic() << "Invalid OpTypeInt instruction";
289 types_[value] = {pInst->words[2], pInst->words[3] != 0,
290 IdTypeClass::kScalarIntegerType};
Lei Zhangb36e7042015-10-28 13:40:52 -0400291 } else if (pInst->opcode == SpvOpTypeFloat) {
David Neto78e677b2015-10-05 13:28:46 -0400292 if (pInst->words.size() != 3)
293 return diagnostic() << "Invalid OpTypeFloat instruction";
294 types_[value] = {pInst->words[2], false, IdTypeClass::kScalarFloatType};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400295 } else {
David Neto78e677b2015-10-05 13:28:46 -0400296 types_[value] = {0, false, IdTypeClass::kOtherType};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400297 }
298 return SPV_SUCCESS;
299}
300
301IdType AssemblyContext::getTypeOfTypeGeneratingValue(uint32_t value) const {
302 auto type = types_.find(value);
303 if (type == types_.end()) {
David Neto78e677b2015-10-05 13:28:46 -0400304 return kUnknownType;
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400305 }
306 return std::get<1>(*type);
307}
308
309IdType AssemblyContext::getTypeOfValueInstruction(uint32_t value) const {
310 auto type_value = value_types_.find(value);
311 if (type_value == value_types_.end()) {
Lei Zhang1a0334e2015-11-02 09:41:20 -0500312 return {0, false, IdTypeClass::kBottom};
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400313 }
314 return getTypeOfTypeGeneratingValue(std::get<1>(*type_value));
315}
316
317spv_result_t AssemblyContext::recordTypeIdForValue(uint32_t value,
318 uint32_t type) {
319 bool successfully_inserted = false;
320 std::tie(std::ignore, successfully_inserted) =
321 value_types_.insert(std::make_pair(value, type));
David Neto78e677b2015-10-05 13:28:46 -0400322 if (!successfully_inserted)
323 return diagnostic() << "Value is being defined a second time";
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400324 return SPV_SUCCESS;
325}
326
David Neto2ae4a682015-11-09 18:55:42 -0500327spv_result_t AssemblyContext::recordIdAsExtInstImport(
328 uint32_t id, spv_ext_inst_type_t type) {
329 bool successfully_inserted = false;
330 std::tie(std::ignore, successfully_inserted) =
331 import_id_to_ext_inst_type_.insert(std::make_pair(id, type));
332 if (!successfully_inserted)
333 return diagnostic() << "Import Id is being defined a second time";
334 return SPV_SUCCESS;
335}
336
337spv_ext_inst_type_t AssemblyContext::getExtInstTypeForId(uint32_t id) const {
338 auto type = import_id_to_ext_inst_type_.find(id);
339 if (type == import_id_to_ext_inst_type_.end()) {
340 return SPV_EXT_INST_TYPE_NONE;
341 }
342 return std::get<1>(*type);
343}
344
David Neto78e677b2015-10-05 13:28:46 -0400345spv_result_t AssemblyContext::binaryEncodeFloatingPointLiteral(
Lei Zhang1a0334e2015-11-02 09:41:20 -0500346 const char* val, spv_result_t error_code, const IdType& type,
347 spv_instruction_t* pInst) {
David Neto78e677b2015-10-05 13:28:46 -0400348 const auto bit_width = assumedBitWidth(type);
349 switch (bit_width) {
Andrew Woloszyn43401d22016-01-08 09:54:42 -0500350 case 16: {
351 spvutils::HexFloat<FloatProxy<spvutils::Float16>> hVal(0);
352 if (auto error = parseNumber(val, error_code, &hVal,
353 "Invalid 16-bit float literal: "))
354 return error;
355 // getAsFloat will return the spvutils::Float16 value, and get_value
356 // will return a uint16_t representing the bits of the float.
357 // The encoding is therefore correct from the perspective of the SPIR-V
358 // spec since the top 16 bits will be 0.
359 return binaryEncodeU32(
360 static_cast<uint32_t>(hVal.value().getAsFloat().get_value()), pInst);
361 } break;
David Neto78e677b2015-10-05 13:28:46 -0400362 case 32: {
David Neto9e545d72015-11-06 18:08:49 -0500363 spvutils::HexFloat<FloatProxy<float>> fVal(0.0f);
David Neto51013d12015-10-14 11:31:51 -0400364 if (auto error = parseNumber(val, error_code, &fVal,
David Neto78e677b2015-10-05 13:28:46 -0400365 "Invalid 32-bit float literal: "))
366 return error;
367 return binaryEncodeU32(BitwiseCast<uint32_t>(fVal), pInst);
368 } break;
369 case 64: {
David Neto9e545d72015-11-06 18:08:49 -0500370 spvutils::HexFloat<FloatProxy<double>> dVal(0.0);
David Neto51013d12015-10-14 11:31:51 -0400371 if (auto error = parseNumber(val, error_code, &dVal,
David Neto78e677b2015-10-05 13:28:46 -0400372 "Invalid 64-bit float literal: "))
373 return error;
374 return binaryEncodeU64(BitwiseCast<uint64_t>(dVal), pInst);
375 } break;
376 default:
377 break;
378 }
379 return diagnostic() << "Unsupported " << bit_width << "-bit float literals";
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400380}
381
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500382// Returns SPV_SUCCESS if the given value fits within the target scalar
383// integral type. The target type may have an unusual bit width.
384// If the value was originally specified as a hexadecimal number, then
385// the overflow bits should be zero. If it was hex and the target type is
386// signed, then return the sign-extended value through the
387// updated_value_for_hex pointer argument.
388// On failure, return the given error code and emit a diagnostic if that error
389// code is not SPV_FAILED_MATCH.
David Neto78e677b2015-10-05 13:28:46 -0400390template <typename T>
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500391spv_result_t checkRangeAndIfHexThenSignExtend(T value, spv_result_t error_code,
392 const IdType& type, bool is_hex,
393 T* updated_value_for_hex) {
David Neto78e677b2015-10-05 13:28:46 -0400394 // The encoded result has three regions of bits that are of interest, from
395 // least to most significant:
396 // - magnitude bits, where the magnitude of the number would be stored if
397 // we were using a signed-magnitude representation.
398 // - an optional sign bit
399 // - overflow bits, up to bit 63 of a 64-bit number
400 // For example:
401 // Type Overflow Sign Magnitude
402 // --------------- -------- ---- ---------
403 // unsigned 8 bit 8-63 n/a 0-7
404 // signed 8 bit 8-63 7 0-6
405 // unsigned 16 bit 16-63 n/a 0-15
406 // signed 16 bit 16-63 15 0-14
407
408 // We'll use masks to define the three regions.
409 // At first we'll assume the number is unsigned.
410 const uint32_t bit_width = assumedBitWidth(type);
411 uint64_t magnitude_mask =
412 (bit_width == 64) ? -1 : ((uint64_t(1) << bit_width) - 1);
413 uint64_t sign_mask = 0;
414 uint64_t overflow_mask = ~magnitude_mask;
415
416 if (value < 0 || type.isSigned) {
417 // Accommodate the sign bit.
418 magnitude_mask >>= 1;
419 sign_mask = magnitude_mask + 1;
420 }
421
422 bool failed = false;
423 if (value < 0) {
424 // The top bits must all be 1 for a negative signed value.
425 failed = ((value & overflow_mask) != overflow_mask) ||
426 ((value & sign_mask) != sign_mask);
427 } else {
428 if (is_hex) {
429 // Hex values are a bit special. They decode as unsigned values, but
430 // may represent a negative number. In this case, the overflow bits
431 // should be zero.
Ben Vanik01c8d7a2015-11-22 08:32:53 -0800432 failed = (value & overflow_mask) != 0;
David Neto78e677b2015-10-05 13:28:46 -0400433 } else {
Lei Zhang8bd75d62015-11-18 09:22:10 -0500434 const uint64_t value_as_u64 = static_cast<uint64_t>(value);
David Neto78e677b2015-10-05 13:28:46 -0400435 // Check overflow in the ordinary case.
Lei Zhang8bd75d62015-11-18 09:22:10 -0500436 failed = (value_as_u64 & magnitude_mask) != value_as_u64;
David Neto78e677b2015-10-05 13:28:46 -0400437 }
438 }
439
440 if (failed) {
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500441 return error_code;
David Neto78e677b2015-10-05 13:28:46 -0400442 }
443
444 // Sign extend hex the number.
445 if (is_hex && (value & sign_mask))
446 *updated_value_for_hex = (value | overflow_mask);
447
448 return SPV_SUCCESS;
449}
Andrew Woloszyn4ddb4312016-02-17 13:00:23 -0500450
451spv_result_t AssemblyContext::binaryEncodeIntegerLiteral(
452 const char* val, spv_result_t error_code, const IdType& type,
453 spv_instruction_t* pInst) {
454 const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
455 const uint32_t bit_width = assumedBitWidth(type);
456
457 if (bit_width > 64)
458 return diagnostic(SPV_ERROR_INTERNAL) << "Unsupported " << bit_width
459 << "-bit integer literals";
460
461 // Either we are expecting anything or integer.
462 bool is_negative = val[0] == '-';
463 bool can_be_signed = is_bottom || type.isSigned;
464
465 if (is_negative && !can_be_signed) {
466 return diagnostic()
467 << "Cannot put a negative number in an unsigned literal";
468 }
469
470 const bool is_hex = val[0] == '0' && (val[1] == 'x' || val[1] == 'X');
471
472 uint64_t decoded_bits;
473 if (is_negative) {
474 int64_t decoded_signed = 0;
475
476 if (auto error = parseNumber(val, error_code, &decoded_signed,
477 "Invalid signed integer literal: "))
478 return error;
479 if (auto error = checkRangeAndIfHexThenSignExtend(
480 decoded_signed, error_code, type, is_hex, &decoded_signed)) {
481 diagnostic(error_code)
482 << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
483 << decoded_signed << " does not fit in a " << std::dec << bit_width
484 << "-bit " << (type.isSigned ? "signed" : "unsigned") << " integer";
485 return error;
486 }
487 decoded_bits = decoded_signed;
488 } else {
489 // There's no leading minus sign, so parse it as an unsigned integer.
490 if (auto error = parseNumber(val, error_code, &decoded_bits,
491 "Invalid unsigned integer literal: "))
492 return error;
493 if (auto error = checkRangeAndIfHexThenSignExtend(
494 decoded_bits, error_code, type, is_hex, &decoded_bits)) {
495 diagnostic(error_code)
496 << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
497 << decoded_bits << " does not fit in a " << std::dec << bit_width
498 << "-bit " << (type.isSigned ? "signed" : "unsigned") << " integer";
499 return error;
500 }
501 }
502 if (bit_width > 32) {
503 return binaryEncodeU64(decoded_bits, pInst);
504 } else {
505 return binaryEncodeU32(uint32_t(decoded_bits), pInst);
506 }
507}
Lei Zhang1a0334e2015-11-02 09:41:20 -0500508} // namespace libspirv