1//===- Parser.cpp - MLIR 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 textual form.
10//
11//===----------------------------------------------------------------------===//
12
13#include "Parser.h"
14#include "AsmParserImpl.h"
15#include "mlir/AsmParser/AsmParser.h"
16#include "mlir/AsmParser/AsmParserState.h"
17#include "mlir/AsmParser/CodeComplete.h"
18#include "mlir/IR/AffineExpr.h"
19#include "mlir/IR/AffineMap.h"
20#include "mlir/IR/AsmState.h"
21#include "mlir/IR/Attributes.h"
22#include "mlir/IR/BuiltinAttributes.h"
23#include "mlir/IR/BuiltinOps.h"
24#include "mlir/IR/BuiltinTypes.h"
25#include "mlir/IR/Diagnostics.h"
26#include "mlir/IR/Dialect.h"
27#include "mlir/IR/Location.h"
28#include "mlir/IR/OpDefinition.h"
29#include "mlir/IR/OpImplementation.h"
30#include "mlir/IR/OperationSupport.h"
31#include "mlir/IR/OwningOpRef.h"
32#include "mlir/IR/Region.h"
33#include "mlir/IR/Value.h"
34#include "mlir/IR/Verifier.h"
35#include "mlir/IR/Visitors.h"
36#include "mlir/Support/LLVM.h"
37#include "mlir/Support/LogicalResult.h"
38#include "mlir/Support/TypeID.h"
39#include "llvm/ADT/APFloat.h"
40#include "llvm/ADT/DenseMap.h"
41#include "llvm/ADT/PointerUnion.h"
42#include "llvm/ADT/STLExtras.h"
43#include "llvm/ADT/ScopeExit.h"
44#include "llvm/ADT/Sequence.h"
45#include "llvm/ADT/StringMap.h"
46#include "llvm/ADT/StringSet.h"
47#include "llvm/Support/Alignment.h"
48#include "llvm/Support/Casting.h"
49#include "llvm/Support/Endian.h"
50#include "llvm/Support/ErrorHandling.h"
51#include "llvm/Support/MathExtras.h"
52#include "llvm/Support/PrettyStackTrace.h"
53#include "llvm/Support/SourceMgr.h"
54#include "llvm/Support/raw_ostream.h"
55#include <algorithm>
56#include <cassert>
57#include <cstddef>
58#include <cstdint>
59#include <cstring>
60#include <memory>
61#include <optional>
62#include <string>
63#include <tuple>
64#include <utility>
65#include <vector>
66
67using namespace mlir;
68using namespace mlir::detail;
69
70//===----------------------------------------------------------------------===//
71// CodeComplete
72//===----------------------------------------------------------------------===//
73
74AsmParserCodeCompleteContext::~AsmParserCodeCompleteContext() = default;
75
76//===----------------------------------------------------------------------===//
77// Parser
78//===----------------------------------------------------------------------===//
79
80/// Parse a list of comma-separated items with an optional delimiter. If a
81/// delimiter is provided, then an empty list is allowed. If not, then at
82/// least one element will be parsed.
83ParseResult
84Parser::parseCommaSeparatedList(Delimiter delimiter,
85 function_ref<ParseResult()> parseElementFn,
86 StringRef contextMessage) {
87 switch (delimiter) {
88 case Delimiter::None:
89 break;
90 case Delimiter::OptionalParen:
91 if (getToken().isNot(k: Token::l_paren))
92 return success();
93 [[fallthrough]];
94 case Delimiter::Paren:
95 if (parseToken(expectedToken: Token::l_paren, message: "expected '('" + contextMessage))
96 return failure();
97 // Check for empty list.
98 if (consumeIf(kind: Token::r_paren))
99 return success();
100 break;
101 case Delimiter::OptionalLessGreater:
102 // Check for absent list.
103 if (getToken().isNot(k: Token::less))
104 return success();
105 [[fallthrough]];
106 case Delimiter::LessGreater:
107 if (parseToken(expectedToken: Token::less, message: "expected '<'" + contextMessage))
108 return success();
109 // Check for empty list.
110 if (consumeIf(kind: Token::greater))
111 return success();
112 break;
113 case Delimiter::OptionalSquare:
114 if (getToken().isNot(k: Token::l_square))
115 return success();
116 [[fallthrough]];
117 case Delimiter::Square:
118 if (parseToken(expectedToken: Token::l_square, message: "expected '['" + contextMessage))
119 return failure();
120 // Check for empty list.
121 if (consumeIf(kind: Token::r_square))
122 return success();
123 break;
124 case Delimiter::OptionalBraces:
125 if (getToken().isNot(k: Token::l_brace))
126 return success();
127 [[fallthrough]];
128 case Delimiter::Braces:
129 if (parseToken(expectedToken: Token::l_brace, message: "expected '{'" + contextMessage))
130 return failure();
131 // Check for empty list.
132 if (consumeIf(kind: Token::r_brace))
133 return success();
134 break;
135 }
136
137 // Non-empty case starts with an element.
138 if (parseElementFn())
139 return failure();
140
141 // Otherwise we have a list of comma separated elements.
142 while (consumeIf(kind: Token::comma)) {
143 if (parseElementFn())
144 return failure();
145 }
146
147 switch (delimiter) {
148 case Delimiter::None:
149 return success();
150 case Delimiter::OptionalParen:
151 case Delimiter::Paren:
152 return parseToken(expectedToken: Token::r_paren, message: "expected ')'" + contextMessage);
153 case Delimiter::OptionalLessGreater:
154 case Delimiter::LessGreater:
155 return parseToken(expectedToken: Token::greater, message: "expected '>'" + contextMessage);
156 case Delimiter::OptionalSquare:
157 case Delimiter::Square:
158 return parseToken(expectedToken: Token::r_square, message: "expected ']'" + contextMessage);
159 case Delimiter::OptionalBraces:
160 case Delimiter::Braces:
161 return parseToken(expectedToken: Token::r_brace, message: "expected '}'" + contextMessage);
162 }
163 llvm_unreachable("Unknown delimiter");
164}
165
166/// Parse a comma-separated list of elements, terminated with an arbitrary
167/// token. This allows empty lists if allowEmptyList is true.
168///
169/// abstract-list ::= rightToken // if allowEmptyList == true
170/// abstract-list ::= element (',' element)* rightToken
171///
172ParseResult
173Parser::parseCommaSeparatedListUntil(Token::Kind rightToken,
174 function_ref<ParseResult()> parseElement,
175 bool allowEmptyList) {
176 // Handle the empty case.
177 if (getToken().is(k: rightToken)) {
178 if (!allowEmptyList)
179 return emitWrongTokenError(message: "expected list element");
180 consumeToken(kind: rightToken);
181 return success();
182 }
183
184 if (parseCommaSeparatedList(parseElementFn: parseElement) ||
185 parseToken(expectedToken: rightToken, message: "expected ',' or '" +
186 Token::getTokenSpelling(kind: rightToken) + "'"))
187 return failure();
188
189 return success();
190}
191
192InFlightDiagnostic Parser::emitError(const Twine &message) {
193 auto loc = state.curToken.getLoc();
194 if (state.curToken.isNot(k: Token::eof))
195 return emitError(loc, message);
196
197 // If the error is to be emitted at EOF, move it back one character.
198 return emitError(loc: SMLoc::getFromPointer(Ptr: loc.getPointer() - 1), message);
199}
200
201InFlightDiagnostic Parser::emitError(SMLoc loc, const Twine &message) {
202 auto diag = mlir::emitError(loc: getEncodedSourceLocation(loc), message);
203
204 // If we hit a parse error in response to a lexer error, then the lexer
205 // already reported the error.
206 if (getToken().is(k: Token::error))
207 diag.abandon();
208 return diag;
209}
210
211/// Emit an error about a "wrong token". If the current token is at the
212/// start of a source line, this will apply heuristics to back up and report
213/// the error at the end of the previous line, which is where the expected
214/// token is supposed to be.
215InFlightDiagnostic Parser::emitWrongTokenError(const Twine &message) {
216 auto loc = state.curToken.getLoc();
217
218 // If the error is to be emitted at EOF, move it back one character.
219 if (state.curToken.is(k: Token::eof))
220 loc = SMLoc::getFromPointer(Ptr: loc.getPointer() - 1);
221
222 // This is the location we were originally asked to report the error at.
223 auto originalLoc = loc;
224
225 // Determine if the token is at the start of the current line.
226 const char *bufferStart = state.lex.getBufferBegin();
227 const char *curPtr = loc.getPointer();
228
229 // Use this StringRef to keep track of what we are going to back up through,
230 // it provides nicer string search functions etc.
231 StringRef startOfBuffer(bufferStart, curPtr - bufferStart);
232
233 // Back up over entirely blank lines.
234 while (true) {
235 // Back up until we see a \n, but don't look past the buffer start.
236 startOfBuffer = startOfBuffer.rtrim(Chars: " \t");
237
238 // For tokens with no preceding source line, just emit at the original
239 // location.
240 if (startOfBuffer.empty())
241 return emitError(loc: originalLoc, message);
242
243 // If we found something that isn't the end of line, then we're done.
244 if (startOfBuffer.back() != '\n' && startOfBuffer.back() != '\r')
245 return emitError(loc: SMLoc::getFromPointer(Ptr: startOfBuffer.end()), message);
246
247 // Drop the \n so we emit the diagnostic at the end of the line.
248 startOfBuffer = startOfBuffer.drop_back();
249
250 // Check to see if the preceding line has a comment on it. We assume that a
251 // `//` is the start of a comment, which is mostly correct.
252 // TODO: This will do the wrong thing for // in a string literal.
253 auto prevLine = startOfBuffer;
254 size_t newLineIndex = prevLine.find_last_of(Chars: "\n\r");
255 if (newLineIndex != StringRef::npos)
256 prevLine = prevLine.drop_front(N: newLineIndex);
257
258 // If we find a // in the current line, then emit the diagnostic before it.
259 size_t commentStart = prevLine.find(Str: "//");
260 if (commentStart != StringRef::npos)
261 startOfBuffer = startOfBuffer.drop_back(N: prevLine.size() - commentStart);
262 }
263}
264
265/// Consume the specified token if present and return success. On failure,
266/// output a diagnostic and return failure.
267ParseResult Parser::parseToken(Token::Kind expectedToken,
268 const Twine &message) {
269 if (consumeIf(kind: expectedToken))
270 return success();
271 return emitWrongTokenError(message);
272}
273
274/// Parse an optional integer value from the stream.
275OptionalParseResult Parser::parseOptionalInteger(APInt &result) {
276 // Parse `false` and `true` keywords as 0 and 1 respectively.
277 if (consumeIf(kind: Token::kw_false)) {
278 result = false;
279 return success();
280 }
281 if (consumeIf(kind: Token::kw_true)) {
282 result = true;
283 return success();
284 }
285
286 Token curToken = getToken();
287 if (curToken.isNot(k1: Token::integer, k2: Token::minus))
288 return std::nullopt;
289
290 bool negative = consumeIf(kind: Token::minus);
291 Token curTok = getToken();
292 if (parseToken(expectedToken: Token::integer, message: "expected integer value"))
293 return failure();
294
295 StringRef spelling = curTok.getSpelling();
296 bool isHex = spelling.size() > 1 && spelling[1] == 'x';
297 if (spelling.getAsInteger(Radix: isHex ? 0 : 10, Result&: result))
298 return emitError(loc: curTok.getLoc(), message: "integer value too large");
299
300 // Make sure we have a zero at the top so we return the right signedness.
301 if (result.isNegative())
302 result = result.zext(width: result.getBitWidth() + 1);
303
304 // Process the negative sign if present.
305 if (negative)
306 result.negate();
307
308 return success();
309}
310
311/// Parse a floating point value from an integer literal token.
312ParseResult Parser::parseFloatFromIntegerLiteral(
313 std::optional<APFloat> &result, const Token &tok, bool isNegative,
314 const llvm::fltSemantics &semantics, size_t typeSizeInBits) {
315 SMLoc loc = tok.getLoc();
316 StringRef spelling = tok.getSpelling();
317 bool isHex = spelling.size() > 1 && spelling[1] == 'x';
318 if (!isHex) {
319 return emitError(loc, message: "unexpected decimal integer literal for a "
320 "floating point value")
321 .attachNote()
322 << "add a trailing dot to make the literal a float";
323 }
324 if (isNegative) {
325 return emitError(loc, message: "hexadecimal float literal should not have a "
326 "leading minus");
327 }
328
329 std::optional<uint64_t> value = tok.getUInt64IntegerValue();
330 if (!value)
331 return emitError(loc, message: "hexadecimal float constant out of range for type");
332
333 if (&semantics == &APFloat::IEEEdouble()) {
334 result = APFloat(semantics, APInt(typeSizeInBits, *value));
335 return success();
336 }
337
338 APInt apInt(typeSizeInBits, *value);
339 if (apInt != *value)
340 return emitError(loc, message: "hexadecimal float constant out of range for type");
341 result = APFloat(semantics, apInt);
342
343 return success();
344}
345
346ParseResult Parser::parseOptionalKeyword(StringRef *keyword) {
347 // Check that the current token is a keyword.
348 if (!isCurrentTokenAKeyword())
349 return failure();
350
351 *keyword = getTokenSpelling();
352 consumeToken();
353 return success();
354}
355
356//===----------------------------------------------------------------------===//
357// Resource Parsing
358
359FailureOr<AsmDialectResourceHandle>
360Parser::parseResourceHandle(const OpAsmDialectInterface *dialect,
361 StringRef &name) {
362 assert(dialect && "expected valid dialect interface");
363 SMLoc nameLoc = getToken().getLoc();
364 if (failed(result: parseOptionalKeyword(keyword: &name)))
365 return emitError(message: "expected identifier key for 'resource' entry");
366 auto &resources = getState().symbols.dialectResources;
367
368 // If this is the first time encountering this handle, ask the dialect to
369 // resolve a reference to this handle. This allows for us to remap the name of
370 // the handle if necessary.
371 std::pair<std::string, AsmDialectResourceHandle> &entry =
372 resources[dialect][name];
373 if (entry.first.empty()) {
374 FailureOr<AsmDialectResourceHandle> result = dialect->declareResource(key: name);
375 if (failed(result)) {
376 return emitError(loc: nameLoc)
377 << "unknown 'resource' key '" << name << "' for dialect '"
378 << dialect->getDialect()->getNamespace() << "'";
379 }
380 entry.first = dialect->getResourceKey(handle: *result);
381 entry.second = *result;
382 }
383
384 name = entry.first;
385 return entry.second;
386}
387
388FailureOr<AsmDialectResourceHandle>
389Parser::parseResourceHandle(Dialect *dialect) {
390 const auto *interface = dyn_cast<OpAsmDialectInterface>(Val: dialect);
391 if (!interface) {
392 return emitError() << "dialect '" << dialect->getNamespace()
393 << "' does not expect resource handles";
394 }
395 StringRef resourceName;
396 return parseResourceHandle(dialect: interface, name&: resourceName);
397}
398
399//===----------------------------------------------------------------------===//
400// Code Completion
401
402ParseResult Parser::codeCompleteDialectName() {
403 state.codeCompleteContext->completeDialectName();
404 return failure();
405}
406
407ParseResult Parser::codeCompleteOperationName(StringRef dialectName) {
408 // Perform some simple validation on the dialect name. This doesn't need to be
409 // extensive, it's more of an optimization (to avoid checking completion
410 // results when we know they will fail).
411 if (dialectName.empty() || dialectName.contains(C: '.'))
412 return failure();
413 state.codeCompleteContext->completeOperationName(dialectName);
414 return failure();
415}
416
417ParseResult Parser::codeCompleteDialectOrElidedOpName(SMLoc loc) {
418 // Check to see if there is anything else on the current line. This check
419 // isn't strictly necessary, but it does avoid unnecessarily triggering
420 // completions for operations and dialects in situations where we don't want
421 // them (e.g. at the end of an operation).
422 auto shouldIgnoreOpCompletion = [&]() {
423 const char *bufBegin = state.lex.getBufferBegin();
424 const char *it = loc.getPointer() - 1;
425 for (; it > bufBegin && *it != '\n'; --it)
426 if (!StringRef(" \t\r").contains(C: *it))
427 return true;
428 return false;
429 };
430 if (shouldIgnoreOpCompletion())
431 return failure();
432
433 // The completion here is either for a dialect name, or an operation name
434 // whose dialect prefix was elided. For this we simply invoke both of the
435 // individual completion methods.
436 (void)codeCompleteDialectName();
437 return codeCompleteOperationName(dialectName: state.defaultDialectStack.back());
438}
439
440ParseResult Parser::codeCompleteStringDialectOrOperationName(StringRef name) {
441 // If the name is empty, this is the start of the string and contains the
442 // dialect.
443 if (name.empty())
444 return codeCompleteDialectName();
445
446 // Otherwise, we treat this as completing an operation name. The current name
447 // is used as the dialect namespace.
448 if (name.consume_back(Suffix: "."))
449 return codeCompleteOperationName(dialectName: name);
450 return failure();
451}
452
453ParseResult Parser::codeCompleteExpectedTokens(ArrayRef<StringRef> tokens) {
454 state.codeCompleteContext->completeExpectedTokens(tokens, /*optional=*/false);
455 return failure();
456}
457ParseResult Parser::codeCompleteOptionalTokens(ArrayRef<StringRef> tokens) {
458 state.codeCompleteContext->completeExpectedTokens(tokens, /*optional=*/true);
459 return failure();
460}
461
462Attribute Parser::codeCompleteAttribute() {
463 state.codeCompleteContext->completeAttribute(
464 aliases: state.symbols.attributeAliasDefinitions);
465 return {};
466}
467Type Parser::codeCompleteType() {
468 state.codeCompleteContext->completeType(aliases: state.symbols.typeAliasDefinitions);
469 return {};
470}
471
472Attribute
473Parser::codeCompleteDialectSymbol(const llvm::StringMap<Attribute> &aliases) {
474 state.codeCompleteContext->completeDialectAttributeOrAlias(aliases);
475 return {};
476}
477Type Parser::codeCompleteDialectSymbol(const llvm::StringMap<Type> &aliases) {
478 state.codeCompleteContext->completeDialectTypeOrAlias(aliases);
479 return {};
480}
481
482//===----------------------------------------------------------------------===//
483// OperationParser
484//===----------------------------------------------------------------------===//
485
486namespace {
487/// This class provides support for parsing operations and regions of
488/// operations.
489class OperationParser : public Parser {
490public:
491 OperationParser(ParserState &state, ModuleOp topLevelOp);
492 ~OperationParser();
493
494 /// After parsing is finished, this function must be called to see if there
495 /// are any remaining issues.
496 ParseResult finalize();
497
498 //===--------------------------------------------------------------------===//
499 // SSA Value Handling
500 //===--------------------------------------------------------------------===//
501
502 using UnresolvedOperand = OpAsmParser::UnresolvedOperand;
503 using Argument = OpAsmParser::Argument;
504
505 struct DeferredLocInfo {
506 SMLoc loc;
507 StringRef identifier;
508 };
509
510 /// Push a new SSA name scope to the parser.
511 void pushSSANameScope(bool isIsolated);
512
513 /// Pop the last SSA name scope from the parser.
514 ParseResult popSSANameScope();
515
516 /// Register a definition of a value with the symbol table.
517 ParseResult addDefinition(UnresolvedOperand useInfo, Value value);
518
519 /// Parse an optional list of SSA uses into 'results'.
520 ParseResult
521 parseOptionalSSAUseList(SmallVectorImpl<UnresolvedOperand> &results);
522
523 /// Parse a single SSA use into 'result'. If 'allowResultNumber' is true then
524 /// we allow #42 syntax.
525 ParseResult parseSSAUse(UnresolvedOperand &result,
526 bool allowResultNumber = true);
527
528 /// Given a reference to an SSA value and its type, return a reference. This
529 /// returns null on failure.
530 Value resolveSSAUse(UnresolvedOperand useInfo, Type type);
531
532 ParseResult parseSSADefOrUseAndType(
533 function_ref<ParseResult(UnresolvedOperand, Type)> action);
534
535 ParseResult parseOptionalSSAUseAndTypeList(SmallVectorImpl<Value> &results);
536
537 /// Return the location of the value identified by its name and number if it
538 /// has been already reference.
539 std::optional<SMLoc> getReferenceLoc(StringRef name, unsigned number) {
540 auto &values = isolatedNameScopes.back().values;
541 if (!values.count(Key: name) || number >= values[name].size())
542 return {};
543 if (values[name][number].value)
544 return values[name][number].loc;
545 return {};
546 }
547
548 //===--------------------------------------------------------------------===//
549 // Operation Parsing
550 //===--------------------------------------------------------------------===//
551
552 /// Parse an operation instance.
553 ParseResult parseOperation();
554
555 /// Parse a single operation successor.
556 ParseResult parseSuccessor(Block *&dest);
557
558 /// Parse a comma-separated list of operation successors in brackets.
559 ParseResult parseSuccessors(SmallVectorImpl<Block *> &destinations);
560
561 /// Parse an operation instance that is in the generic form.
562 Operation *parseGenericOperation();
563
564 /// Parse different components, viz., use-info of operand(s), successor(s),
565 /// region(s), attribute(s) and function-type, of the generic form of an
566 /// operation instance and populate the input operation-state 'result' with
567 /// those components. If any of the components is explicitly provided, then
568 /// skip parsing that component.
569 ParseResult parseGenericOperationAfterOpName(
570 OperationState &result,
571 std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo =
572 std::nullopt,
573 std::optional<ArrayRef<Block *>> parsedSuccessors = std::nullopt,
574 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions =
575 std::nullopt,
576 std::optional<ArrayRef<NamedAttribute>> parsedAttributes = std::nullopt,
577 std::optional<Attribute> propertiesAttribute = std::nullopt,
578 std::optional<FunctionType> parsedFnType = std::nullopt);
579
580 /// Parse an operation instance that is in the generic form and insert it at
581 /// the provided insertion point.
582 Operation *parseGenericOperation(Block *insertBlock,
583 Block::iterator insertPt);
584
585 /// This type is used to keep track of things that are either an Operation or
586 /// a BlockArgument. We cannot use Value for this, because not all Operations
587 /// have results.
588 using OpOrArgument = llvm::PointerUnion<Operation *, BlockArgument>;
589
590 /// Parse an optional trailing location and add it to the specifier Operation
591 /// or `UnresolvedOperand` if present.
592 ///
593 /// trailing-location ::= (`loc` (`(` location `)` | attribute-alias))?
594 ///
595 ParseResult parseTrailingLocationSpecifier(OpOrArgument opOrArgument);
596
597 /// Parse a location alias, that is a sequence looking like: #loc42
598 /// The alias may have already be defined or may be defined later, in which
599 /// case an OpaqueLoc is used a placeholder.
600 ParseResult parseLocationAlias(LocationAttr &loc);
601
602 /// This is the structure of a result specifier in the assembly syntax,
603 /// including the name, number of results, and location.
604 using ResultRecord = std::tuple<StringRef, unsigned, SMLoc>;
605
606 /// Parse an operation instance that is in the op-defined custom form.
607 /// resultInfo specifies information about the "%name =" specifiers.
608 Operation *parseCustomOperation(ArrayRef<ResultRecord> resultIDs);
609
610 /// Parse the name of an operation, in the custom form. On success, return a
611 /// an object of type 'OperationName'. Otherwise, failure is returned.
612 FailureOr<OperationName> parseCustomOperationName();
613
614 //===--------------------------------------------------------------------===//
615 // Region Parsing
616 //===--------------------------------------------------------------------===//
617
618 /// Parse a region into 'region' with the provided entry block arguments.
619 /// 'isIsolatedNameScope' indicates if the naming scope of this region is
620 /// isolated from those above.
621 ParseResult parseRegion(Region &region, ArrayRef<Argument> entryArguments,
622 bool isIsolatedNameScope = false);
623
624 /// Parse a region body into 'region'.
625 ParseResult parseRegionBody(Region &region, SMLoc startLoc,
626 ArrayRef<Argument> entryArguments,
627 bool isIsolatedNameScope);
628
629 //===--------------------------------------------------------------------===//
630 // Block Parsing
631 //===--------------------------------------------------------------------===//
632
633 /// Parse a new block into 'block'.
634 ParseResult parseBlock(Block *&block);
635
636 /// Parse a list of operations into 'block'.
637 ParseResult parseBlockBody(Block *block);
638
639 /// Parse a (possibly empty) list of block arguments.
640 ParseResult parseOptionalBlockArgList(Block *owner);
641
642 /// Get the block with the specified name, creating it if it doesn't
643 /// already exist. The location specified is the point of use, which allows
644 /// us to diagnose references to blocks that are not defined precisely.
645 Block *getBlockNamed(StringRef name, SMLoc loc);
646
647 //===--------------------------------------------------------------------===//
648 // Code Completion
649 //===--------------------------------------------------------------------===//
650
651 /// The set of various code completion methods. Every completion method
652 /// returns `failure` to stop the parsing process after providing completion
653 /// results.
654
655 ParseResult codeCompleteSSAUse();
656 ParseResult codeCompleteBlock();
657
658private:
659 /// This class represents a definition of a Block.
660 struct BlockDefinition {
661 /// A pointer to the defined Block.
662 Block *block;
663 /// The location that the Block was defined at.
664 SMLoc loc;
665 };
666 /// This class represents a definition of a Value.
667 struct ValueDefinition {
668 /// A pointer to the defined Value.
669 Value value;
670 /// The location that the Value was defined at.
671 SMLoc loc;
672 };
673
674 /// Returns the info for a block at the current scope for the given name.
675 BlockDefinition &getBlockInfoByName(StringRef name) {
676 return blocksByName.back()[name];
677 }
678
679 /// Insert a new forward reference to the given block.
680 void insertForwardRef(Block *block, SMLoc loc) {
681 forwardRef.back().try_emplace(Key: block, Args&: loc);
682 }
683
684 /// Erase any forward reference to the given block.
685 bool eraseForwardRef(Block *block) { return forwardRef.back().erase(Val: block); }
686
687 /// Record that a definition was added at the current scope.
688 void recordDefinition(StringRef def);
689
690 /// Get the value entry for the given SSA name.
691 SmallVectorImpl<ValueDefinition> &getSSAValueEntry(StringRef name);
692
693 /// Create a forward reference placeholder value with the given location and
694 /// result type.
695 Value createForwardRefPlaceholder(SMLoc loc, Type type);
696
697 /// Return true if this is a forward reference.
698 bool isForwardRefPlaceholder(Value value) {
699 return forwardRefPlaceholders.count(Val: value);
700 }
701
702 /// This struct represents an isolated SSA name scope. This scope may contain
703 /// other nested non-isolated scopes. These scopes are used for operations
704 /// that are known to be isolated to allow for reusing names within their
705 /// regions, even if those names are used above.
706 struct IsolatedSSANameScope {
707 /// Record that a definition was added at the current scope.
708 void recordDefinition(StringRef def) {
709 definitionsPerScope.back().insert(key: def);
710 }
711
712 /// Push a nested name scope.
713 void pushSSANameScope() { definitionsPerScope.push_back(Elt: {}); }
714
715 /// Pop a nested name scope.
716 void popSSANameScope() {
717 for (auto &def : definitionsPerScope.pop_back_val())
718 values.erase(Key: def.getKey());
719 }
720
721 /// This keeps track of all of the SSA values we are tracking for each name
722 /// scope, indexed by their name. This has one entry per result number.
723 llvm::StringMap<SmallVector<ValueDefinition, 1>> values;
724
725 /// This keeps track of all of the values defined by a specific name scope.
726 SmallVector<llvm::StringSet<>, 2> definitionsPerScope;
727 };
728
729 /// A list of isolated name scopes.
730 SmallVector<IsolatedSSANameScope, 2> isolatedNameScopes;
731
732 /// This keeps track of the block names as well as the location of the first
733 /// reference for each nested name scope. This is used to diagnose invalid
734 /// block references and memorize them.
735 SmallVector<DenseMap<StringRef, BlockDefinition>, 2> blocksByName;
736 SmallVector<DenseMap<Block *, SMLoc>, 2> forwardRef;
737
738 /// These are all of the placeholders we've made along with the location of
739 /// their first reference, to allow checking for use of undefined values.
740 DenseMap<Value, SMLoc> forwardRefPlaceholders;
741
742 /// Deffered locations: when parsing `loc(#loc42)` we add an entry to this
743 /// map. After parsing the definition `#loc42 = ...` we'll patch back users
744 /// of this location.
745 std::vector<DeferredLocInfo> deferredLocsReferences;
746
747 /// The builder used when creating parsed operation instances.
748 OpBuilder opBuilder;
749
750 /// The top level operation that holds all of the parsed operations.
751 Operation *topLevelOp;
752};
753} // namespace
754
755MLIR_DECLARE_EXPLICIT_TYPE_ID(OperationParser::DeferredLocInfo *)
756MLIR_DEFINE_EXPLICIT_TYPE_ID(OperationParser::DeferredLocInfo *)
757
758OperationParser::OperationParser(ParserState &state, ModuleOp topLevelOp)
759 : Parser(state), opBuilder(topLevelOp.getRegion()), topLevelOp(topLevelOp) {
760 // The top level operation starts a new name scope.
761 pushSSANameScope(/*isIsolated=*/true);
762
763 // If we are populating the parser state, prepare it for parsing.
764 if (state.asmState)
765 state.asmState->initialize(topLevelOp: topLevelOp);
766}
767
768OperationParser::~OperationParser() {
769 for (auto &fwd : forwardRefPlaceholders) {
770 // Drop all uses of undefined forward declared reference and destroy
771 // defining operation.
772 fwd.first.dropAllUses();
773 fwd.first.getDefiningOp()->destroy();
774 }
775 for (const auto &scope : forwardRef) {
776 for (const auto &fwd : scope) {
777 // Delete all blocks that were created as forward references but never
778 // included into a region.
779 fwd.first->dropAllUses();
780 delete fwd.first;
781 }
782 }
783}
784
785/// After parsing is finished, this function must be called to see if there are
786/// any remaining issues.
787ParseResult OperationParser::finalize() {
788 // Check for any forward references that are left. If we find any, error
789 // out.
790 if (!forwardRefPlaceholders.empty()) {
791 SmallVector<const char *, 4> errors;
792 // Iteration over the map isn't deterministic, so sort by source location.
793 for (auto entry : forwardRefPlaceholders)
794 errors.push_back(Elt: entry.second.getPointer());
795 llvm::array_pod_sort(Start: errors.begin(), End: errors.end());
796
797 for (const char *entry : errors) {
798 auto loc = SMLoc::getFromPointer(Ptr: entry);
799 emitError(loc, message: "use of undeclared SSA value name");
800 }
801 return failure();
802 }
803
804 // Resolve the locations of any deferred operations.
805 auto &attributeAliases = state.symbols.attributeAliasDefinitions;
806 auto locID = TypeID::get<DeferredLocInfo *>();
807 auto resolveLocation = [&, this](auto &opOrArgument) -> LogicalResult {
808 auto fwdLoc = dyn_cast<OpaqueLoc>(opOrArgument.getLoc());
809 if (!fwdLoc || fwdLoc.getUnderlyingTypeID() != locID)
810 return success();
811 auto locInfo = deferredLocsReferences[fwdLoc.getUnderlyingLocation()];
812 Attribute attr = attributeAliases.lookup(Key: locInfo.identifier);
813 if (!attr)
814 return this->emitError(locInfo.loc)
815 << "operation location alias was never defined";
816 auto locAttr = dyn_cast<LocationAttr>(Val&: attr);
817 if (!locAttr)
818 return this->emitError(locInfo.loc)
819 << "expected location, but found '" << attr << "'";
820 opOrArgument.setLoc(locAttr);
821 return success();
822 };
823
824 auto walkRes = topLevelOp->walk(callback: [&](Operation *op) {
825 if (failed(result: resolveLocation(*op)))
826 return WalkResult::interrupt();
827 for (Region &region : op->getRegions())
828 for (Block &block : region.getBlocks())
829 for (BlockArgument arg : block.getArguments())
830 if (failed(result: resolveLocation(arg)))
831 return WalkResult::interrupt();
832 return WalkResult::advance();
833 });
834 if (walkRes.wasInterrupted())
835 return failure();
836
837 // Pop the top level name scope.
838 if (failed(result: popSSANameScope()))
839 return failure();
840
841 // Verify that the parsed operations are valid.
842 if (state.config.shouldVerifyAfterParse() && failed(result: verify(op: topLevelOp)))
843 return failure();
844
845 // If we are populating the parser state, finalize the top-level operation.
846 if (state.asmState)
847 state.asmState->finalize(topLevelOp);
848 return success();
849}
850
851//===----------------------------------------------------------------------===//
852// SSA Value Handling
853//===----------------------------------------------------------------------===//
854
855void OperationParser::pushSSANameScope(bool isIsolated) {
856 blocksByName.push_back(Elt: DenseMap<StringRef, BlockDefinition>());
857 forwardRef.push_back(Elt: DenseMap<Block *, SMLoc>());
858
859 // Push back a new name definition scope.
860 if (isIsolated)
861 isolatedNameScopes.push_back(Elt: {});
862 isolatedNameScopes.back().pushSSANameScope();
863}
864
865ParseResult OperationParser::popSSANameScope() {
866 auto forwardRefInCurrentScope = forwardRef.pop_back_val();
867
868 // Verify that all referenced blocks were defined.
869 if (!forwardRefInCurrentScope.empty()) {
870 SmallVector<std::pair<const char *, Block *>, 4> errors;
871 // Iteration over the map isn't deterministic, so sort by source location.
872 for (auto entry : forwardRefInCurrentScope) {
873 errors.push_back(Elt: {entry.second.getPointer(), entry.first});
874 // Add this block to the top-level region to allow for automatic cleanup.
875 topLevelOp->getRegion(index: 0).push_back(block: entry.first);
876 }
877 llvm::array_pod_sort(Start: errors.begin(), End: errors.end());
878
879 for (auto entry : errors) {
880 auto loc = SMLoc::getFromPointer(Ptr: entry.first);
881 emitError(loc, message: "reference to an undefined block");
882 }
883 return failure();
884 }
885
886 // Pop the next nested namescope. If there is only one internal namescope,
887 // just pop the isolated scope.
888 auto &currentNameScope = isolatedNameScopes.back();
889 if (currentNameScope.definitionsPerScope.size() == 1)
890 isolatedNameScopes.pop_back();
891 else
892 currentNameScope.popSSANameScope();
893
894 blocksByName.pop_back();
895 return success();
896}
897
898/// Register a definition of a value with the symbol table.
899ParseResult OperationParser::addDefinition(UnresolvedOperand useInfo,
900 Value value) {
901 auto &entries = getSSAValueEntry(name: useInfo.name);
902
903 // Make sure there is a slot for this value.
904 if (entries.size() <= useInfo.number)
905 entries.resize(N: useInfo.number + 1);
906
907 // If we already have an entry for this, check to see if it was a definition
908 // or a forward reference.
909 if (auto existing = entries[useInfo.number].value) {
910 if (!isForwardRefPlaceholder(value: existing)) {
911 return emitError(loc: useInfo.location)
912 .append(args: "redefinition of SSA value '", args&: useInfo.name, args: "'")
913 .attachNote(noteLoc: getEncodedSourceLocation(loc: entries[useInfo.number].loc))
914 .append(arg: "previously defined here");
915 }
916
917 if (existing.getType() != value.getType()) {
918 return emitError(loc: useInfo.location)
919 .append(args: "definition of SSA value '", args&: useInfo.name, args: "#",
920 args&: useInfo.number, args: "' has type ", args: value.getType())
921 .attachNote(noteLoc: getEncodedSourceLocation(loc: entries[useInfo.number].loc))
922 .append(arg1: "previously used here with type ", arg2: existing.getType());
923 }
924
925 // If it was a forward reference, update everything that used it to use
926 // the actual definition instead, delete the forward ref, and remove it
927 // from our set of forward references we track.
928 existing.replaceAllUsesWith(newValue: value);
929 existing.getDefiningOp()->destroy();
930 forwardRefPlaceholders.erase(Val: existing);
931
932 // If a definition of the value already exists, replace it in the assembly
933 // state.
934 if (state.asmState)
935 state.asmState->refineDefinition(oldValue: existing, newValue: value);
936 }
937
938 /// Record this definition for the current scope.
939 entries[useInfo.number] = {.value: value, .loc: useInfo.location};
940 recordDefinition(def: useInfo.name);
941 return success();
942}
943
944/// Parse a (possibly empty) list of SSA operands.
945///
946/// ssa-use-list ::= ssa-use (`,` ssa-use)*
947/// ssa-use-list-opt ::= ssa-use-list?
948///
949ParseResult OperationParser::parseOptionalSSAUseList(
950 SmallVectorImpl<UnresolvedOperand> &results) {
951 if (!getToken().isOrIsCodeCompletionFor(kind: Token::percent_identifier))
952 return success();
953 return parseCommaSeparatedList(parseElementFn: [&]() -> ParseResult {
954 UnresolvedOperand result;
955 if (parseSSAUse(result))
956 return failure();
957 results.push_back(Elt: result);
958 return success();
959 });
960}
961
962/// Parse a SSA operand for an operation.
963///
964/// ssa-use ::= ssa-id
965///
966ParseResult OperationParser::parseSSAUse(UnresolvedOperand &result,
967 bool allowResultNumber) {
968 if (getToken().isCodeCompletion())
969 return codeCompleteSSAUse();
970
971 result.name = getTokenSpelling();
972 result.number = 0;
973 result.location = getToken().getLoc();
974 if (parseToken(expectedToken: Token::percent_identifier, message: "expected SSA operand"))
975 return failure();
976
977 // If we have an attribute ID, it is a result number.
978 if (getToken().is(k: Token::hash_identifier)) {
979 if (!allowResultNumber)
980 return emitError(message: "result number not allowed in argument list");
981
982 if (auto value = getToken().getHashIdentifierNumber())
983 result.number = *value;
984 else
985 return emitError(message: "invalid SSA value result number");
986 consumeToken(kind: Token::hash_identifier);
987 }
988
989 return success();
990}
991
992/// Given an unbound reference to an SSA value and its type, return the value
993/// it specifies. This returns null on failure.
994Value OperationParser::resolveSSAUse(UnresolvedOperand useInfo, Type type) {
995 auto &entries = getSSAValueEntry(name: useInfo.name);
996
997 // Functor used to record the use of the given value if the assembly state
998 // field is populated.
999 auto maybeRecordUse = [&](Value value) {
1000 if (state.asmState)
1001 state.asmState->addUses(value, locations: useInfo.location);
1002 return value;
1003 };
1004
1005 // If we have already seen a value of this name, return it.
1006 if (useInfo.number < entries.size() && entries[useInfo.number].value) {
1007 Value result = entries[useInfo.number].value;
1008 // Check that the type matches the other uses.
1009 if (result.getType() == type)
1010 return maybeRecordUse(result);
1011
1012 emitError(loc: useInfo.location, message: "use of value '")
1013 .append(args&: useInfo.name,
1014 args: "' expects different type than prior uses: ", args&: type, args: " vs ",
1015 args: result.getType())
1016 .attachNote(noteLoc: getEncodedSourceLocation(loc: entries[useInfo.number].loc))
1017 .append(arg: "prior use here");
1018 return nullptr;
1019 }
1020
1021 // Make sure we have enough slots for this.
1022 if (entries.size() <= useInfo.number)
1023 entries.resize(N: useInfo.number + 1);
1024
1025 // If the value has already been defined and this is an overly large result
1026 // number, diagnose that.
1027 if (entries[0].value && !isForwardRefPlaceholder(value: entries[0].value))
1028 return (emitError(loc: useInfo.location, message: "reference to invalid result number"),
1029 nullptr);
1030
1031 // Otherwise, this is a forward reference. Create a placeholder and remember
1032 // that we did so.
1033 Value result = createForwardRefPlaceholder(loc: useInfo.location, type);
1034 entries[useInfo.number] = {.value: result, .loc: useInfo.location};
1035 return maybeRecordUse(result);
1036}
1037
1038/// Parse an SSA use with an associated type.
1039///
1040/// ssa-use-and-type ::= ssa-use `:` type
1041ParseResult OperationParser::parseSSADefOrUseAndType(
1042 function_ref<ParseResult(UnresolvedOperand, Type)> action) {
1043 UnresolvedOperand useInfo;
1044 if (parseSSAUse(result&: useInfo) ||
1045 parseToken(expectedToken: Token::colon, message: "expected ':' and type for SSA operand"))
1046 return failure();
1047
1048 auto type = parseType();
1049 if (!type)
1050 return failure();
1051
1052 return action(useInfo, type);
1053}
1054
1055/// Parse a (possibly empty) list of SSA operands, followed by a colon, then
1056/// followed by a type list.
1057///
1058/// ssa-use-and-type-list
1059/// ::= ssa-use-list ':' type-list-no-parens
1060///
1061ParseResult OperationParser::parseOptionalSSAUseAndTypeList(
1062 SmallVectorImpl<Value> &results) {
1063 SmallVector<UnresolvedOperand, 4> valueIDs;
1064 if (parseOptionalSSAUseList(results&: valueIDs))
1065 return failure();
1066
1067 // If there were no operands, then there is no colon or type lists.
1068 if (valueIDs.empty())
1069 return success();
1070
1071 SmallVector<Type, 4> types;
1072 if (parseToken(expectedToken: Token::colon, message: "expected ':' in operand list") ||
1073 parseTypeListNoParens(elements&: types))
1074 return failure();
1075
1076 if (valueIDs.size() != types.size())
1077 return emitError(message: "expected ")
1078 << valueIDs.size() << " types to match operand list";
1079
1080 results.reserve(N: valueIDs.size());
1081 for (unsigned i = 0, e = valueIDs.size(); i != e; ++i) {
1082 if (auto value = resolveSSAUse(useInfo: valueIDs[i], type: types[i]))
1083 results.push_back(Elt: value);
1084 else
1085 return failure();
1086 }
1087
1088 return success();
1089}
1090
1091/// Record that a definition was added at the current scope.
1092void OperationParser::recordDefinition(StringRef def) {
1093 isolatedNameScopes.back().recordDefinition(def);
1094}
1095
1096/// Get the value entry for the given SSA name.
1097auto OperationParser::getSSAValueEntry(StringRef name)
1098 -> SmallVectorImpl<ValueDefinition> & {
1099 return isolatedNameScopes.back().values[name];
1100}
1101
1102/// Create and remember a new placeholder for a forward reference.
1103Value OperationParser::createForwardRefPlaceholder(SMLoc loc, Type type) {
1104 // Forward references are always created as operations, because we just need
1105 // something with a def/use chain.
1106 //
1107 // We create these placeholders as having an empty name, which we know
1108 // cannot be created through normal user input, allowing us to distinguish
1109 // them.
1110 auto name = OperationName("builtin.unrealized_conversion_cast", getContext());
1111 auto *op = Operation::create(
1112 location: getEncodedSourceLocation(loc), name, resultTypes: type, /*operands=*/{},
1113 /*attributes=*/std::nullopt, /*properties=*/nullptr, /*successors=*/{},
1114 /*numRegions=*/0);
1115 forwardRefPlaceholders[op->getResult(idx: 0)] = loc;
1116 return op->getResult(idx: 0);
1117}
1118
1119//===----------------------------------------------------------------------===//
1120// Operation Parsing
1121//===----------------------------------------------------------------------===//
1122
1123/// Parse an operation.
1124///
1125/// operation ::= op-result-list?
1126/// (generic-operation | custom-operation)
1127/// trailing-location?
1128/// generic-operation ::= string-literal `(` ssa-use-list? `)`
1129/// successor-list? (`(` region-list `)`)?
1130/// attribute-dict? `:` function-type
1131/// custom-operation ::= bare-id custom-operation-format
1132/// op-result-list ::= op-result (`,` op-result)* `=`
1133/// op-result ::= ssa-id (`:` integer-literal)
1134///
1135ParseResult OperationParser::parseOperation() {
1136 auto loc = getToken().getLoc();
1137 SmallVector<ResultRecord, 1> resultIDs;
1138 size_t numExpectedResults = 0;
1139 if (getToken().is(k: Token::percent_identifier)) {
1140 // Parse the group of result ids.
1141 auto parseNextResult = [&]() -> ParseResult {
1142 // Parse the next result id.
1143 Token nameTok = getToken();
1144 if (parseToken(expectedToken: Token::percent_identifier,
1145 message: "expected valid ssa identifier"))
1146 return failure();
1147
1148 // If the next token is a ':', we parse the expected result count.
1149 size_t expectedSubResults = 1;
1150 if (consumeIf(kind: Token::colon)) {
1151 // Check that the next token is an integer.
1152 if (!getToken().is(k: Token::integer))
1153 return emitWrongTokenError(message: "expected integer number of results");
1154
1155 // Check that number of results is > 0.
1156 auto val = getToken().getUInt64IntegerValue();
1157 if (!val || *val < 1)
1158 return emitError(
1159 message: "expected named operation to have at least 1 result");
1160 consumeToken(kind: Token::integer);
1161 expectedSubResults = *val;
1162 }
1163
1164 resultIDs.emplace_back(Args: nameTok.getSpelling(), Args&: expectedSubResults,
1165 Args: nameTok.getLoc());
1166 numExpectedResults += expectedSubResults;
1167 return success();
1168 };
1169 if (parseCommaSeparatedList(parseElementFn: parseNextResult))
1170 return failure();
1171
1172 if (parseToken(expectedToken: Token::equal, message: "expected '=' after SSA name"))
1173 return failure();
1174 }
1175
1176 Operation *op;
1177 Token nameTok = getToken();
1178 if (nameTok.is(k: Token::bare_identifier) || nameTok.isKeyword())
1179 op = parseCustomOperation(resultIDs);
1180 else if (nameTok.is(k: Token::string))
1181 op = parseGenericOperation();
1182 else if (nameTok.isCodeCompletionFor(kind: Token::string))
1183 return codeCompleteStringDialectOrOperationName(name: nameTok.getStringValue());
1184 else if (nameTok.isCodeCompletion())
1185 return codeCompleteDialectOrElidedOpName(loc);
1186 else
1187 return emitWrongTokenError(message: "expected operation name in quotes");
1188
1189 // If parsing of the basic operation failed, then this whole thing fails.
1190 if (!op)
1191 return failure();
1192
1193 // If the operation had a name, register it.
1194 if (!resultIDs.empty()) {
1195 if (op->getNumResults() == 0)
1196 return emitError(loc, message: "cannot name an operation with no results");
1197 if (numExpectedResults != op->getNumResults())
1198 return emitError(loc, message: "operation defines ")
1199 << op->getNumResults() << " results but was provided "
1200 << numExpectedResults << " to bind";
1201
1202 // Add this operation to the assembly state if it was provided to populate.
1203 if (state.asmState) {
1204 unsigned resultIt = 0;
1205 SmallVector<std::pair<unsigned, SMLoc>> asmResultGroups;
1206 asmResultGroups.reserve(N: resultIDs.size());
1207 for (ResultRecord &record : resultIDs) {
1208 asmResultGroups.emplace_back(Args&: resultIt, Args&: std::get<2>(t&: record));
1209 resultIt += std::get<1>(t&: record);
1210 }
1211 state.asmState->finalizeOperationDefinition(
1212 op, nameLoc: nameTok.getLocRange(), /*endLoc=*/getLastToken().getEndLoc(),
1213 resultGroups: asmResultGroups);
1214 }
1215
1216 // Add definitions for each of the result groups.
1217 unsigned opResI = 0;
1218 for (ResultRecord &resIt : resultIDs) {
1219 for (unsigned subRes : llvm::seq<unsigned>(Begin: 0, End: std::get<1>(t&: resIt))) {
1220 if (addDefinition(useInfo: {.location: std::get<2>(t&: resIt), .name: std::get<0>(t&: resIt), .number: subRes},
1221 value: op->getResult(idx: opResI++)))
1222 return failure();
1223 }
1224 }
1225
1226 // Add this operation to the assembly state if it was provided to populate.
1227 } else if (state.asmState) {
1228 state.asmState->finalizeOperationDefinition(
1229 op, nameLoc: nameTok.getLocRange(),
1230 /*endLoc=*/getLastToken().getEndLoc());
1231 }
1232
1233 return success();
1234}
1235
1236/// Parse a single operation successor.
1237///
1238/// successor ::= block-id
1239///
1240ParseResult OperationParser::parseSuccessor(Block *&dest) {
1241 if (getToken().isCodeCompletion())
1242 return codeCompleteBlock();
1243
1244 // Verify branch is identifier and get the matching block.
1245 if (!getToken().is(k: Token::caret_identifier))
1246 return emitWrongTokenError(message: "expected block name");
1247 dest = getBlockNamed(name: getTokenSpelling(), loc: getToken().getLoc());
1248 consumeToken();
1249 return success();
1250}
1251
1252/// Parse a comma-separated list of operation successors in brackets.
1253///
1254/// successor-list ::= `[` successor (`,` successor )* `]`
1255///
1256ParseResult
1257OperationParser::parseSuccessors(SmallVectorImpl<Block *> &destinations) {
1258 if (parseToken(expectedToken: Token::l_square, message: "expected '['"))
1259 return failure();
1260
1261 auto parseElt = [this, &destinations] {
1262 Block *dest;
1263 ParseResult res = parseSuccessor(dest);
1264 destinations.push_back(Elt: dest);
1265 return res;
1266 };
1267 return parseCommaSeparatedListUntil(rightToken: Token::r_square, parseElement: parseElt,
1268 /*allowEmptyList=*/false);
1269}
1270
1271namespace {
1272// RAII-style guard for cleaning up the regions in the operation state before
1273// deleting them. Within the parser, regions may get deleted if parsing failed,
1274// and other errors may be present, in particular undominated uses. This makes
1275// sure such uses are deleted.
1276struct CleanupOpStateRegions {
1277 ~CleanupOpStateRegions() {
1278 SmallVector<Region *, 4> regionsToClean;
1279 regionsToClean.reserve(N: state.regions.size());
1280 for (auto &region : state.regions)
1281 if (region)
1282 for (auto &block : *region)
1283 block.dropAllDefinedValueUses();
1284 }
1285 OperationState &state;
1286};
1287} // namespace
1288
1289ParseResult OperationParser::parseGenericOperationAfterOpName(
1290 OperationState &result,
1291 std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo,
1292 std::optional<ArrayRef<Block *>> parsedSuccessors,
1293 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1294 std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1295 std::optional<Attribute> propertiesAttribute,
1296 std::optional<FunctionType> parsedFnType) {
1297
1298 // Parse the operand list, if not explicitly provided.
1299 SmallVector<UnresolvedOperand, 8> opInfo;
1300 if (!parsedOperandUseInfo) {
1301 if (parseToken(expectedToken: Token::l_paren, message: "expected '(' to start operand list") ||
1302 parseOptionalSSAUseList(results&: opInfo) ||
1303 parseToken(expectedToken: Token::r_paren, message: "expected ')' to end operand list")) {
1304 return failure();
1305 }
1306 parsedOperandUseInfo = opInfo;
1307 }
1308
1309 // Parse the successor list, if not explicitly provided.
1310 if (!parsedSuccessors) {
1311 if (getToken().is(k: Token::l_square)) {
1312 // Check if the operation is not a known terminator.
1313 if (!result.name.mightHaveTrait<OpTrait::IsTerminator>())
1314 return emitError(message: "successors in non-terminator");
1315
1316 SmallVector<Block *, 2> successors;
1317 if (parseSuccessors(destinations&: successors))
1318 return failure();
1319 result.addSuccessors(newSuccessors: successors);
1320 }
1321 } else {
1322 result.addSuccessors(newSuccessors: *parsedSuccessors);
1323 }
1324
1325 // Parse the properties, if not explicitly provided.
1326 if (propertiesAttribute) {
1327 result.propertiesAttr = *propertiesAttribute;
1328 } else if (consumeIf(kind: Token::less)) {
1329 result.propertiesAttr = parseAttribute();
1330 if (!result.propertiesAttr)
1331 return failure();
1332 if (parseToken(expectedToken: Token::greater, message: "expected '>' to close properties"))
1333 return failure();
1334 }
1335 // Parse the region list, if not explicitly provided.
1336 if (!parsedRegions) {
1337 if (consumeIf(kind: Token::l_paren)) {
1338 do {
1339 // Create temporary regions with the top level region as parent.
1340 result.regions.emplace_back(Args: new Region(topLevelOp));
1341 if (parseRegion(region&: *result.regions.back(), /*entryArguments=*/{}))
1342 return failure();
1343 } while (consumeIf(kind: Token::comma));
1344 if (parseToken(expectedToken: Token::r_paren, message: "expected ')' to end region list"))
1345 return failure();
1346 }
1347 } else {
1348 result.addRegions(regions: *parsedRegions);
1349 }
1350
1351 // Parse the attributes, if not explicitly provided.
1352 if (!parsedAttributes) {
1353 if (getToken().is(k: Token::l_brace)) {
1354 if (parseAttributeDict(attributes&: result.attributes))
1355 return failure();
1356 }
1357 } else {
1358 result.addAttributes(newAttributes: *parsedAttributes);
1359 }
1360
1361 // Parse the operation type, if not explicitly provided.
1362 Location typeLoc = result.location;
1363 if (!parsedFnType) {
1364 if (parseToken(expectedToken: Token::colon, message: "expected ':' followed by operation type"))
1365 return failure();
1366
1367 typeLoc = getEncodedSourceLocation(loc: getToken().getLoc());
1368 auto type = parseType();
1369 if (!type)
1370 return failure();
1371 auto fnType = dyn_cast<FunctionType>(type);
1372 if (!fnType)
1373 return mlir::emitError(loc: typeLoc, message: "expected function type");
1374
1375 parsedFnType = fnType;
1376 }
1377
1378 result.addTypes(parsedFnType->getResults());
1379
1380 // Check that we have the right number of types for the operands.
1381 ArrayRef<Type> operandTypes = parsedFnType->getInputs();
1382 if (operandTypes.size() != parsedOperandUseInfo->size()) {
1383 auto plural = "s"[parsedOperandUseInfo->size() == 1];
1384 return mlir::emitError(loc: typeLoc, message: "expected ")
1385 << parsedOperandUseInfo->size() << " operand type" << plural
1386 << " but had " << operandTypes.size();
1387 }
1388
1389 // Resolve all of the operands.
1390 for (unsigned i = 0, e = parsedOperandUseInfo->size(); i != e; ++i) {
1391 result.operands.push_back(
1392 Elt: resolveSSAUse(useInfo: (*parsedOperandUseInfo)[i], type: operandTypes[i]));
1393 if (!result.operands.back())
1394 return failure();
1395 }
1396
1397 return success();
1398}
1399
1400Operation *OperationParser::parseGenericOperation() {
1401 // Get location information for the operation.
1402 auto srcLocation = getEncodedSourceLocation(loc: getToken().getLoc());
1403
1404 std::string name = getToken().getStringValue();
1405 if (name.empty())
1406 return (emitError(message: "empty operation name is invalid"), nullptr);
1407 if (name.find(c: '\0') != StringRef::npos)
1408 return (emitError(message: "null character not allowed in operation name"), nullptr);
1409
1410 consumeToken(kind: Token::string);
1411
1412 OperationState result(srcLocation, name);
1413 CleanupOpStateRegions guard{.state: result};
1414
1415 // Lazy load dialects in the context as needed.
1416 if (!result.name.isRegistered()) {
1417 StringRef dialectName = StringRef(name).split(Separator: '.').first;
1418 if (!getContext()->getLoadedDialect(name: dialectName) &&
1419 !getContext()->getOrLoadDialect(name: dialectName)) {
1420 if (!getContext()->allowsUnregisteredDialects()) {
1421 // Emit an error if the dialect couldn't be loaded (i.e., it was not
1422 // registered) and unregistered dialects aren't allowed.
1423 emitError(message: "operation being parsed with an unregistered dialect. If "
1424 "this is intended, please use -allow-unregistered-dialect "
1425 "with the MLIR tool used");
1426 return nullptr;
1427 }
1428 } else {
1429 // Reload the OperationName now that the dialect is loaded.
1430 result.name = OperationName(name, getContext());
1431 }
1432 }
1433
1434 // If we are populating the parser state, start a new operation definition.
1435 if (state.asmState)
1436 state.asmState->startOperationDefinition(opName: result.name);
1437
1438 if (parseGenericOperationAfterOpName(result))
1439 return nullptr;
1440
1441 // Operation::create() is not allowed to fail, however setting the properties
1442 // from an attribute is a failable operation. So we save the attribute here
1443 // and set it on the operation post-parsing.
1444 Attribute properties;
1445 std::swap(a&: properties, b&: result.propertiesAttr);
1446
1447 // If we don't have properties in the textual IR, but the operation now has
1448 // support for properties, we support some backward-compatible generic syntax
1449 // for the operation and as such we accept inherent attributes mixed in the
1450 // dictionary of discardable attributes. We pre-validate these here because
1451 // invalid attributes can't be casted to the properties storage and will be
1452 // silently dropped. For example an attribute { foo = 0 : i32 } that is
1453 // declared as F32Attr in ODS would have a C++ type of FloatAttr in the
1454 // properties array. When setting it we would do something like:
1455 //
1456 // properties.foo = dyn_cast<FloatAttr>(fooAttr);
1457 //
1458 // which would end up with a null Attribute. The diagnostic from the verifier
1459 // would be "missing foo attribute" instead of something like "expects a 32
1460 // bits float attribute but got a 32 bits integer attribute".
1461 if (!properties && !result.getRawProperties()) {
1462 std::optional<RegisteredOperationName> info =
1463 result.name.getRegisteredInfo();
1464 if (info) {
1465 if (failed(result: info->verifyInherentAttrs(attributes&: result.attributes, emitError: [&]() {
1466 return mlir::emitError(loc: srcLocation) << "'" << name << "' op ";
1467 })))
1468 return nullptr;
1469 }
1470 }
1471
1472 // Create the operation and try to parse a location for it.
1473 Operation *op = opBuilder.create(state: result);
1474 if (parseTrailingLocationSpecifier(opOrArgument: op))
1475 return nullptr;
1476
1477 // Try setting the properties for the operation, using a diagnostic to print
1478 // errors.
1479 if (properties) {
1480 auto emitError = [&]() {
1481 return mlir::emitError(loc: srcLocation, message: "invalid properties ")
1482 << properties << " for op " << name << ": ";
1483 };
1484 if (failed(result: op->setPropertiesFromAttribute(attr: properties, emitError)))
1485 return nullptr;
1486 }
1487
1488 return op;
1489}
1490
1491Operation *OperationParser::parseGenericOperation(Block *insertBlock,
1492 Block::iterator insertPt) {
1493 Token nameToken = getToken();
1494
1495 OpBuilder::InsertionGuard restoreInsertionPoint(opBuilder);
1496 opBuilder.setInsertionPoint(block: insertBlock, insertPoint: insertPt);
1497 Operation *op = parseGenericOperation();
1498 if (!op)
1499 return nullptr;
1500
1501 // If we are populating the parser asm state, finalize this operation
1502 // definition.
1503 if (state.asmState)
1504 state.asmState->finalizeOperationDefinition(
1505 op, nameLoc: nameToken.getLocRange(),
1506 /*endLoc=*/getLastToken().getEndLoc());
1507 return op;
1508}
1509
1510namespace {
1511class CustomOpAsmParser : public AsmParserImpl<OpAsmParser> {
1512public:
1513 CustomOpAsmParser(
1514 SMLoc nameLoc, ArrayRef<OperationParser::ResultRecord> resultIDs,
1515 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly,
1516 bool isIsolatedFromAbove, StringRef opName, OperationParser &parser)
1517 : AsmParserImpl<OpAsmParser>(nameLoc, parser), resultIDs(resultIDs),
1518 parseAssembly(parseAssembly), isIsolatedFromAbove(isIsolatedFromAbove),
1519 opName(opName), parser(parser) {
1520 (void)isIsolatedFromAbove; // Only used in assert, silence unused warning.
1521 }
1522
1523 /// Parse an instance of the operation described by 'opDefinition' into the
1524 /// provided operation state.
1525 ParseResult parseOperation(OperationState &opState) {
1526 if (parseAssembly(*this, opState))
1527 return failure();
1528 // Verify that the parsed attributes does not have duplicate attributes.
1529 // This can happen if an attribute set during parsing is also specified in
1530 // the attribute dictionary in the assembly, or the attribute is set
1531 // multiple during parsing.
1532 std::optional<NamedAttribute> duplicate =
1533 opState.attributes.findDuplicate();
1534 if (duplicate)
1535 return emitError(loc: getNameLoc(), message: "attribute '")
1536 << duplicate->getName().getValue()
1537 << "' occurs more than once in the attribute list";
1538 return success();
1539 }
1540
1541 Operation *parseGenericOperation(Block *insertBlock,
1542 Block::iterator insertPt) final {
1543 return parser.parseGenericOperation(insertBlock, insertPt);
1544 }
1545
1546 FailureOr<OperationName> parseCustomOperationName() final {
1547 return parser.parseCustomOperationName();
1548 }
1549
1550 ParseResult parseGenericOperationAfterOpName(
1551 OperationState &result,
1552 std::optional<ArrayRef<UnresolvedOperand>> parsedUnresolvedOperands,
1553 std::optional<ArrayRef<Block *>> parsedSuccessors,
1554 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1555 std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1556 std::optional<Attribute> parsedPropertiesAttribute,
1557 std::optional<FunctionType> parsedFnType) final {
1558 return parser.parseGenericOperationAfterOpName(
1559 result, parsedOperandUseInfo: parsedUnresolvedOperands, parsedSuccessors, parsedRegions,
1560 parsedAttributes, propertiesAttribute: parsedPropertiesAttribute, parsedFnType);
1561 }
1562 //===--------------------------------------------------------------------===//
1563 // Utilities
1564 //===--------------------------------------------------------------------===//
1565
1566 /// Return the name of the specified result in the specified syntax, as well
1567 /// as the subelement in the name. For example, in this operation:
1568 ///
1569 /// %x, %y:2, %z = foo.op
1570 ///
1571 /// getResultName(0) == {"x", 0 }
1572 /// getResultName(1) == {"y", 0 }
1573 /// getResultName(2) == {"y", 1 }
1574 /// getResultName(3) == {"z", 0 }
1575 std::pair<StringRef, unsigned>
1576 getResultName(unsigned resultNo) const override {
1577 // Scan for the resultID that contains this result number.
1578 for (const auto &entry : resultIDs) {
1579 if (resultNo < std::get<1>(t: entry)) {
1580 // Don't pass on the leading %.
1581 StringRef name = std::get<0>(t: entry).drop_front();
1582 return {name, resultNo};
1583 }
1584 resultNo -= std::get<1>(t: entry);
1585 }
1586
1587 // Invalid result number.
1588 return {"", ~0U};
1589 }
1590
1591 /// Return the number of declared SSA results. This returns 4 for the foo.op
1592 /// example in the comment for getResultName.
1593 size_t getNumResults() const override {
1594 size_t count = 0;
1595 for (auto &entry : resultIDs)
1596 count += std::get<1>(t: entry);
1597 return count;
1598 }
1599
1600 /// Emit a diagnostic at the specified location and return failure.
1601 InFlightDiagnostic emitError(SMLoc loc, const Twine &message) override {
1602 return AsmParserImpl<OpAsmParser>::emitError(loc, "custom op '" + opName +
1603 "' " + message);
1604 }
1605
1606 //===--------------------------------------------------------------------===//
1607 // Operand Parsing
1608 //===--------------------------------------------------------------------===//
1609
1610 /// Parse a single operand.
1611 ParseResult parseOperand(UnresolvedOperand &result,
1612 bool allowResultNumber = true) override {
1613 OperationParser::UnresolvedOperand useInfo;
1614 if (parser.parseSSAUse(result&: useInfo, allowResultNumber))
1615 return failure();
1616
1617 result = {.location: useInfo.location, .name: useInfo.name, .number: useInfo.number};
1618 return success();
1619 }
1620
1621 /// Parse a single operand if present.
1622 OptionalParseResult
1623 parseOptionalOperand(UnresolvedOperand &result,
1624 bool allowResultNumber = true) override {
1625 if (parser.getToken().isOrIsCodeCompletionFor(kind: Token::percent_identifier))
1626 return parseOperand(result, allowResultNumber);
1627 return std::nullopt;
1628 }
1629
1630 /// Parse zero or more SSA comma-separated operand references with a specified
1631 /// surrounding delimiter, and an optional required operand count.
1632 ParseResult parseOperandList(SmallVectorImpl<UnresolvedOperand> &result,
1633 Delimiter delimiter = Delimiter::None,
1634 bool allowResultNumber = true,
1635 int requiredOperandCount = -1) override {
1636 // The no-delimiter case has some special handling for better diagnostics.
1637 if (delimiter == Delimiter::None) {
1638 // parseCommaSeparatedList doesn't handle the missing case for "none",
1639 // so we handle it custom here.
1640 Token tok = parser.getToken();
1641 if (!tok.isOrIsCodeCompletionFor(kind: Token::percent_identifier)) {
1642 // If we didn't require any operands or required exactly zero (weird)
1643 // then this is success.
1644 if (requiredOperandCount == -1 || requiredOperandCount == 0)
1645 return success();
1646
1647 // Otherwise, try to produce a nice error message.
1648 if (tok.isAny(k1: Token::l_paren, k2: Token::l_square))
1649 return parser.emitError(message: "unexpected delimiter");
1650 return parser.emitWrongTokenError(message: "expected operand");
1651 }
1652 }
1653
1654 auto parseOneOperand = [&]() -> ParseResult {
1655 return parseOperand(result&: result.emplace_back(), allowResultNumber);
1656 };
1657
1658 auto startLoc = parser.getToken().getLoc();
1659 if (parseCommaSeparatedList(delimiter, parseOneOperand, " in operand list"))
1660 return failure();
1661
1662 // Check that we got the expected # of elements.
1663 if (requiredOperandCount != -1 &&
1664 result.size() != static_cast<size_t>(requiredOperandCount))
1665 return emitError(loc: startLoc, message: "expected ")
1666 << requiredOperandCount << " operands";
1667 return success();
1668 }
1669
1670 /// Resolve an operand to an SSA value, emitting an error on failure.
1671 ParseResult resolveOperand(const UnresolvedOperand &operand, Type type,
1672 SmallVectorImpl<Value> &result) override {
1673 if (auto value = parser.resolveSSAUse(operand, type)) {
1674 result.push_back(Elt: value);
1675 return success();
1676 }
1677 return failure();
1678 }
1679
1680 /// Parse an AffineMap of SSA ids.
1681 ParseResult
1682 parseAffineMapOfSSAIds(SmallVectorImpl<UnresolvedOperand> &operands,
1683 Attribute &mapAttr, StringRef attrName,
1684 NamedAttrList &attrs, Delimiter delimiter) override {
1685 SmallVector<UnresolvedOperand, 2> dimOperands;
1686 SmallVector<UnresolvedOperand, 1> symOperands;
1687
1688 auto parseElement = [&](bool isSymbol) -> ParseResult {
1689 UnresolvedOperand operand;
1690 if (parseOperand(result&: operand))
1691 return failure();
1692 if (isSymbol)
1693 symOperands.push_back(operand);
1694 else
1695 dimOperands.push_back(operand);
1696 return success();
1697 };
1698
1699 AffineMap map;
1700 if (parser.parseAffineMapOfSSAIds(map, parseElement, delimiter: delimiter))
1701 return failure();
1702 // Add AffineMap attribute.
1703 if (map) {
1704 mapAttr = AffineMapAttr::get(map);
1705 attrs.push_back(newAttribute: parser.builder.getNamedAttr(name: attrName, val: mapAttr));
1706 }
1707
1708 // Add dim operands before symbol operands in 'operands'.
1709 operands.assign(dimOperands.begin(), dimOperands.end());
1710 operands.append(symOperands.begin(), symOperands.end());
1711 return success();
1712 }
1713
1714 /// Parse an AffineExpr of SSA ids.
1715 ParseResult
1716 parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands,
1717 SmallVectorImpl<UnresolvedOperand> &symbOperands,
1718 AffineExpr &expr) override {
1719 auto parseElement = [&](bool isSymbol) -> ParseResult {
1720 UnresolvedOperand operand;
1721 if (parseOperand(result&: operand))
1722 return failure();
1723 if (isSymbol)
1724 symbOperands.push_back(operand);
1725 else
1726 dimOperands.push_back(operand);
1727 return success();
1728 };
1729
1730 return parser.parseAffineExprOfSSAIds(expr, parseElement);
1731 }
1732
1733 //===--------------------------------------------------------------------===//
1734 // Argument Parsing
1735 //===--------------------------------------------------------------------===//
1736
1737 /// Parse a single argument with the following syntax:
1738 ///
1739 /// `%ssaname : !type { optionalAttrDict} loc(optionalSourceLoc)`
1740 ///
1741 /// If `allowType` is false or `allowAttrs` are false then the respective
1742 /// parts of the grammar are not parsed.
1743 ParseResult parseArgument(Argument &result, bool allowType = false,
1744 bool allowAttrs = false) override {
1745 NamedAttrList attrs;
1746 if (parseOperand(result&: result.ssaName, /*allowResultNumber=*/false) ||
1747 (allowType && parseColonType(result.type)) ||
1748 (allowAttrs && parseOptionalAttrDict(attrs)) ||
1749 parseOptionalLocationSpecifier(result&: result.sourceLoc))
1750 return failure();
1751 result.attrs = attrs.getDictionary(context: getContext());
1752 return success();
1753 }
1754
1755 /// Parse a single argument if present.
1756 OptionalParseResult parseOptionalArgument(Argument &result, bool allowType,
1757 bool allowAttrs) override {
1758 if (parser.getToken().is(Token::percent_identifier))
1759 return parseArgument(result, allowType, allowAttrs);
1760 return std::nullopt;
1761 }
1762
1763 ParseResult parseArgumentList(SmallVectorImpl<Argument> &result,
1764 Delimiter delimiter, bool allowType,
1765 bool allowAttrs) override {
1766 // The no-delimiter case has some special handling for the empty case.
1767 if (delimiter == Delimiter::None &&
1768 parser.getToken().isNot(Token::percent_identifier))
1769 return success();
1770
1771 auto parseOneArgument = [&]() -> ParseResult {
1772 return parseArgument(result.emplace_back(), allowType, allowAttrs);
1773 };
1774 return parseCommaSeparatedList(delimiter, parseOneArgument,
1775 " in argument list");
1776 }
1777
1778 //===--------------------------------------------------------------------===//
1779 // Region Parsing
1780 //===--------------------------------------------------------------------===//
1781
1782 /// Parse a region that takes `arguments` of `argTypes` types. This
1783 /// effectively defines the SSA values of `arguments` and assigns their type.
1784 ParseResult parseRegion(Region &region, ArrayRef<Argument> arguments,
1785 bool enableNameShadowing) override {
1786 // Try to parse the region.
1787 (void)isIsolatedFromAbove;
1788 assert((!enableNameShadowing || isIsolatedFromAbove) &&
1789 "name shadowing is only allowed on isolated regions");
1790 if (parser.parseRegion(region, entryArguments: arguments, isIsolatedNameScope: enableNameShadowing))
1791 return failure();
1792 return success();
1793 }
1794
1795 /// Parses a region if present.
1796 OptionalParseResult parseOptionalRegion(Region &region,
1797 ArrayRef<Argument> arguments,
1798 bool enableNameShadowing) override {
1799 if (parser.getToken().isNot(k: Token::l_brace))
1800 return std::nullopt;
1801 return parseRegion(region, arguments, enableNameShadowing);
1802 }
1803
1804 /// Parses a region if present. If the region is present, a new region is
1805 /// allocated and placed in `region`. If no region is present, `region`
1806 /// remains untouched.
1807 OptionalParseResult
1808 parseOptionalRegion(std::unique_ptr<Region> &region,
1809 ArrayRef<Argument> arguments,
1810 bool enableNameShadowing = false) override {
1811 if (parser.getToken().isNot(k: Token::l_brace))
1812 return std::nullopt;
1813 std::unique_ptr<Region> newRegion = std::make_unique<Region>();
1814 if (parseRegion(*newRegion, arguments, enableNameShadowing))
1815 return failure();
1816
1817 region = std::move(newRegion);
1818 return success();
1819 }
1820
1821 //===--------------------------------------------------------------------===//
1822 // Successor Parsing
1823 //===--------------------------------------------------------------------===//
1824
1825 /// Parse a single operation successor.
1826 ParseResult parseSuccessor(Block *&dest) override {
1827 return parser.parseSuccessor(dest);
1828 }
1829
1830 /// Parse an optional operation successor and its operand list.
1831 OptionalParseResult parseOptionalSuccessor(Block *&dest) override {
1832 if (!parser.getToken().isOrIsCodeCompletionFor(kind: Token::caret_identifier))
1833 return std::nullopt;
1834 return parseSuccessor(dest);
1835 }
1836
1837 /// Parse a single operation successor and its operand list.
1838 ParseResult
1839 parseSuccessorAndUseList(Block *&dest,
1840 SmallVectorImpl<Value> &operands) override {
1841 if (parseSuccessor(dest))
1842 return failure();
1843
1844 // Handle optional arguments.
1845 if (succeeded(parseOptionalLParen()) &&
1846 (parser.parseOptionalSSAUseAndTypeList(results&: operands) || parseRParen())) {
1847 return failure();
1848 }
1849 return success();
1850 }
1851
1852 //===--------------------------------------------------------------------===//
1853 // Type Parsing
1854 //===--------------------------------------------------------------------===//
1855
1856 /// Parse a list of assignments of the form
1857 /// (%x1 = %y1, %x2 = %y2, ...).
1858 OptionalParseResult parseOptionalAssignmentList(
1859 SmallVectorImpl<Argument> &lhs,
1860 SmallVectorImpl<UnresolvedOperand> &rhs) override {
1861 if (failed(parseOptionalLParen()))
1862 return std::nullopt;
1863
1864 auto parseElt = [&]() -> ParseResult {
1865 if (parseArgument(lhs.emplace_back()) || parseEqual() ||
1866 parseOperand(rhs.emplace_back()))
1867 return failure();
1868 return success();
1869 };
1870 return parser.parseCommaSeparatedListUntil(rightToken: Token::r_paren, parseElement: parseElt);
1871 }
1872
1873 /// Parse a loc(...) specifier if present, filling in result if so.
1874 ParseResult
1875 parseOptionalLocationSpecifier(std::optional<Location> &result) override {
1876 // If there is a 'loc' we parse a trailing location.
1877 if (!parser.consumeIf(kind: Token::kw_loc))
1878 return success();
1879 LocationAttr directLoc;
1880 if (parser.parseToken(expectedToken: Token::l_paren, message: "expected '(' in location"))
1881 return failure();
1882
1883 Token tok = parser.getToken();
1884
1885 // Check to see if we are parsing a location alias.
1886 // Otherwise, we parse the location directly.
1887 if (tok.is(k: Token::hash_identifier)) {
1888 if (parser.parseLocationAlias(loc&: directLoc))
1889 return failure();
1890 } else if (parser.parseLocationInstance(loc&: directLoc)) {
1891 return failure();
1892 }
1893
1894 if (parser.parseToken(expectedToken: Token::r_paren, message: "expected ')' in location"))
1895 return failure();
1896
1897 result = directLoc;
1898 return success();
1899 }
1900
1901private:
1902 /// Information about the result name specifiers.
1903 ArrayRef<OperationParser::ResultRecord> resultIDs;
1904
1905 /// The abstract information of the operation.
1906 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly;
1907 bool isIsolatedFromAbove;
1908 StringRef opName;
1909
1910 /// The backing operation parser.
1911 OperationParser &parser;
1912};
1913} // namespace
1914
1915FailureOr<OperationName> OperationParser::parseCustomOperationName() {
1916 Token nameTok = getToken();
1917 StringRef opName = nameTok.getSpelling();
1918 if (opName.empty())
1919 return (emitError(message: "empty operation name is invalid"), failure());
1920 consumeToken();
1921
1922 // Check to see if this operation name is already registered.
1923 std::optional<RegisteredOperationName> opInfo =
1924 RegisteredOperationName::lookup(name: opName, ctx: getContext());
1925 if (opInfo)
1926 return *opInfo;
1927
1928 // If the operation doesn't have a dialect prefix try using the default
1929 // dialect.
1930 auto opNameSplit = opName.split(Separator: '.');
1931 StringRef dialectName = opNameSplit.first;
1932 std::string opNameStorage;
1933 if (opNameSplit.second.empty()) {
1934 // If the name didn't have a prefix, check for a code completion request.
1935 if (getToken().isCodeCompletion() && opName.back() == '.')
1936 return codeCompleteOperationName(dialectName);
1937
1938 dialectName = getState().defaultDialectStack.back();
1939 opNameStorage = (dialectName + "." + opName).str();
1940 opName = opNameStorage;
1941 }
1942
1943 // Try to load the dialect before returning the operation name to make sure
1944 // the operation has a chance to be registered.
1945 getContext()->getOrLoadDialect(name: dialectName);
1946 return OperationName(opName, getContext());
1947}
1948
1949Operation *
1950OperationParser::parseCustomOperation(ArrayRef<ResultRecord> resultIDs) {
1951 SMLoc opLoc = getToken().getLoc();
1952 StringRef originalOpName = getTokenSpelling();
1953
1954 FailureOr<OperationName> opNameInfo = parseCustomOperationName();
1955 if (failed(result: opNameInfo))
1956 return nullptr;
1957 StringRef opName = opNameInfo->getStringRef();
1958
1959 // This is the actual hook for the custom op parsing, usually implemented by
1960 // the op itself (`Op::parse()`). We retrieve it either from the
1961 // RegisteredOperationName or from the Dialect.
1962 OperationName::ParseAssemblyFn parseAssemblyFn;
1963 bool isIsolatedFromAbove = false;
1964
1965 StringRef defaultDialect = "";
1966 if (auto opInfo = opNameInfo->getRegisteredInfo()) {
1967 parseAssemblyFn = opInfo->getParseAssemblyFn();
1968 isIsolatedFromAbove = opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>();
1969 auto *iface = opInfo->getInterface<OpAsmOpInterface>();
1970 if (iface && !iface->getDefaultDialect().empty())
1971 defaultDialect = iface->getDefaultDialect();
1972 } else {
1973 std::optional<Dialect::ParseOpHook> dialectHook;
1974 Dialect *dialect = opNameInfo->getDialect();
1975 if (!dialect) {
1976 InFlightDiagnostic diag =
1977 emitError(loc: opLoc) << "Dialect `" << opNameInfo->getDialectNamespace()
1978 << "' not found for custom op '" << originalOpName
1979 << "' ";
1980 if (originalOpName != opName)
1981 diag << " (tried '" << opName << "' as well)";
1982 auto &note = diag.attachNote();
1983 note << "Registered dialects: ";
1984 llvm::interleaveComma(c: getContext()->getAvailableDialects(), os&: note,
1985 each_fn: [&](StringRef dialect) { note << dialect; });
1986 note << " ; for more info on dialect registration see "
1987 "https://mlir.llvm.org/getting_started/Faq/"
1988 "#registered-loaded-dependent-whats-up-with-dialects-management";
1989 return nullptr;
1990 }
1991 dialectHook = dialect->getParseOperationHook(opName);
1992 if (!dialectHook) {
1993 InFlightDiagnostic diag =
1994 emitError(loc: opLoc) << "custom op '" << originalOpName << "' is unknown";
1995 if (originalOpName != opName)
1996 diag << " (tried '" << opName << "' as well)";
1997 return nullptr;
1998 }
1999 parseAssemblyFn = *dialectHook;
2000 }
2001 getState().defaultDialectStack.push_back(Elt: defaultDialect);
2002 auto restoreDefaultDialect = llvm::make_scope_exit(
2003 F: [&]() { getState().defaultDialectStack.pop_back(); });
2004
2005 // If the custom op parser crashes, produce some indication to help
2006 // debugging.
2007 llvm::PrettyStackTraceFormat fmt("MLIR Parser: custom op parser '%s'",
2008 opNameInfo->getIdentifier().data());
2009
2010 // Get location information for the operation.
2011 auto srcLocation = getEncodedSourceLocation(loc: opLoc);
2012 OperationState opState(srcLocation, *opNameInfo);
2013
2014 // If we are populating the parser state, start a new operation definition.
2015 if (state.asmState)
2016 state.asmState->startOperationDefinition(opName: opState.name);
2017
2018 // Have the op implementation take a crack and parsing this.
2019 CleanupOpStateRegions guard{.state: opState};
2020 CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn,
2021 isIsolatedFromAbove, opName, *this);
2022 if (opAsmParser.parseOperation(opState))
2023 return nullptr;
2024
2025 // If it emitted an error, we failed.
2026 if (opAsmParser.didEmitError())
2027 return nullptr;
2028
2029 Attribute properties = opState.propertiesAttr;
2030 opState.propertiesAttr = Attribute{};
2031
2032 // Otherwise, create the operation and try to parse a location for it.
2033 Operation *op = opBuilder.create(state: opState);
2034 if (parseTrailingLocationSpecifier(opOrArgument: op))
2035 return nullptr;
2036
2037 // Try setting the properties for the operation.
2038 if (properties) {
2039 auto emitError = [&]() {
2040 return mlir::emitError(loc: srcLocation, message: "invalid properties ")
2041 << properties << " for op " << op->getName().getStringRef()
2042 << ": ";
2043 };
2044 if (failed(result: op->setPropertiesFromAttribute(attr: properties, emitError)))
2045 return nullptr;
2046 }
2047 return op;
2048}
2049
2050ParseResult OperationParser::parseLocationAlias(LocationAttr &loc) {
2051 Token tok = getToken();
2052 consumeToken(kind: Token::hash_identifier);
2053 StringRef identifier = tok.getSpelling().drop_front();
2054 if (identifier.contains(C: '.')) {
2055 return emitError(loc: tok.getLoc())
2056 << "expected location, but found dialect attribute: '#" << identifier
2057 << "'";
2058 }
2059 if (state.asmState)
2060 state.asmState->addAttrAliasUses(name: identifier, locations: tok.getLocRange());
2061
2062 // If this alias can be resolved, do it now.
2063 Attribute attr = state.symbols.attributeAliasDefinitions.lookup(Key: identifier);
2064 if (attr) {
2065 if (!(loc = dyn_cast<LocationAttr>(Val&: attr)))
2066 return emitError(loc: tok.getLoc())
2067 << "expected location, but found '" << attr << "'";
2068 } else {
2069 // Otherwise, remember this operation and resolve its location later.
2070 // In the meantime, use a special OpaqueLoc as a marker.
2071 loc = OpaqueLoc::get(deferredLocsReferences.size(),
2072 TypeID::get<DeferredLocInfo *>(),
2073 UnknownLoc::get(getContext()));
2074 deferredLocsReferences.push_back(x: DeferredLocInfo{.loc: tok.getLoc(), .identifier: identifier});
2075 }
2076 return success();
2077}
2078
2079ParseResult
2080OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) {
2081 // If there is a 'loc' we parse a trailing location.
2082 if (!consumeIf(kind: Token::kw_loc))
2083 return success();
2084 if (parseToken(expectedToken: Token::l_paren, message: "expected '(' in location"))
2085 return failure();
2086 Token tok = getToken();
2087
2088 // Check to see if we are parsing a location alias.
2089 // Otherwise, we parse the location directly.
2090 LocationAttr directLoc;
2091 if (tok.is(k: Token::hash_identifier)) {
2092 if (parseLocationAlias(loc&: directLoc))
2093 return failure();
2094 } else if (parseLocationInstance(loc&: directLoc)) {
2095 return failure();
2096 }
2097
2098 if (parseToken(expectedToken: Token::r_paren, message: "expected ')' in location"))
2099 return failure();
2100
2101 if (auto *op = llvm::dyn_cast_if_present<Operation *>(Val&: opOrArgument))
2102 op->setLoc(directLoc);
2103 else
2104 opOrArgument.get<BlockArgument>().setLoc(directLoc);
2105 return success();
2106}
2107
2108//===----------------------------------------------------------------------===//
2109// Region Parsing
2110//===----------------------------------------------------------------------===//
2111
2112ParseResult OperationParser::parseRegion(Region &region,
2113 ArrayRef<Argument> entryArguments,
2114 bool isIsolatedNameScope) {
2115 // Parse the '{'.
2116 Token lBraceTok = getToken();
2117 if (parseToken(expectedToken: Token::l_brace, message: "expected '{' to begin a region"))
2118 return failure();
2119
2120 // If we are populating the parser state, start a new region definition.
2121 if (state.asmState)
2122 state.asmState->startRegionDefinition();
2123
2124 // Parse the region body.
2125 if ((!entryArguments.empty() || getToken().isNot(k: Token::r_brace)) &&
2126 parseRegionBody(region, startLoc: lBraceTok.getLoc(), entryArguments,
2127 isIsolatedNameScope)) {
2128 return failure();
2129 }
2130 consumeToken(kind: Token::r_brace);
2131
2132 // If we are populating the parser state, finalize this region.
2133 if (state.asmState)
2134 state.asmState->finalizeRegionDefinition();
2135
2136 return success();
2137}
2138
2139ParseResult OperationParser::parseRegionBody(Region &region, SMLoc startLoc,
2140 ArrayRef<Argument> entryArguments,
2141 bool isIsolatedNameScope) {
2142 auto currentPt = opBuilder.saveInsertionPoint();
2143
2144 // Push a new named value scope.
2145 pushSSANameScope(isIsolated: isIsolatedNameScope);
2146
2147 // Parse the first block directly to allow for it to be unnamed.
2148 auto owningBlock = std::make_unique<Block>();
2149 Block *block = owningBlock.get();
2150
2151 // If this block is not defined in the source file, add a definition for it
2152 // now in the assembly state. Blocks with a name will be defined when the name
2153 // is parsed.
2154 if (state.asmState && getToken().isNot(k: Token::caret_identifier))
2155 state.asmState->addDefinition(block, location: startLoc);
2156
2157 // Add arguments to the entry block if we had the form with explicit names.
2158 if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) {
2159 // If we had named arguments, then don't allow a block name.
2160 if (getToken().is(k: Token::caret_identifier))
2161 return emitError(message: "invalid block name in region with named arguments");
2162
2163 for (auto &entryArg : entryArguments) {
2164 auto &argInfo = entryArg.ssaName;
2165
2166 // Ensure that the argument was not already defined.
2167 if (auto defLoc = getReferenceLoc(name: argInfo.name, number: argInfo.number)) {
2168 return emitError(loc: argInfo.location, message: "region entry argument '" +
2169 argInfo.name +
2170 "' is already in use")
2171 .attachNote(noteLoc: getEncodedSourceLocation(loc: *defLoc))
2172 << "previously referenced here";
2173 }
2174 Location loc = entryArg.sourceLoc.has_value()
2175 ? *entryArg.sourceLoc
2176 : getEncodedSourceLocation(loc: argInfo.location);
2177 BlockArgument arg = block->addArgument(type: entryArg.type, loc);
2178
2179 // Add a definition of this arg to the assembly state if provided.
2180 if (state.asmState)
2181 state.asmState->addDefinition(blockArg: arg, location: argInfo.location);
2182
2183 // Record the definition for this argument.
2184 if (addDefinition(useInfo: argInfo, value: arg))
2185 return failure();
2186 }
2187 }
2188
2189 if (parseBlock(block))
2190 return failure();
2191
2192 // Verify that no other arguments were parsed.
2193 if (!entryArguments.empty() &&
2194 block->getNumArguments() > entryArguments.size()) {
2195 return emitError(message: "entry block arguments were already defined");
2196 }
2197
2198 // Parse the rest of the region.
2199 region.push_back(block: owningBlock.release());
2200 while (getToken().isNot(k: Token::r_brace)) {
2201 Block *newBlock = nullptr;
2202 if (parseBlock(block&: newBlock))
2203 return failure();
2204 region.push_back(block: newBlock);
2205 }
2206
2207 // Pop the SSA value scope for this region.
2208 if (popSSANameScope())
2209 return failure();
2210
2211 // Reset the original insertion point.
2212 opBuilder.restoreInsertionPoint(ip: currentPt);
2213 return success();
2214}
2215
2216//===----------------------------------------------------------------------===//
2217// Block Parsing
2218//===----------------------------------------------------------------------===//
2219
2220/// Block declaration.
2221///
2222/// block ::= block-label? operation*
2223/// block-label ::= block-id block-arg-list? `:`
2224/// block-id ::= caret-id
2225/// block-arg-list ::= `(` ssa-id-and-type-list? `)`
2226///
2227ParseResult OperationParser::parseBlock(Block *&block) {
2228 // The first block of a region may already exist, if it does the caret
2229 // identifier is optional.
2230 if (block && getToken().isNot(k: Token::caret_identifier))
2231 return parseBlockBody(block);
2232
2233 SMLoc nameLoc = getToken().getLoc();
2234 auto name = getTokenSpelling();
2235 if (parseToken(expectedToken: Token::caret_identifier, message: "expected block name"))
2236 return failure();
2237
2238 // Define the block with the specified name.
2239 auto &blockAndLoc = getBlockInfoByName(name);
2240 blockAndLoc.loc = nameLoc;
2241
2242 // Use a unique pointer for in-flight block being parsed. Release ownership
2243 // only in the case of a successful parse. This ensures that the Block
2244 // allocated is released if the parse fails and control returns early.
2245 std::unique_ptr<Block> inflightBlock;
2246 auto cleanupOnFailure = llvm::make_scope_exit(F: [&] {
2247 if (inflightBlock)
2248 inflightBlock->dropAllDefinedValueUses();
2249 });
2250
2251 // If a block has yet to be set, this is a new definition. If the caller
2252 // provided a block, use it. Otherwise create a new one.
2253 if (!blockAndLoc.block) {
2254 if (block) {
2255 blockAndLoc.block = block;
2256 } else {
2257 inflightBlock = std::make_unique<Block>();
2258 blockAndLoc.block = inflightBlock.get();
2259 }
2260
2261 // Otherwise, the block has a forward declaration. Forward declarations are
2262 // removed once defined, so if we are defining a existing block and it is
2263 // not a forward declaration, then it is a redeclaration. Fail if the block
2264 // was already defined.
2265 } else if (!eraseForwardRef(block: blockAndLoc.block)) {
2266 return emitError(loc: nameLoc, message: "redefinition of block '") << name << "'";
2267 } else {
2268 // This was a forward reference block that is now floating. Keep track of it
2269 // as inflight in case of error, so that it gets cleaned up properly.
2270 inflightBlock.reset(p: blockAndLoc.block);
2271 }
2272
2273 // Populate the high level assembly state if necessary.
2274 if (state.asmState)
2275 state.asmState->addDefinition(block: blockAndLoc.block, location: nameLoc);
2276 block = blockAndLoc.block;
2277
2278 // If an argument list is present, parse it.
2279 if (getToken().is(k: Token::l_paren))
2280 if (parseOptionalBlockArgList(owner: block))
2281 return failure();
2282 if (parseToken(expectedToken: Token::colon, message: "expected ':' after block name"))
2283 return failure();
2284
2285 // Parse the body of the block.
2286 ParseResult res = parseBlockBody(block);
2287
2288 // If parsing was successful, drop the inflight block. We relinquish ownership
2289 // back up to the caller.
2290 if (succeeded(result: res))
2291 (void)inflightBlock.release();
2292 return res;
2293}
2294
2295ParseResult OperationParser::parseBlockBody(Block *block) {
2296 // Set the insertion point to the end of the block to parse.
2297 opBuilder.setInsertionPointToEnd(block);
2298
2299 // Parse the list of operations that make up the body of the block.
2300 while (getToken().isNot(k1: Token::caret_identifier, k2: Token::r_brace))
2301 if (parseOperation())
2302 return failure();
2303
2304 return success();
2305}
2306
2307/// Get the block with the specified name, creating it if it doesn't already
2308/// exist. The location specified is the point of use, which allows
2309/// us to diagnose references to blocks that are not defined precisely.
2310Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
2311 BlockDefinition &blockDef = getBlockInfoByName(name);
2312 if (!blockDef.block) {
2313 blockDef = {.block: new Block(), .loc: loc};
2314 insertForwardRef(block: blockDef.block, loc: blockDef.loc);
2315 }
2316
2317 // Populate the high level assembly state if necessary.
2318 if (state.asmState)
2319 state.asmState->addUses(block: blockDef.block, locations: loc);
2320
2321 return blockDef.block;
2322}
2323
2324/// Parse a (possibly empty) list of SSA operands with types as block arguments
2325/// enclosed in parentheses.
2326///
2327/// value-id-and-type-list ::= value-id-and-type (`,` ssa-id-and-type)*
2328/// block-arg-list ::= `(` value-id-and-type-list? `)`
2329///
2330ParseResult OperationParser::parseOptionalBlockArgList(Block *owner) {
2331 if (getToken().is(k: Token::r_brace))
2332 return success();
2333
2334 // If the block already has arguments, then we're handling the entry block.
2335 // Parse and register the names for the arguments, but do not add them.
2336 bool definingExistingArgs = owner->getNumArguments() != 0;
2337 unsigned nextArgument = 0;
2338
2339 return parseCommaSeparatedList(delimiter: Delimiter::Paren, parseElementFn: [&]() -> ParseResult {
2340 return parseSSADefOrUseAndType(
2341 action: [&](UnresolvedOperand useInfo, Type type) -> ParseResult {
2342 BlockArgument arg;
2343
2344 // If we are defining existing arguments, ensure that the argument
2345 // has already been created with the right type.
2346 if (definingExistingArgs) {
2347 // Otherwise, ensure that this argument has already been created.
2348 if (nextArgument >= owner->getNumArguments())
2349 return emitError(message: "too many arguments specified in argument list");
2350
2351 // Finally, make sure the existing argument has the correct type.
2352 arg = owner->getArgument(i: nextArgument++);
2353 if (arg.getType() != type)
2354 return emitError(message: "argument and block argument type mismatch");
2355 } else {
2356 auto loc = getEncodedSourceLocation(loc: useInfo.location);
2357 arg = owner->addArgument(type, loc);
2358 }
2359
2360 // If the argument has an explicit loc(...) specifier, parse and apply
2361 // it.
2362 if (parseTrailingLocationSpecifier(opOrArgument: arg))
2363 return failure();
2364
2365 // Mark this block argument definition in the parser state if it was
2366 // provided.
2367 if (state.asmState)
2368 state.asmState->addDefinition(blockArg: arg, location: useInfo.location);
2369
2370 return addDefinition(useInfo, value: arg);
2371 });
2372 });
2373}
2374
2375//===----------------------------------------------------------------------===//
2376// Code Completion
2377//===----------------------------------------------------------------------===//
2378
2379ParseResult OperationParser::codeCompleteSSAUse() {
2380 std::string detailData;
2381 llvm::raw_string_ostream detailOS(detailData);
2382 for (IsolatedSSANameScope &scope : isolatedNameScopes) {
2383 for (auto &it : scope.values) {
2384 if (it.second.empty())
2385 continue;
2386 Value frontValue = it.second.front().value;
2387
2388 // If the value isn't a forward reference, we also add the name of the op
2389 // to the detail.
2390 if (auto result = dyn_cast<OpResult>(Val&: frontValue)) {
2391 if (!forwardRefPlaceholders.count(Val: result))
2392 detailOS << result.getOwner()->getName() << ": ";
2393 } else {
2394 detailOS << "arg #" << cast<BlockArgument>(Val&: frontValue).getArgNumber()
2395 << ": ";
2396 }
2397
2398 // Emit the type of the values to aid with completion selection.
2399 detailOS << frontValue.getType();
2400
2401 // FIXME: We should define a policy for packed values, e.g. with a limit
2402 // on the detail size, but it isn't clear what would be useful right now.
2403 // For now we just only emit the first type.
2404 if (it.second.size() > 1)
2405 detailOS << ", ...";
2406
2407 state.codeCompleteContext->appendSSAValueCompletion(
2408 name: it.getKey(), typeData: std::move(detailOS.str()));
2409 }
2410 }
2411
2412 return failure();
2413}
2414
2415ParseResult OperationParser::codeCompleteBlock() {
2416 // Don't provide completions if the token isn't empty, e.g. this avoids
2417 // weirdness when we encounter a `.` within the identifier.
2418 StringRef spelling = getTokenSpelling();
2419 if (!(spelling.empty() || spelling == "^"))
2420 return failure();
2421
2422 for (const auto &it : blocksByName.back())
2423 state.codeCompleteContext->appendBlockCompletion(name: it.getFirst());
2424 return failure();
2425}
2426
2427//===----------------------------------------------------------------------===//
2428// Top-level entity parsing.
2429//===----------------------------------------------------------------------===//
2430
2431namespace {
2432/// This parser handles entities that are only valid at the top level of the
2433/// file.
2434class TopLevelOperationParser : public Parser {
2435public:
2436 explicit TopLevelOperationParser(ParserState &state) : Parser(state) {}
2437
2438 /// Parse a set of operations into the end of the given Block.
2439 ParseResult parse(Block *topLevelBlock, Location parserLoc);
2440
2441private:
2442 /// Parse an attribute alias declaration.
2443 ///
2444 /// attribute-alias-def ::= '#' alias-name `=` attribute-value
2445 ///
2446 ParseResult parseAttributeAliasDef();
2447
2448 /// Parse a type alias declaration.
2449 ///
2450 /// type-alias-def ::= '!' alias-name `=` type
2451 ///
2452 ParseResult parseTypeAliasDef();
2453
2454 /// Parse a top-level file metadata dictionary.
2455 ///
2456 /// file-metadata-dict ::= '{-#' file-metadata-entry* `#-}'
2457 ///
2458 ParseResult parseFileMetadataDictionary();
2459
2460 /// Parse a resource metadata dictionary.
2461 ParseResult parseResourceFileMetadata(
2462 function_ref<ParseResult(StringRef, SMLoc)> parseBody);
2463 ParseResult parseDialectResourceFileMetadata();
2464 ParseResult parseExternalResourceFileMetadata();
2465};
2466
2467/// This class represents an implementation of a resource entry for the MLIR
2468/// textual format.
2469class ParsedResourceEntry : public AsmParsedResourceEntry {
2470public:
2471 ParsedResourceEntry(StringRef key, SMLoc keyLoc, Token value, Parser &p)
2472 : key(key), keyLoc(keyLoc), value(value), p(p) {}
2473 ~ParsedResourceEntry() override = default;
2474
2475 StringRef getKey() const final { return key; }
2476
2477 InFlightDiagnostic emitError() const final { return p.emitError(loc: keyLoc); }
2478
2479 AsmResourceEntryKind getKind() const final {
2480 if (value.isAny(k1: Token::kw_true, k2: Token::kw_false))
2481 return AsmResourceEntryKind::Bool;
2482 return value.getSpelling().starts_with(Prefix: "\"0x")
2483 ? AsmResourceEntryKind::Blob
2484 : AsmResourceEntryKind::String;
2485 }
2486
2487 FailureOr<bool> parseAsBool() const final {
2488 if (value.is(k: Token::kw_true))
2489 return true;
2490 if (value.is(k: Token::kw_false))
2491 return false;
2492 return p.emitError(loc: value.getLoc(),
2493 message: "expected 'true' or 'false' value for key '" + key +
2494 "'");
2495 }
2496
2497 FailureOr<std::string> parseAsString() const final {
2498 if (value.isNot(k: Token::string))
2499 return p.emitError(loc: value.getLoc(),
2500 message: "expected string value for key '" + key + "'");
2501 return value.getStringValue();
2502 }
2503
2504 FailureOr<AsmResourceBlob>
2505 parseAsBlob(BlobAllocatorFn allocator) const final {
2506 // Blob data within then textual format is represented as a hex string.
2507 // TODO: We could avoid an additional alloc+copy here if we pre-allocated
2508 // the buffer to use during hex processing.
2509 std::optional<std::string> blobData =
2510 value.is(k: Token::string) ? value.getHexStringValue() : std::nullopt;
2511 if (!blobData)
2512 return p.emitError(loc: value.getLoc(),
2513 message: "expected hex string blob for key '" + key + "'");
2514
2515 // Extract the alignment of the blob data, which gets stored at the
2516 // beginning of the string.
2517 if (blobData->size() < sizeof(uint32_t)) {
2518 return p.emitError(loc: value.getLoc(),
2519 message: "expected hex string blob for key '" + key +
2520 "' to encode alignment in first 4 bytes");
2521 }
2522 llvm::support::ulittle32_t align;
2523 memcpy(dest: &align, src: blobData->data(), n: sizeof(uint32_t));
2524 if (align && !llvm::isPowerOf2_32(Value: align)) {
2525 return p.emitError(loc: value.getLoc(),
2526 message: "expected hex string blob for key '" + key +
2527 "' to encode alignment in first 4 bytes, but got "
2528 "non-power-of-2 value: " +
2529 Twine(align));
2530 }
2531
2532 // Get the data portion of the blob.
2533 StringRef data = StringRef(*blobData).drop_front(N: sizeof(uint32_t));
2534 if (data.empty())
2535 return AsmResourceBlob();
2536
2537 // Allocate memory for the blob using the provided allocator and copy the
2538 // data into it.
2539 AsmResourceBlob blob = allocator(data.size(), align);
2540 assert(llvm::isAddrAligned(llvm::Align(align), blob.getData().data()) &&
2541 blob.isMutable() &&
2542 "blob allocator did not return a properly aligned address");
2543 memcpy(dest: blob.getMutableData().data(), src: data.data(), n: data.size());
2544 return blob;
2545 }
2546
2547private:
2548 StringRef key;
2549 SMLoc keyLoc;
2550 Token value;
2551 Parser &p;
2552};
2553} // namespace
2554
2555ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
2556 assert(getToken().is(Token::hash_identifier));
2557 StringRef aliasName = getTokenSpelling().drop_front();
2558
2559 // Check for redefinitions.
2560 if (state.symbols.attributeAliasDefinitions.count(Key: aliasName) > 0)
2561 return emitError(message: "redefinition of attribute alias id '" + aliasName + "'");
2562
2563 // Make sure this isn't invading the dialect attribute namespace.
2564 if (aliasName.contains(C: '.'))
2565 return emitError(message: "attribute names with a '.' are reserved for "
2566 "dialect-defined names");
2567
2568 SMRange location = getToken().getLocRange();
2569 consumeToken(kind: Token::hash_identifier);
2570
2571 // Parse the '='.
2572 if (parseToken(expectedToken: Token::equal, message: "expected '=' in attribute alias definition"))
2573 return failure();
2574
2575 // Parse the attribute value.
2576 Attribute attr = parseAttribute();
2577 if (!attr)
2578 return failure();
2579
2580 // Register this alias with the parser state.
2581 if (state.asmState)
2582 state.asmState->addAttrAliasDefinition(name: aliasName, location, value: attr);
2583 state.symbols.attributeAliasDefinitions[aliasName] = attr;
2584 return success();
2585}
2586
2587ParseResult TopLevelOperationParser::parseTypeAliasDef() {
2588 assert(getToken().is(Token::exclamation_identifier));
2589 StringRef aliasName = getTokenSpelling().drop_front();
2590
2591 // Check for redefinitions.
2592 if (state.symbols.typeAliasDefinitions.count(Key: aliasName) > 0)
2593 return emitError(message: "redefinition of type alias id '" + aliasName + "'");
2594
2595 // Make sure this isn't invading the dialect type namespace.
2596 if (aliasName.contains(C: '.'))
2597 return emitError(message: "type names with a '.' are reserved for "
2598 "dialect-defined names");
2599
2600 SMRange location = getToken().getLocRange();
2601 consumeToken(kind: Token::exclamation_identifier);
2602
2603 // Parse the '='.
2604 if (parseToken(expectedToken: Token::equal, message: "expected '=' in type alias definition"))
2605 return failure();
2606
2607 // Parse the type.
2608 Type aliasedType = parseType();
2609 if (!aliasedType)
2610 return failure();
2611
2612 // Register this alias with the parser state.
2613 if (state.asmState)
2614 state.asmState->addTypeAliasDefinition(name: aliasName, location, value: aliasedType);
2615 state.symbols.typeAliasDefinitions.try_emplace(Key: aliasName, Args&: aliasedType);
2616 return success();
2617}
2618
2619ParseResult TopLevelOperationParser::parseFileMetadataDictionary() {
2620 consumeToken(kind: Token::file_metadata_begin);
2621 return parseCommaSeparatedListUntil(
2622 rightToken: Token::file_metadata_end, parseElement: [&]() -> ParseResult {
2623 // Parse the key of the metadata dictionary.
2624 SMLoc keyLoc = getToken().getLoc();
2625 StringRef key;
2626 if (failed(result: parseOptionalKeyword(keyword: &key)))
2627 return emitError(message: "expected identifier key in file "
2628 "metadata dictionary");
2629 if (parseToken(expectedToken: Token::colon, message: "expected ':'"))
2630 return failure();
2631
2632 // Process the metadata entry.
2633 if (key == "dialect_resources")
2634 return parseDialectResourceFileMetadata();
2635 if (key == "external_resources")
2636 return parseExternalResourceFileMetadata();
2637 return emitError(loc: keyLoc, message: "unknown key '" + key +
2638 "' in file metadata dictionary");
2639 });
2640}
2641
2642ParseResult TopLevelOperationParser::parseResourceFileMetadata(
2643 function_ref<ParseResult(StringRef, SMLoc)> parseBody) {
2644 if (parseToken(expectedToken: Token::l_brace, message: "expected '{'"))
2645 return failure();
2646
2647 return parseCommaSeparatedListUntil(rightToken: Token::r_brace, parseElement: [&]() -> ParseResult {
2648 // Parse the top-level name entry.
2649 SMLoc nameLoc = getToken().getLoc();
2650 StringRef name;
2651 if (failed(result: parseOptionalKeyword(keyword: &name)))
2652 return emitError(message: "expected identifier key for 'resource' entry");
2653
2654 if (parseToken(expectedToken: Token::colon, message: "expected ':'") ||
2655 parseToken(expectedToken: Token::l_brace, message: "expected '{'"))
2656 return failure();
2657 return parseBody(name, nameLoc);
2658 });
2659}
2660
2661ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() {
2662 return parseResourceFileMetadata(parseBody: [&](StringRef name,
2663 SMLoc nameLoc) -> ParseResult {
2664 // Lookup the dialect and check that it can handle a resource entry.
2665 Dialect *dialect = getContext()->getOrLoadDialect(name);
2666 if (!dialect)
2667 return emitError(loc: nameLoc, message: "dialect '" + name + "' is unknown");
2668 const auto *handler = dyn_cast<OpAsmDialectInterface>(Val: dialect);
2669 if (!handler) {
2670 return emitError() << "unexpected 'resource' section for dialect '"
2671 << dialect->getNamespace() << "'";
2672 }
2673
2674 return parseCommaSeparatedListUntil(rightToken: Token::r_brace, parseElement: [&]() -> ParseResult {
2675 // Parse the name of the resource entry.
2676 SMLoc keyLoc = getToken().getLoc();
2677 StringRef key;
2678 if (failed(result: parseResourceHandle(dialect: handler, name&: key)) ||
2679 parseToken(expectedToken: Token::colon, message: "expected ':'"))
2680 return failure();
2681 Token valueTok = getToken();
2682 consumeToken();
2683
2684 ParsedResourceEntry entry(key, keyLoc, valueTok, *this);
2685 return handler->parseResource(entry);
2686 });
2687 });
2688}
2689
2690ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() {
2691 return parseResourceFileMetadata(parseBody: [&](StringRef name,
2692 SMLoc nameLoc) -> ParseResult {
2693 AsmResourceParser *handler = state.config.getResourceParser(name);
2694
2695 // TODO: Should we require handling external resources in some scenarios?
2696 if (!handler) {
2697 emitWarning(loc: getEncodedSourceLocation(loc: nameLoc))
2698 << "ignoring unknown external resources for '" << name << "'";
2699 }
2700
2701 return parseCommaSeparatedListUntil(rightToken: Token::r_brace, parseElement: [&]() -> ParseResult {
2702 // Parse the name of the resource entry.
2703 SMLoc keyLoc = getToken().getLoc();
2704 StringRef key;
2705 if (failed(result: parseOptionalKeyword(keyword: &key)))
2706 return emitError(
2707 message: "expected identifier key for 'external_resources' entry");
2708 if (parseToken(expectedToken: Token::colon, message: "expected ':'"))
2709 return failure();
2710 Token valueTok = getToken();
2711 consumeToken();
2712
2713 if (!handler)
2714 return success();
2715 ParsedResourceEntry entry(key, keyLoc, valueTok, *this);
2716 return handler->parseResource(entry);
2717 });
2718 });
2719}
2720
2721ParseResult TopLevelOperationParser::parse(Block *topLevelBlock,
2722 Location parserLoc) {
2723 // Create a top-level operation to contain the parsed state.
2724 OwningOpRef<ModuleOp> topLevelOp(ModuleOp::create(parserLoc));
2725 OperationParser opParser(state, topLevelOp.get());
2726 while (true) {
2727 switch (getToken().getKind()) {
2728 default:
2729 // Parse a top-level operation.
2730 if (opParser.parseOperation())
2731 return failure();
2732 break;
2733
2734 // If we got to the end of the file, then we're done.
2735 case Token::eof: {
2736 if (opParser.finalize())
2737 return failure();
2738
2739 // Splice the blocks of the parsed operation over to the provided
2740 // top-level block.
2741 auto &parsedOps = topLevelOp->getBody()->getOperations();
2742 auto &destOps = topLevelBlock->getOperations();
2743 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(),
2744 parsedOps.end());
2745 return success();
2746 }
2747
2748 // If we got an error token, then the lexer already emitted an error, just
2749 // stop. Someday we could introduce error recovery if there was demand
2750 // for it.
2751 case Token::error:
2752 return failure();
2753
2754 // Parse an attribute alias.
2755 case Token::hash_identifier:
2756 if (parseAttributeAliasDef())
2757 return failure();
2758 break;
2759
2760 // Parse a type alias.
2761 case Token::exclamation_identifier:
2762 if (parseTypeAliasDef())
2763 return failure();
2764 break;
2765
2766 // Parse a file-level metadata dictionary.
2767 case Token::file_metadata_begin:
2768 if (parseFileMetadataDictionary())
2769 return failure();
2770 break;
2771 }
2772 }
2773}
2774
2775//===----------------------------------------------------------------------===//
2776
2777LogicalResult
2778mlir::parseAsmSourceFile(const llvm::SourceMgr &sourceMgr, Block *block,
2779 const ParserConfig &config, AsmParserState *asmState,
2780 AsmParserCodeCompleteContext *codeCompleteContext) {
2781 const auto *sourceBuf = sourceMgr.getMemoryBuffer(i: sourceMgr.getMainFileID());
2782
2783 Location parserLoc =
2784 FileLineColLoc::get(config.getContext(), sourceBuf->getBufferIdentifier(),
2785 /*line=*/0, /*column=*/0);
2786
2787 SymbolState aliasState;
2788 ParserState state(sourceMgr, config, aliasState, asmState,
2789 codeCompleteContext);
2790 return TopLevelOperationParser(state).parse(topLevelBlock: block, parserLoc);
2791}
2792

source code of mlir/lib/AsmParser/Parser.cpp