File: | build/source/mlir/lib/AsmParser/TypeParser.cpp |
Warning: | line 522, column 7 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- TypeParser.cpp - MLIR Type Parser Implementation -------------------===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | // | |||
9 | // This file implements the parser for the MLIR Types. | |||
10 | // | |||
11 | //===----------------------------------------------------------------------===// | |||
12 | ||||
13 | #include "Parser.h" | |||
14 | #include "mlir/IR/AffineMap.h" | |||
15 | #include "mlir/IR/BuiltinTypes.h" | |||
16 | #include "mlir/IR/OpDefinition.h" | |||
17 | #include "mlir/IR/TensorEncoding.h" | |||
18 | ||||
19 | using namespace mlir; | |||
20 | using namespace mlir::detail; | |||
21 | ||||
22 | /// Optionally parse a type. | |||
23 | OptionalParseResult Parser::parseOptionalType(Type &type) { | |||
24 | // There are many different starting tokens for a type, check them here. | |||
25 | switch (getToken().getKind()) { | |||
26 | case Token::l_paren: | |||
27 | case Token::kw_memref: | |||
28 | case Token::kw_tensor: | |||
29 | case Token::kw_complex: | |||
30 | case Token::kw_tuple: | |||
31 | case Token::kw_vector: | |||
32 | case Token::inttype: | |||
33 | case Token::kw_f8E5M2: | |||
34 | case Token::kw_f8E4M3FN: | |||
35 | case Token::kw_bf16: | |||
36 | case Token::kw_f16: | |||
37 | case Token::kw_f32: | |||
38 | case Token::kw_f64: | |||
39 | case Token::kw_f80: | |||
40 | case Token::kw_f128: | |||
41 | case Token::kw_index: | |||
42 | case Token::kw_none: | |||
43 | case Token::exclamation_identifier: | |||
44 | return failure(!(type = parseType())); | |||
45 | ||||
46 | default: | |||
47 | return std::nullopt; | |||
48 | } | |||
49 | } | |||
50 | ||||
51 | /// Parse an arbitrary type. | |||
52 | /// | |||
53 | /// type ::= function-type | |||
54 | /// | non-function-type | |||
55 | /// | |||
56 | Type Parser::parseType() { | |||
57 | if (getToken().is(Token::l_paren)) | |||
58 | return parseFunctionType(); | |||
59 | return parseNonFunctionType(); | |||
60 | } | |||
61 | ||||
62 | /// Parse a function result type. | |||
63 | /// | |||
64 | /// function-result-type ::= type-list-parens | |||
65 | /// | non-function-type | |||
66 | /// | |||
67 | ParseResult Parser::parseFunctionResultTypes(SmallVectorImpl<Type> &elements) { | |||
68 | if (getToken().is(Token::l_paren)) | |||
69 | return parseTypeListParens(elements); | |||
70 | ||||
71 | Type t = parseNonFunctionType(); | |||
72 | if (!t) | |||
73 | return failure(); | |||
74 | elements.push_back(t); | |||
75 | return success(); | |||
76 | } | |||
77 | ||||
78 | /// Parse a list of types without an enclosing parenthesis. The list must have | |||
79 | /// at least one member. | |||
80 | /// | |||
81 | /// type-list-no-parens ::= type (`,` type)* | |||
82 | /// | |||
83 | ParseResult Parser::parseTypeListNoParens(SmallVectorImpl<Type> &elements) { | |||
84 | auto parseElt = [&]() -> ParseResult { | |||
85 | auto elt = parseType(); | |||
86 | elements.push_back(elt); | |||
87 | return elt ? success() : failure(); | |||
88 | }; | |||
89 | ||||
90 | return parseCommaSeparatedList(parseElt); | |||
91 | } | |||
92 | ||||
93 | /// Parse a parenthesized list of types. | |||
94 | /// | |||
95 | /// type-list-parens ::= `(` `)` | |||
96 | /// | `(` type-list-no-parens `)` | |||
97 | /// | |||
98 | ParseResult Parser::parseTypeListParens(SmallVectorImpl<Type> &elements) { | |||
99 | if (parseToken(Token::l_paren, "expected '('")) | |||
100 | return failure(); | |||
101 | ||||
102 | // Handle empty lists. | |||
103 | if (getToken().is(Token::r_paren)) | |||
104 | return consumeToken(), success(); | |||
105 | ||||
106 | if (parseTypeListNoParens(elements) || | |||
107 | parseToken(Token::r_paren, "expected ')'")) | |||
108 | return failure(); | |||
109 | return success(); | |||
110 | } | |||
111 | ||||
112 | /// Parse a complex type. | |||
113 | /// | |||
114 | /// complex-type ::= `complex` `<` type `>` | |||
115 | /// | |||
116 | Type Parser::parseComplexType() { | |||
117 | consumeToken(Token::kw_complex); | |||
118 | ||||
119 | // Parse the '<'. | |||
120 | if (parseToken(Token::less, "expected '<' in complex type")) | |||
121 | return nullptr; | |||
122 | ||||
123 | SMLoc elementTypeLoc = getToken().getLoc(); | |||
124 | auto elementType = parseType(); | |||
125 | if (!elementType || | |||
126 | parseToken(Token::greater, "expected '>' in complex type")) | |||
127 | return nullptr; | |||
128 | if (!elementType.isa<FloatType>() && !elementType.isa<IntegerType>()) | |||
129 | return emitError(elementTypeLoc, "invalid element type for complex"), | |||
130 | nullptr; | |||
131 | ||||
132 | return ComplexType::get(elementType); | |||
133 | } | |||
134 | ||||
135 | /// Parse a function type. | |||
136 | /// | |||
137 | /// function-type ::= type-list-parens `->` function-result-type | |||
138 | /// | |||
139 | Type Parser::parseFunctionType() { | |||
140 | assert(getToken().is(Token::l_paren))(static_cast <bool> (getToken().is(Token::l_paren)) ? void (0) : __assert_fail ("getToken().is(Token::l_paren)", "mlir/lib/AsmParser/TypeParser.cpp" , 140, __extension__ __PRETTY_FUNCTION__)); | |||
141 | ||||
142 | SmallVector<Type, 4> arguments, results; | |||
143 | if (parseTypeListParens(arguments) || | |||
144 | parseToken(Token::arrow, "expected '->' in function type") || | |||
145 | parseFunctionResultTypes(results)) | |||
146 | return nullptr; | |||
147 | ||||
148 | return builder.getFunctionType(arguments, results); | |||
149 | } | |||
150 | ||||
151 | /// Parse a memref type. | |||
152 | /// | |||
153 | /// memref-type ::= ranked-memref-type | unranked-memref-type | |||
154 | /// | |||
155 | /// ranked-memref-type ::= `memref` `<` dimension-list-ranked type | |||
156 | /// (`,` layout-specification)? (`,` memory-space)? `>` | |||
157 | /// | |||
158 | /// unranked-memref-type ::= `memref` `<*x` type (`,` memory-space)? `>` | |||
159 | /// | |||
160 | /// stride-list ::= `[` (dimension (`,` dimension)*)? `]` | |||
161 | /// strided-layout ::= `offset:` dimension `,` `strides: ` stride-list | |||
162 | /// layout-specification ::= semi-affine-map | strided-layout | attribute | |||
163 | /// memory-space ::= integer-literal | attribute | |||
164 | /// | |||
165 | Type Parser::parseMemRefType() { | |||
166 | SMLoc loc = getToken().getLoc(); | |||
167 | consumeToken(Token::kw_memref); | |||
168 | ||||
169 | if (parseToken(Token::less, "expected '<' in memref type")) | |||
170 | return nullptr; | |||
171 | ||||
172 | bool isUnranked; | |||
173 | SmallVector<int64_t, 4> dimensions; | |||
174 | ||||
175 | if (consumeIf(Token::star)) { | |||
176 | // This is an unranked memref type. | |||
177 | isUnranked = true; | |||
178 | if (parseXInDimensionList()) | |||
179 | return nullptr; | |||
180 | ||||
181 | } else { | |||
182 | isUnranked = false; | |||
183 | if (parseDimensionListRanked(dimensions)) | |||
184 | return nullptr; | |||
185 | } | |||
186 | ||||
187 | // Parse the element type. | |||
188 | auto typeLoc = getToken().getLoc(); | |||
189 | auto elementType = parseType(); | |||
190 | if (!elementType) | |||
191 | return nullptr; | |||
192 | ||||
193 | // Check that memref is formed from allowed types. | |||
194 | if (!BaseMemRefType::isValidElementType(elementType)) | |||
195 | return emitError(typeLoc, "invalid memref element type"), nullptr; | |||
196 | ||||
197 | MemRefLayoutAttrInterface layout; | |||
198 | Attribute memorySpace; | |||
199 | ||||
200 | auto parseElt = [&]() -> ParseResult { | |||
201 | // Either it is MemRefLayoutAttrInterface or memory space attribute. | |||
202 | Attribute attr = parseAttribute(); | |||
203 | if (!attr) | |||
204 | return failure(); | |||
205 | ||||
206 | if (attr.isa<MemRefLayoutAttrInterface>()) { | |||
207 | layout = attr.cast<MemRefLayoutAttrInterface>(); | |||
208 | } else if (memorySpace) { | |||
209 | return emitError("multiple memory spaces specified in memref type"); | |||
210 | } else { | |||
211 | memorySpace = attr; | |||
212 | return success(); | |||
213 | } | |||
214 | ||||
215 | if (isUnranked) | |||
216 | return emitError("cannot have affine map for unranked memref type"); | |||
217 | if (memorySpace) | |||
218 | return emitError("expected memory space to be last in memref type"); | |||
219 | ||||
220 | return success(); | |||
221 | }; | |||
222 | ||||
223 | // Parse a list of mappings and address space if present. | |||
224 | if (!consumeIf(Token::greater)) { | |||
225 | // Parse comma separated list of affine maps, followed by memory space. | |||
226 | if (parseToken(Token::comma, "expected ',' or '>' in memref type") || | |||
227 | parseCommaSeparatedListUntil(Token::greater, parseElt, | |||
228 | /*allowEmptyList=*/false)) { | |||
229 | return nullptr; | |||
230 | } | |||
231 | } | |||
232 | ||||
233 | if (isUnranked) | |||
234 | return getChecked<UnrankedMemRefType>(loc, elementType, memorySpace); | |||
235 | ||||
236 | return getChecked<MemRefType>(loc, dimensions, elementType, layout, | |||
237 | memorySpace); | |||
238 | } | |||
239 | ||||
240 | /// Parse any type except the function type. | |||
241 | /// | |||
242 | /// non-function-type ::= integer-type | |||
243 | /// | index-type | |||
244 | /// | float-type | |||
245 | /// | extended-type | |||
246 | /// | vector-type | |||
247 | /// | tensor-type | |||
248 | /// | memref-type | |||
249 | /// | complex-type | |||
250 | /// | tuple-type | |||
251 | /// | none-type | |||
252 | /// | |||
253 | /// index-type ::= `index` | |||
254 | /// float-type ::= `f16` | `bf16` | `f32` | `f64` | `f80` | `f128` | |||
255 | /// none-type ::= `none` | |||
256 | /// | |||
257 | Type Parser::parseNonFunctionType() { | |||
258 | switch (getToken().getKind()) { | |||
259 | default: | |||
260 | return (emitWrongTokenError("expected non-function type"), nullptr); | |||
261 | case Token::kw_memref: | |||
262 | return parseMemRefType(); | |||
263 | case Token::kw_tensor: | |||
264 | return parseTensorType(); | |||
265 | case Token::kw_complex: | |||
266 | return parseComplexType(); | |||
267 | case Token::kw_tuple: | |||
268 | return parseTupleType(); | |||
269 | case Token::kw_vector: | |||
270 | return parseVectorType(); | |||
271 | // integer-type | |||
272 | case Token::inttype: { | |||
273 | auto width = getToken().getIntTypeBitwidth(); | |||
274 | if (!width.has_value()) | |||
275 | return (emitError("invalid integer width"), nullptr); | |||
276 | if (*width > IntegerType::kMaxWidth) { | |||
277 | emitError(getToken().getLoc(), "integer bitwidth is limited to ") | |||
278 | << IntegerType::kMaxWidth << " bits"; | |||
279 | return nullptr; | |||
280 | } | |||
281 | ||||
282 | IntegerType::SignednessSemantics signSemantics = IntegerType::Signless; | |||
283 | if (Optional<bool> signedness = getToken().getIntTypeSignedness()) | |||
284 | signSemantics = *signedness ? IntegerType::Signed : IntegerType::Unsigned; | |||
285 | ||||
286 | consumeToken(Token::inttype); | |||
287 | return IntegerType::get(getContext(), *width, signSemantics); | |||
288 | } | |||
289 | ||||
290 | // float-type | |||
291 | case Token::kw_f8E5M2: | |||
292 | consumeToken(Token::kw_f8E5M2); | |||
293 | return builder.getFloat8E5M2Type(); | |||
294 | case Token::kw_f8E4M3FN: | |||
295 | consumeToken(Token::kw_f8E4M3FN); | |||
296 | return builder.getFloat8E4M3FNType(); | |||
297 | case Token::kw_bf16: | |||
298 | consumeToken(Token::kw_bf16); | |||
299 | return builder.getBF16Type(); | |||
300 | case Token::kw_f16: | |||
301 | consumeToken(Token::kw_f16); | |||
302 | return builder.getF16Type(); | |||
303 | case Token::kw_f32: | |||
304 | consumeToken(Token::kw_f32); | |||
305 | return builder.getF32Type(); | |||
306 | case Token::kw_f64: | |||
307 | consumeToken(Token::kw_f64); | |||
308 | return builder.getF64Type(); | |||
309 | case Token::kw_f80: | |||
310 | consumeToken(Token::kw_f80); | |||
311 | return builder.getF80Type(); | |||
312 | case Token::kw_f128: | |||
313 | consumeToken(Token::kw_f128); | |||
314 | return builder.getF128Type(); | |||
315 | ||||
316 | // index-type | |||
317 | case Token::kw_index: | |||
318 | consumeToken(Token::kw_index); | |||
319 | return builder.getIndexType(); | |||
320 | ||||
321 | // none-type | |||
322 | case Token::kw_none: | |||
323 | consumeToken(Token::kw_none); | |||
324 | return builder.getNoneType(); | |||
325 | ||||
326 | // extended type | |||
327 | case Token::exclamation_identifier: | |||
328 | return parseExtendedType(); | |||
329 | ||||
330 | // Handle completion of a dialect type. | |||
331 | case Token::code_complete: | |||
332 | if (getToken().isCodeCompletionFor(Token::exclamation_identifier)) | |||
333 | return parseExtendedType(); | |||
334 | return codeCompleteType(); | |||
335 | } | |||
336 | } | |||
337 | ||||
338 | /// Parse a tensor type. | |||
339 | /// | |||
340 | /// tensor-type ::= `tensor` `<` dimension-list type `>` | |||
341 | /// dimension-list ::= dimension-list-ranked | `*x` | |||
342 | /// | |||
343 | Type Parser::parseTensorType() { | |||
344 | consumeToken(Token::kw_tensor); | |||
345 | ||||
346 | if (parseToken(Token::less, "expected '<' in tensor type")) | |||
347 | return nullptr; | |||
348 | ||||
349 | bool isUnranked; | |||
350 | SmallVector<int64_t, 4> dimensions; | |||
351 | ||||
352 | if (consumeIf(Token::star)) { | |||
353 | // This is an unranked tensor type. | |||
354 | isUnranked = true; | |||
355 | ||||
356 | if (parseXInDimensionList()) | |||
357 | return nullptr; | |||
358 | ||||
359 | } else { | |||
360 | isUnranked = false; | |||
361 | if (parseDimensionListRanked(dimensions)) | |||
362 | return nullptr; | |||
363 | } | |||
364 | ||||
365 | // Parse the element type. | |||
366 | auto elementTypeLoc = getToken().getLoc(); | |||
367 | auto elementType = parseType(); | |||
368 | ||||
369 | // Parse an optional encoding attribute. | |||
370 | Attribute encoding; | |||
371 | if (consumeIf(Token::comma)) { | |||
372 | encoding = parseAttribute(); | |||
373 | if (auto v = encoding.dyn_cast_or_null<VerifiableTensorEncoding>()) { | |||
374 | if (failed(v.verifyEncoding(dimensions, elementType, | |||
375 | [&] { return emitError(); }))) | |||
376 | return nullptr; | |||
377 | } | |||
378 | } | |||
379 | ||||
380 | if (!elementType || parseToken(Token::greater, "expected '>' in tensor type")) | |||
381 | return nullptr; | |||
382 | if (!TensorType::isValidElementType(elementType)) | |||
383 | return emitError(elementTypeLoc, "invalid tensor element type"), nullptr; | |||
384 | ||||
385 | if (isUnranked) { | |||
386 | if (encoding) | |||
387 | return emitError("cannot apply encoding to unranked tensor"), nullptr; | |||
388 | return UnrankedTensorType::get(elementType); | |||
389 | } | |||
390 | return RankedTensorType::get(dimensions, elementType, encoding); | |||
391 | } | |||
392 | ||||
393 | /// Parse a tuple type. | |||
394 | /// | |||
395 | /// tuple-type ::= `tuple` `<` (type (`,` type)*)? `>` | |||
396 | /// | |||
397 | Type Parser::parseTupleType() { | |||
398 | consumeToken(Token::kw_tuple); | |||
399 | ||||
400 | // Parse the '<'. | |||
401 | if (parseToken(Token::less, "expected '<' in tuple type")) | |||
402 | return nullptr; | |||
403 | ||||
404 | // Check for an empty tuple by directly parsing '>'. | |||
405 | if (consumeIf(Token::greater)) | |||
406 | return TupleType::get(getContext()); | |||
407 | ||||
408 | // Parse the element types and the '>'. | |||
409 | SmallVector<Type, 4> types; | |||
410 | if (parseTypeListNoParens(types) || | |||
411 | parseToken(Token::greater, "expected '>' in tuple type")) | |||
412 | return nullptr; | |||
413 | ||||
414 | return TupleType::get(getContext(), types); | |||
415 | } | |||
416 | ||||
417 | /// Parse a vector type. | |||
418 | /// | |||
419 | /// vector-type ::= `vector` `<` vector-dim-list vector-element-type `>` | |||
420 | /// vector-dim-list := (static-dim-list `x`)? (`[` static-dim-list `]` `x`)? | |||
421 | /// static-dim-list ::= decimal-literal (`x` decimal-literal)* | |||
422 | /// | |||
423 | VectorType Parser::parseVectorType() { | |||
424 | consumeToken(Token::kw_vector); | |||
425 | ||||
426 | if (parseToken(Token::less, "expected '<' in vector type")) | |||
427 | return nullptr; | |||
428 | ||||
429 | SmallVector<int64_t, 4> dimensions; | |||
430 | unsigned numScalableDims; | |||
431 | if (parseVectorDimensionList(dimensions, numScalableDims)) | |||
432 | return nullptr; | |||
433 | if (any_of(dimensions, [](int64_t i) { return i <= 0; })) | |||
434 | return emitError(getToken().getLoc(), | |||
435 | "vector types must have positive constant sizes"), | |||
436 | nullptr; | |||
437 | ||||
438 | // Parse the element type. | |||
439 | auto typeLoc = getToken().getLoc(); | |||
440 | auto elementType = parseType(); | |||
441 | if (!elementType || parseToken(Token::greater, "expected '>' in vector type")) | |||
442 | return nullptr; | |||
443 | ||||
444 | if (!VectorType::isValidElementType(elementType)) | |||
445 | return emitError(typeLoc, "vector elements must be int/index/float type"), | |||
446 | nullptr; | |||
447 | ||||
448 | return VectorType::get(dimensions, elementType, numScalableDims); | |||
449 | } | |||
450 | ||||
451 | /// Parse a dimension list in a vector type. This populates the dimension list, | |||
452 | /// and returns the number of scalable dimensions in `numScalableDims`. | |||
453 | /// | |||
454 | /// vector-dim-list := (static-dim-list `x`)? (`[` static-dim-list `]` `x`)? | |||
455 | /// static-dim-list ::= decimal-literal (`x` decimal-literal)* | |||
456 | /// | |||
457 | ParseResult | |||
458 | Parser::parseVectorDimensionList(SmallVectorImpl<int64_t> &dimensions, | |||
459 | unsigned &numScalableDims) { | |||
460 | numScalableDims = 0; | |||
461 | // If there is a set of fixed-length dimensions, consume it | |||
462 | while (getToken().is(Token::integer)) { | |||
463 | int64_t value; | |||
464 | if (parseIntegerInDimensionList(value)) | |||
465 | return failure(); | |||
466 | dimensions.push_back(value); | |||
467 | // Make sure we have an 'x' or something like 'xbf32'. | |||
468 | if (parseXInDimensionList()) | |||
469 | return failure(); | |||
470 | } | |||
471 | // If there is a set of scalable dimensions, consume it | |||
472 | if (consumeIf(Token::l_square)) { | |||
473 | while (getToken().is(Token::integer)) { | |||
474 | int64_t value; | |||
475 | if (parseIntegerInDimensionList(value)) | |||
476 | return failure(); | |||
477 | dimensions.push_back(value); | |||
478 | numScalableDims++; | |||
479 | // Check if we have reached the end of the scalable dimension list | |||
480 | if (consumeIf(Token::r_square)) { | |||
481 | // Make sure we have something like 'xbf32'. | |||
482 | return parseXInDimensionList(); | |||
483 | } | |||
484 | // Make sure we have an 'x' | |||
485 | if (parseXInDimensionList()) | |||
486 | return failure(); | |||
487 | } | |||
488 | // If we make it here, we've finished parsing the dimension list | |||
489 | // without finding ']' closing the set of scalable dimensions | |||
490 | return emitWrongTokenError( | |||
491 | "missing ']' closing set of scalable dimensions"); | |||
492 | } | |||
493 | ||||
494 | return success(); | |||
495 | } | |||
496 | ||||
497 | /// Parse a dimension list of a tensor or memref type. This populates the | |||
498 | /// dimension list, using -1 for the `?` dimensions if `allowDynamic` is set and | |||
499 | /// errors out on `?` otherwise. Parsing the trailing `x` is configurable. | |||
500 | /// | |||
501 | /// dimension-list ::= eps | dimension (`x` dimension)* | |||
502 | /// dimension-list-with-trailing-x ::= (dimension `x`)* | |||
503 | /// dimension ::= `?` | decimal-literal | |||
504 | /// | |||
505 | /// When `allowDynamic` is not set, this is used to parse: | |||
506 | /// | |||
507 | /// static-dimension-list ::= eps | decimal-literal (`x` decimal-literal)* | |||
508 | /// static-dimension-list-with-trailing-x ::= (dimension `x`)* | |||
509 | ParseResult | |||
510 | Parser::parseDimensionListRanked(SmallVectorImpl<int64_t> &dimensions, | |||
511 | bool allowDynamic, bool withTrailingX) { | |||
512 | auto parseDim = [&]() -> LogicalResult { | |||
513 | auto loc = getToken().getLoc(); | |||
514 | if (consumeIf(Token::question)) { | |||
| ||||
515 | if (!allowDynamic) | |||
516 | return emitError(loc, "expected static shape"); | |||
517 | dimensions.push_back(ShapedType::kDynamic); | |||
518 | } else { | |||
519 | int64_t value; | |||
520 | if (failed(parseIntegerInDimensionList(value))) | |||
521 | return failure(); | |||
522 | dimensions.push_back(value); | |||
| ||||
523 | } | |||
524 | return success(); | |||
525 | }; | |||
526 | ||||
527 | if (withTrailingX) { | |||
528 | while (getToken().isAny(Token::integer, Token::question)) { | |||
529 | if (failed(parseDim()) || failed(parseXInDimensionList())) | |||
530 | return failure(); | |||
531 | } | |||
532 | return success(); | |||
533 | } | |||
534 | ||||
535 | if (getToken().isAny(Token::integer, Token::question)) { | |||
536 | if (failed(parseDim())) | |||
537 | return failure(); | |||
538 | while (getToken().is(Token::bare_identifier) && | |||
539 | getTokenSpelling()[0] == 'x') { | |||
540 | if (failed(parseXInDimensionList()) || failed(parseDim())) | |||
541 | return failure(); | |||
542 | } | |||
543 | } | |||
544 | return success(); | |||
545 | } | |||
546 | ||||
547 | ParseResult Parser::parseIntegerInDimensionList(int64_t &value) { | |||
548 | // Hexadecimal integer literals (starting with `0x`) are not allowed in | |||
549 | // aggregate type declarations. Therefore, `0xf32` should be processed as | |||
550 | // a sequence of separate elements `0`, `x`, `f32`. | |||
551 | if (getTokenSpelling().size() > 1 && getTokenSpelling()[1] == 'x') { | |||
552 | // We can get here only if the token is an integer literal. Hexadecimal | |||
553 | // integer literals can only start with `0x` (`1x` wouldn't lex as a | |||
554 | // literal, just `1` would, at which point we don't get into this | |||
555 | // branch). | |||
556 | assert(getTokenSpelling()[0] == '0' && "invalid integer literal")(static_cast <bool> (getTokenSpelling()[0] == '0' && "invalid integer literal") ? void (0) : __assert_fail ("getTokenSpelling()[0] == '0' && \"invalid integer literal\"" , "mlir/lib/AsmParser/TypeParser.cpp", 556, __extension__ __PRETTY_FUNCTION__ )); | |||
557 | value = 0; | |||
558 | state.lex.resetPointer(getTokenSpelling().data() + 1); | |||
559 | consumeToken(); | |||
560 | } else { | |||
561 | // Make sure this integer value is in bound and valid. | |||
562 | Optional<uint64_t> dimension = getToken().getUInt64IntegerValue(); | |||
563 | if (!dimension || | |||
564 | *dimension > (uint64_t)std::numeric_limits<int64_t>::max()) | |||
565 | return emitError("invalid dimension"); | |||
566 | value = (int64_t)*dimension; | |||
567 | consumeToken(Token::integer); | |||
568 | } | |||
569 | return success(); | |||
570 | } | |||
571 | ||||
572 | /// Parse an 'x' token in a dimension list, handling the case where the x is | |||
573 | /// juxtaposed with an element type, as in "xf32", leaving the "f32" as the next | |||
574 | /// token. | |||
575 | ParseResult Parser::parseXInDimensionList() { | |||
576 | if (getToken().isNot(Token::bare_identifier) || getTokenSpelling()[0] != 'x') | |||
577 | return emitWrongTokenError("expected 'x' in dimension list"); | |||
578 | ||||
579 | // If we had a prefix of 'x', lex the next token immediately after the 'x'. | |||
580 | if (getTokenSpelling().size() != 1) | |||
581 | state.lex.resetPointer(getTokenSpelling().data() + 1); | |||
582 | ||||
583 | // Consume the 'x'. | |||
584 | consumeToken(Token::bare_identifier); | |||
585 | ||||
586 | return success(); | |||
587 | } |