1 //===- Parser.cpp - MLIR Parser Implementation ----------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the parser for the MLIR textual form.
11 //===----------------------------------------------------------------------===//
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"
68 using namespace mlir::detail
;
70 //===----------------------------------------------------------------------===//
72 //===----------------------------------------------------------------------===//
74 AsmParserCodeCompleteContext::~AsmParserCodeCompleteContext() = default;
76 //===----------------------------------------------------------------------===//
78 //===----------------------------------------------------------------------===//
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.
84 Parser::parseCommaSeparatedList(Delimiter delimiter
,
85 function_ref
<ParseResult()> parseElementFn
,
86 StringRef contextMessage
) {
90 case Delimiter::OptionalParen
:
91 if (getToken().isNot(Token::l_paren
))
94 case Delimiter::Paren
:
95 if (parseToken(Token::l_paren
, "expected '('" + contextMessage
))
97 // Check for empty list.
98 if (consumeIf(Token::r_paren
))
101 case Delimiter::OptionalLessGreater
:
102 // Check for absent list.
103 if (getToken().isNot(Token::less
))
106 case Delimiter::LessGreater
:
107 if (parseToken(Token::less
, "expected '<'" + contextMessage
))
109 // Check for empty list.
110 if (consumeIf(Token::greater
))
113 case Delimiter::OptionalSquare
:
114 if (getToken().isNot(Token::l_square
))
117 case Delimiter::Square
:
118 if (parseToken(Token::l_square
, "expected '['" + contextMessage
))
120 // Check for empty list.
121 if (consumeIf(Token::r_square
))
124 case Delimiter::OptionalBraces
:
125 if (getToken().isNot(Token::l_brace
))
128 case Delimiter::Braces
:
129 if (parseToken(Token::l_brace
, "expected '{'" + contextMessage
))
131 // Check for empty list.
132 if (consumeIf(Token::r_brace
))
137 // Non-empty case starts with an element.
138 if (parseElementFn())
141 // Otherwise we have a list of comma separated elements.
142 while (consumeIf(Token::comma
)) {
143 if (parseElementFn())
148 case Delimiter::None
:
150 case Delimiter::OptionalParen
:
151 case Delimiter::Paren
:
152 return parseToken(Token::r_paren
, "expected ')'" + contextMessage
);
153 case Delimiter::OptionalLessGreater
:
154 case Delimiter::LessGreater
:
155 return parseToken(Token::greater
, "expected '>'" + contextMessage
);
156 case Delimiter::OptionalSquare
:
157 case Delimiter::Square
:
158 return parseToken(Token::r_square
, "expected ']'" + contextMessage
);
159 case Delimiter::OptionalBraces
:
160 case Delimiter::Braces
:
161 return parseToken(Token::r_brace
, "expected '}'" + contextMessage
);
163 llvm_unreachable("Unknown delimiter");
166 /// Parse a comma-separated list of elements, terminated with an arbitrary
167 /// token. This allows empty lists if allowEmptyList is true.
169 /// abstract-list ::= rightToken // if allowEmptyList == true
170 /// abstract-list ::= element (',' element)* rightToken
173 Parser::parseCommaSeparatedListUntil(Token::Kind rightToken
,
174 function_ref
<ParseResult()> parseElement
,
175 bool allowEmptyList
) {
176 // Handle the empty case.
177 if (getToken().is(rightToken
)) {
179 return emitWrongTokenError("expected list element");
180 consumeToken(rightToken
);
184 if (parseCommaSeparatedList(parseElement
) ||
185 parseToken(rightToken
, "expected ',' or '" +
186 Token::getTokenSpelling(rightToken
) + "'"))
192 InFlightDiagnostic
Parser::emitError(const Twine
&message
) {
193 auto loc
= state
.curToken
.getLoc();
194 if (state
.curToken
.isNot(Token::eof
))
195 return emitError(loc
, message
);
197 // If the error is to be emitted at EOF, move it back one character.
198 return emitError(SMLoc::getFromPointer(loc
.getPointer() - 1), message
);
201 InFlightDiagnostic
Parser::emitError(SMLoc loc
, const Twine
&message
) {
202 auto diag
= mlir::emitError(getEncodedSourceLocation(loc
), message
);
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(Token::error
))
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.
215 InFlightDiagnostic
Parser::emitWrongTokenError(const Twine
&message
) {
216 auto loc
= state
.curToken
.getLoc();
218 // If the error is to be emitted at EOF, move it back one character.
219 if (state
.curToken
.is(Token::eof
))
220 loc
= SMLoc::getFromPointer(loc
.getPointer() - 1);
222 // This is the location we were originally asked to report the error at.
223 auto originalLoc
= loc
;
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();
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
);
233 // Back up over entirely blank lines.
235 // Back up until we see a \n, but don't look past the buffer start.
236 startOfBuffer
= startOfBuffer
.rtrim(" \t");
238 // For tokens with no preceding source line, just emit at the original
240 if (startOfBuffer
.empty())
241 return emitError(originalLoc
, message
);
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(SMLoc::getFromPointer(startOfBuffer
.end()), message
);
247 // Drop the \n so we emit the diagnostic at the end of the line.
248 startOfBuffer
= startOfBuffer
.drop_back();
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("\n\r");
255 if (newLineIndex
!= StringRef::npos
)
256 prevLine
= prevLine
.drop_front(newLineIndex
);
258 // If we find a // in the current line, then emit the diagnostic before it.
259 size_t commentStart
= prevLine
.find("//");
260 if (commentStart
!= StringRef::npos
)
261 startOfBuffer
= startOfBuffer
.drop_back(prevLine
.size() - commentStart
);
265 /// Consume the specified token if present and return success. On failure,
266 /// output a diagnostic and return failure.
267 ParseResult
Parser::parseToken(Token::Kind expectedToken
,
268 const Twine
&message
) {
269 if (consumeIf(expectedToken
))
271 return emitWrongTokenError(message
);
274 /// Parse an optional integer value from the stream.
275 OptionalParseResult
Parser::parseOptionalInteger(APInt
&result
) {
276 // Parse `false` and `true` keywords as 0 and 1 respectively.
277 if (consumeIf(Token::kw_false
)) {
281 if (consumeIf(Token::kw_true
)) {
286 Token curToken
= getToken();
287 if (curToken
.isNot(Token::integer
, Token::minus
))
290 bool negative
= consumeIf(Token::minus
);
291 Token curTok
= getToken();
292 if (parseToken(Token::integer
, "expected integer value"))
295 StringRef spelling
= curTok
.getSpelling();
296 bool isHex
= spelling
.size() > 1 && spelling
[1] == 'x';
297 if (spelling
.getAsInteger(isHex
? 0 : 10, result
))
298 return emitError(curTok
.getLoc(), "integer value too large");
300 // Make sure we have a zero at the top so we return the right signedness.
301 if (result
.isNegative())
302 result
= result
.zext(result
.getBitWidth() + 1);
304 // Process the negative sign if present.
311 /// Parse a floating point value from an integer literal token.
312 ParseResult
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';
319 return emitError(loc
, "unexpected decimal integer literal for a "
320 "floating point value")
322 << "add a trailing dot to make the literal a float";
325 return emitError(loc
, "hexadecimal float literal should not have a "
329 std::optional
<uint64_t> value
= tok
.getUInt64IntegerValue();
331 return emitError(loc
, "hexadecimal float constant out of range for type");
333 if (&semantics
== &APFloat::IEEEdouble()) {
334 result
= APFloat(semantics
, APInt(typeSizeInBits
, *value
));
338 APInt
apInt(typeSizeInBits
, *value
);
340 return emitError(loc
, "hexadecimal float constant out of range for type");
341 result
= APFloat(semantics
, apInt
);
346 ParseResult
Parser::parseOptionalKeyword(StringRef
*keyword
) {
347 // Check that the current token is a keyword.
348 if (!isCurrentTokenAKeyword())
351 *keyword
= getTokenSpelling();
356 //===----------------------------------------------------------------------===//
359 FailureOr
<AsmDialectResourceHandle
>
360 Parser::parseResourceHandle(const OpAsmDialectInterface
*dialect
,
362 assert(dialect
&& "expected valid dialect interface");
363 SMLoc nameLoc
= getToken().getLoc();
364 if (failed(parseOptionalKeyword(&name
)))
365 return emitError("expected identifier key for 'resource' entry");
366 auto &resources
= getState().symbols
.dialectResources
;
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(name
);
375 if (failed(result
)) {
376 return emitError(nameLoc
)
377 << "unknown 'resource' key '" << name
<< "' for dialect '"
378 << dialect
->getDialect()->getNamespace() << "'";
380 entry
.first
= dialect
->getResourceKey(*result
);
381 entry
.second
= *result
;
388 FailureOr
<AsmDialectResourceHandle
>
389 Parser::parseResourceHandle(Dialect
*dialect
) {
390 const auto *interface
= dyn_cast
<OpAsmDialectInterface
>(dialect
);
392 return emitError() << "dialect '" << dialect
->getNamespace()
393 << "' does not expect resource handles";
395 StringRef resourceName
;
396 return parseResourceHandle(interface
, resourceName
);
399 //===----------------------------------------------------------------------===//
402 ParseResult
Parser::codeCompleteDialectName() {
403 state
.codeCompleteContext
->completeDialectName();
407 ParseResult
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('.'))
413 state
.codeCompleteContext
->completeOperationName(dialectName
);
417 ParseResult
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(*it
))
430 if (shouldIgnoreOpCompletion())
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(state
.defaultDialectStack
.back());
440 ParseResult
Parser::codeCompleteStringDialectOrOperationName(StringRef name
) {
441 // If the name is empty, this is the start of the string and contains the
444 return codeCompleteDialectName();
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("."))
449 return codeCompleteOperationName(name
);
453 ParseResult
Parser::codeCompleteExpectedTokens(ArrayRef
<StringRef
> tokens
) {
454 state
.codeCompleteContext
->completeExpectedTokens(tokens
, /*optional=*/false);
457 ParseResult
Parser::codeCompleteOptionalTokens(ArrayRef
<StringRef
> tokens
) {
458 state
.codeCompleteContext
->completeExpectedTokens(tokens
, /*optional=*/true);
462 Attribute
Parser::codeCompleteAttribute() {
463 state
.codeCompleteContext
->completeAttribute(
464 state
.symbols
.attributeAliasDefinitions
);
467 Type
Parser::codeCompleteType() {
468 state
.codeCompleteContext
->completeType(state
.symbols
.typeAliasDefinitions
);
473 Parser::codeCompleteDialectSymbol(const llvm::StringMap
<Attribute
> &aliases
) {
474 state
.codeCompleteContext
->completeDialectAttributeOrAlias(aliases
);
477 Type
Parser::codeCompleteDialectSymbol(const llvm::StringMap
<Type
> &aliases
) {
478 state
.codeCompleteContext
->completeDialectTypeOrAlias(aliases
);
482 //===----------------------------------------------------------------------===//
484 //===----------------------------------------------------------------------===//
487 /// This class provides support for parsing operations and regions of
489 class OperationParser
: public Parser
{
491 OperationParser(ParserState
&state
, ModuleOp topLevelOp
);
494 /// After parsing is finished, this function must be called to see if there
495 /// are any remaining issues.
496 ParseResult
finalize();
498 //===--------------------------------------------------------------------===//
499 // SSA Value Handling
500 //===--------------------------------------------------------------------===//
502 using UnresolvedOperand
= OpAsmParser::UnresolvedOperand
;
503 using Argument
= OpAsmParser::Argument
;
505 struct DeferredLocInfo
{
507 StringRef identifier
;
510 /// Push a new SSA name scope to the parser.
511 void pushSSANameScope(bool isIsolated
);
513 /// Pop the last SSA name scope from the parser.
514 ParseResult
popSSANameScope();
516 /// Register a definition of a value with the symbol table.
517 ParseResult
addDefinition(UnresolvedOperand useInfo
, Value value
);
519 /// Parse an optional list of SSA uses into 'results'.
521 parseOptionalSSAUseList(SmallVectorImpl
<UnresolvedOperand
> &results
);
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);
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
);
532 ParseResult
parseSSADefOrUseAndType(
533 function_ref
<ParseResult(UnresolvedOperand
, Type
)> action
);
535 ParseResult
parseOptionalSSAUseAndTypeList(SmallVectorImpl
<Value
> &results
);
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(name
) || number
>= values
[name
].size())
543 if (values
[name
][number
].value
)
544 return values
[name
][number
].loc
;
548 //===--------------------------------------------------------------------===//
550 //===--------------------------------------------------------------------===//
552 /// Parse an operation instance.
553 ParseResult
parseOperation();
555 /// Parse a single operation successor.
556 ParseResult
parseSuccessor(Block
*&dest
);
558 /// Parse a comma-separated list of operation successors in brackets.
559 ParseResult
parseSuccessors(SmallVectorImpl
<Block
*> &destinations
);
561 /// Parse an operation instance that is in the generic form.
562 Operation
*parseGenericOperation();
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
=
573 std::optional
<ArrayRef
<Block
*>> parsedSuccessors
= std::nullopt
,
574 std::optional
<MutableArrayRef
<std::unique_ptr
<Region
>>> parsedRegions
=
576 std::optional
<ArrayRef
<NamedAttribute
>> parsedAttributes
= std::nullopt
,
577 std::optional
<Attribute
> propertiesAttribute
= std::nullopt
,
578 std::optional
<FunctionType
> parsedFnType
= std::nullopt
);
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
);
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
588 using OpOrArgument
= llvm::PointerUnion
<Operation
*, BlockArgument
>;
590 /// Parse an optional trailing location and add it to the specifier Operation
591 /// or `UnresolvedOperand` if present.
593 /// trailing-location ::= (`loc` (`(` location `)` | attribute-alias))?
595 ParseResult
parseTrailingLocationSpecifier(OpOrArgument opOrArgument
);
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
);
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
>;
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
);
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();
614 //===--------------------------------------------------------------------===//
616 //===--------------------------------------------------------------------===//
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
®ion
, ArrayRef
<Argument
> entryArguments
,
622 bool isIsolatedNameScope
= false);
624 /// Parse a region body into 'region'.
625 ParseResult
parseRegionBody(Region
®ion
, SMLoc startLoc
,
626 ArrayRef
<Argument
> entryArguments
,
627 bool isIsolatedNameScope
);
629 //===--------------------------------------------------------------------===//
631 //===--------------------------------------------------------------------===//
633 /// Parse a new block into 'block'.
634 ParseResult
parseBlock(Block
*&block
);
636 /// Parse a list of operations into 'block'.
637 ParseResult
parseBlockBody(Block
*block
);
639 /// Parse a (possibly empty) list of block arguments.
640 ParseResult
parseOptionalBlockArgList(Block
*owner
);
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
);
647 //===--------------------------------------------------------------------===//
649 //===--------------------------------------------------------------------===//
651 /// The set of various code completion methods. Every completion method
652 /// returns `failure` to stop the parsing process after providing completion
655 ParseResult
codeCompleteSSAUse();
656 ParseResult
codeCompleteBlock();
659 /// This class represents a definition of a Block.
660 struct BlockDefinition
{
661 /// A pointer to the defined Block.
663 /// The location that the Block was defined at.
666 /// This class represents a definition of a Value.
667 struct ValueDefinition
{
668 /// A pointer to the defined Value.
670 /// The location that the Value was defined at.
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
];
679 /// Insert a new forward reference to the given block.
680 void insertForwardRef(Block
*block
, SMLoc loc
) {
681 forwardRef
.back().try_emplace(block
, loc
);
684 /// Erase any forward reference to the given block.
685 bool eraseForwardRef(Block
*block
) { return forwardRef
.back().erase(block
); }
687 /// Record that a definition was added at the current scope.
688 void recordDefinition(StringRef def
);
690 /// Get the value entry for the given SSA name.
691 SmallVectorImpl
<ValueDefinition
> &getSSAValueEntry(StringRef name
);
693 /// Create a forward reference placeholder value with the given location and
695 Value
createForwardRefPlaceholder(SMLoc loc
, Type type
);
697 /// Return true if this is a forward reference.
698 bool isForwardRefPlaceholder(Value value
) {
699 return forwardRefPlaceholders
.count(value
);
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(def
);
712 /// Push a nested name scope.
713 void pushSSANameScope() { definitionsPerScope
.push_back({}); }
715 /// Pop a nested name scope.
716 void popSSANameScope() {
717 for (auto &def
: definitionsPerScope
.pop_back_val())
718 values
.erase(def
.getKey());
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
;
725 /// This keeps track of all of the values defined by a specific name scope.
726 SmallVector
<llvm::StringSet
<>, 2> definitionsPerScope
;
729 /// A list of isolated name scopes.
730 SmallVector
<IsolatedSSANameScope
, 2> isolatedNameScopes
;
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
;
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
;
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
;
747 /// The builder used when creating parsed operation instances.
750 /// The top level operation that holds all of the parsed operations.
751 Operation
*topLevelOp
;
755 MLIR_DECLARE_EXPLICIT_TYPE_ID(OperationParser::DeferredLocInfo
*)
756 MLIR_DEFINE_EXPLICIT_TYPE_ID(OperationParser::DeferredLocInfo
*)
758 OperationParser::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);
763 // If we are populating the parser state, prepare it for parsing.
765 state
.asmState
->initialize(topLevelOp
);
768 OperationParser::~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();
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();
785 /// After parsing is finished, this function must be called to see if there are
786 /// any remaining issues.
787 ParseResult
OperationParser::finalize() {
788 // Check for any forward references that are left. If we find any, error
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(entry
.second
.getPointer());
795 llvm::array_pod_sort(errors
.begin(), errors
.end());
797 for (const char *entry
: errors
) {
798 auto loc
= SMLoc::getFromPointer(entry
);
799 emitError(loc
, "use of undeclared SSA value name");
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
)
811 auto locInfo
= deferredLocsReferences
[fwdLoc
.getUnderlyingLocation()];
812 Attribute attr
= attributeAliases
.lookup(locInfo
.identifier
);
814 return this->emitError(locInfo
.loc
)
815 << "operation location alias was never defined";
816 auto locAttr
= dyn_cast
<LocationAttr
>(attr
);
818 return this->emitError(locInfo
.loc
)
819 << "expected location, but found '" << attr
<< "'";
820 opOrArgument
.setLoc(locAttr
);
824 auto walkRes
= topLevelOp
->walk([&](Operation
*op
) {
825 if (failed(resolveLocation(*op
)))
826 return WalkResult::interrupt();
827 for (Region
®ion
: op
->getRegions())
828 for (Block
&block
: region
.getBlocks())
829 for (BlockArgument arg
: block
.getArguments())
830 if (failed(resolveLocation(arg
)))
831 return WalkResult::interrupt();
832 return WalkResult::advance();
834 if (walkRes
.wasInterrupted())
837 // Pop the top level name scope.
838 if (failed(popSSANameScope()))
841 // Verify that the parsed operations are valid.
842 if (state
.config
.shouldVerifyAfterParse() && failed(verify(topLevelOp
)))
845 // If we are populating the parser state, finalize the top-level operation.
847 state
.asmState
->finalize(topLevelOp
);
851 //===----------------------------------------------------------------------===//
852 // SSA Value Handling
853 //===----------------------------------------------------------------------===//
855 void OperationParser::pushSSANameScope(bool isIsolated
) {
856 blocksByName
.push_back(DenseMap
<StringRef
, BlockDefinition
>());
857 forwardRef
.push_back(DenseMap
<Block
*, SMLoc
>());
859 // Push back a new name definition scope.
861 isolatedNameScopes
.push_back({});
862 isolatedNameScopes
.back().pushSSANameScope();
865 ParseResult
OperationParser::popSSANameScope() {
866 auto forwardRefInCurrentScope
= forwardRef
.pop_back_val();
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({entry
.second
.getPointer(), entry
.first
});
874 // Add this block to the top-level region to allow for automatic cleanup.
875 topLevelOp
->getRegion(0).push_back(entry
.first
);
877 llvm::array_pod_sort(errors
.begin(), errors
.end());
879 for (auto entry
: errors
) {
880 auto loc
= SMLoc::getFromPointer(entry
.first
);
881 emitError(loc
, "reference to an undefined block");
886 // Pop the next nested namescope. If there is only one internal namescope,
887 // just pop the isolated scope.
888 auto ¤tNameScope
= isolatedNameScopes
.back();
889 if (currentNameScope
.definitionsPerScope
.size() == 1)
890 isolatedNameScopes
.pop_back();
892 currentNameScope
.popSSANameScope();
894 blocksByName
.pop_back();
898 /// Register a definition of a value with the symbol table.
899 ParseResult
OperationParser::addDefinition(UnresolvedOperand useInfo
,
901 auto &entries
= getSSAValueEntry(useInfo
.name
);
903 // Make sure there is a slot for this value.
904 if (entries
.size() <= useInfo
.number
)
905 entries
.resize(useInfo
.number
+ 1);
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(existing
)) {
911 return emitError(useInfo
.location
)
912 .append("redefinition of SSA value '", useInfo
.name
, "'")
913 .attachNote(getEncodedSourceLocation(entries
[useInfo
.number
].loc
))
914 .append("previously defined here");
917 if (existing
.getType() != value
.getType()) {
918 return emitError(useInfo
.location
)
919 .append("definition of SSA value '", useInfo
.name
, "#",
920 useInfo
.number
, "' has type ", value
.getType())
921 .attachNote(getEncodedSourceLocation(entries
[useInfo
.number
].loc
))
922 .append("previously used here with type ", existing
.getType());
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(value
);
929 existing
.getDefiningOp()->destroy();
930 forwardRefPlaceholders
.erase(existing
);
932 // If a definition of the value already exists, replace it in the assembly
935 state
.asmState
->refineDefinition(existing
, value
);
938 /// Record this definition for the current scope.
939 entries
[useInfo
.number
] = {value
, useInfo
.location
};
940 recordDefinition(useInfo
.name
);
944 /// Parse a (possibly empty) list of SSA operands.
946 /// ssa-use-list ::= ssa-use (`,` ssa-use)*
947 /// ssa-use-list-opt ::= ssa-use-list?
949 ParseResult
OperationParser::parseOptionalSSAUseList(
950 SmallVectorImpl
<UnresolvedOperand
> &results
) {
951 if (!getToken().isOrIsCodeCompletionFor(Token::percent_identifier
))
953 return parseCommaSeparatedList([&]() -> ParseResult
{
954 UnresolvedOperand result
;
955 if (parseSSAUse(result
))
957 results
.push_back(result
);
962 /// Parse a SSA operand for an operation.
964 /// ssa-use ::= ssa-id
966 ParseResult
OperationParser::parseSSAUse(UnresolvedOperand
&result
,
967 bool allowResultNumber
) {
968 if (getToken().isCodeCompletion())
969 return codeCompleteSSAUse();
971 result
.name
= getTokenSpelling();
973 result
.location
= getToken().getLoc();
974 if (parseToken(Token::percent_identifier
, "expected SSA operand"))
977 // If we have an attribute ID, it is a result number.
978 if (getToken().is(Token::hash_identifier
)) {
979 if (!allowResultNumber
)
980 return emitError("result number not allowed in argument list");
982 if (auto value
= getToken().getHashIdentifierNumber())
983 result
.number
= *value
;
985 return emitError("invalid SSA value result number");
986 consumeToken(Token::hash_identifier
);
992 /// Given an unbound reference to an SSA value and its type, return the value
993 /// it specifies. This returns null on failure.
994 Value
OperationParser::resolveSSAUse(UnresolvedOperand useInfo
, Type type
) {
995 auto &entries
= getSSAValueEntry(useInfo
.name
);
997 // Functor used to record the use of the given value if the assembly state
998 // field is populated.
999 auto maybeRecordUse
= [&](Value value
) {
1001 state
.asmState
->addUses(value
, useInfo
.location
);
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
);
1012 emitError(useInfo
.location
, "use of value '")
1013 .append(useInfo
.name
,
1014 "' expects different type than prior uses: ", type
, " vs ",
1016 .attachNote(getEncodedSourceLocation(entries
[useInfo
.number
].loc
))
1017 .append("prior use here");
1021 // Make sure we have enough slots for this.
1022 if (entries
.size() <= useInfo
.number
)
1023 entries
.resize(useInfo
.number
+ 1);
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(entries
[0].value
))
1028 return (emitError(useInfo
.location
, "reference to invalid result number"),
1031 // Otherwise, this is a forward reference. Create a placeholder and remember
1033 Value result
= createForwardRefPlaceholder(useInfo
.location
, type
);
1034 entries
[useInfo
.number
] = {result
, useInfo
.location
};
1035 return maybeRecordUse(result
);
1038 /// Parse an SSA use with an associated type.
1040 /// ssa-use-and-type ::= ssa-use `:` type
1041 ParseResult
OperationParser::parseSSADefOrUseAndType(
1042 function_ref
<ParseResult(UnresolvedOperand
, Type
)> action
) {
1043 UnresolvedOperand useInfo
;
1044 if (parseSSAUse(useInfo
) ||
1045 parseToken(Token::colon
, "expected ':' and type for SSA operand"))
1048 auto type
= parseType();
1052 return action(useInfo
, type
);
1055 /// Parse a (possibly empty) list of SSA operands, followed by a colon, then
1056 /// followed by a type list.
1058 /// ssa-use-and-type-list
1059 /// ::= ssa-use-list ':' type-list-no-parens
1061 ParseResult
OperationParser::parseOptionalSSAUseAndTypeList(
1062 SmallVectorImpl
<Value
> &results
) {
1063 SmallVector
<UnresolvedOperand
, 4> valueIDs
;
1064 if (parseOptionalSSAUseList(valueIDs
))
1067 // If there were no operands, then there is no colon or type lists.
1068 if (valueIDs
.empty())
1071 SmallVector
<Type
, 4> types
;
1072 if (parseToken(Token::colon
, "expected ':' in operand list") ||
1073 parseTypeListNoParens(types
))
1076 if (valueIDs
.size() != types
.size())
1077 return emitError("expected ")
1078 << valueIDs
.size() << " types to match operand list";
1080 results
.reserve(valueIDs
.size());
1081 for (unsigned i
= 0, e
= valueIDs
.size(); i
!= e
; ++i
) {
1082 if (auto value
= resolveSSAUse(valueIDs
[i
], types
[i
]))
1083 results
.push_back(value
);
1091 /// Record that a definition was added at the current scope.
1092 void OperationParser::recordDefinition(StringRef def
) {
1093 isolatedNameScopes
.back().recordDefinition(def
);
1096 /// Get the value entry for the given SSA name.
1097 auto OperationParser::getSSAValueEntry(StringRef name
)
1098 -> SmallVectorImpl
<ValueDefinition
> & {
1099 return isolatedNameScopes
.back().values
[name
];
1102 /// Create and remember a new placeholder for a forward reference.
1103 Value
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.
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
1110 auto name
= OperationName("builtin.unrealized_conversion_cast", getContext());
1111 auto *op
= Operation::create(
1112 getEncodedSourceLocation(loc
), name
, type
, /*operands=*/{},
1113 /*attributes=*/std::nullopt
, /*properties=*/nullptr, /*successors=*/{},
1115 forwardRefPlaceholders
[op
->getResult(0)] = loc
;
1116 return op
->getResult(0);
1119 //===----------------------------------------------------------------------===//
1120 // Operation Parsing
1121 //===----------------------------------------------------------------------===//
1123 /// Parse an operation.
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)
1135 ParseResult
OperationParser::parseOperation() {
1136 auto loc
= getToken().getLoc();
1137 SmallVector
<ResultRecord
, 1> resultIDs
;
1138 size_t numExpectedResults
= 0;
1139 if (getToken().is(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(Token::percent_identifier
,
1145 "expected valid ssa identifier"))
1148 // If the next token is a ':', we parse the expected result count.
1149 size_t expectedSubResults
= 1;
1150 if (consumeIf(Token::colon
)) {
1151 // Check that the next token is an integer.
1152 if (!getToken().is(Token::integer
))
1153 return emitWrongTokenError("expected integer number of results");
1155 // Check that number of results is > 0.
1156 auto val
= getToken().getUInt64IntegerValue();
1157 if (!val
|| *val
< 1)
1159 "expected named operation to have at least 1 result");
1160 consumeToken(Token::integer
);
1161 expectedSubResults
= *val
;
1164 resultIDs
.emplace_back(nameTok
.getSpelling(), expectedSubResults
,
1166 numExpectedResults
+= expectedSubResults
;
1169 if (parseCommaSeparatedList(parseNextResult
))
1172 if (parseToken(Token::equal
, "expected '=' after SSA name"))
1177 Token nameTok
= getToken();
1178 if (nameTok
.is(Token::bare_identifier
) || nameTok
.isKeyword())
1179 op
= parseCustomOperation(resultIDs
);
1180 else if (nameTok
.is(Token::string
))
1181 op
= parseGenericOperation();
1182 else if (nameTok
.isCodeCompletionFor(Token::string
))
1183 return codeCompleteStringDialectOrOperationName(nameTok
.getStringValue());
1184 else if (nameTok
.isCodeCompletion())
1185 return codeCompleteDialectOrElidedOpName(loc
);
1187 return emitWrongTokenError("expected operation name in quotes");
1189 // If parsing of the basic operation failed, then this whole thing fails.
1193 // If the operation had a name, register it.
1194 if (!resultIDs
.empty()) {
1195 if (op
->getNumResults() == 0)
1196 return emitError(loc
, "cannot name an operation with no results");
1197 if (numExpectedResults
!= op
->getNumResults())
1198 return emitError(loc
, "operation defines ")
1199 << op
->getNumResults() << " results but was provided "
1200 << numExpectedResults
<< " to bind";
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(resultIDs
.size());
1207 for (ResultRecord
&record
: resultIDs
) {
1208 asmResultGroups
.emplace_back(resultIt
, std::get
<2>(record
));
1209 resultIt
+= std::get
<1>(record
);
1211 state
.asmState
->finalizeOperationDefinition(
1212 op
, nameTok
.getLocRange(), /*endLoc=*/getToken().getLoc(),
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>(0, std::get
<1>(resIt
))) {
1220 if (addDefinition({std::get
<2>(resIt
), std::get
<0>(resIt
), subRes
},
1221 op
->getResult(opResI
++)))
1226 // Add this operation to the assembly state if it was provided to populate.
1227 } else if (state
.asmState
) {
1228 state
.asmState
->finalizeOperationDefinition(op
, nameTok
.getLocRange(),
1229 /*endLoc=*/getToken().getLoc());
1235 /// Parse a single operation successor.
1237 /// successor ::= block-id
1239 ParseResult
OperationParser::parseSuccessor(Block
*&dest
) {
1240 if (getToken().isCodeCompletion())
1241 return codeCompleteBlock();
1243 // Verify branch is identifier and get the matching block.
1244 if (!getToken().is(Token::caret_identifier
))
1245 return emitWrongTokenError("expected block name");
1246 dest
= getBlockNamed(getTokenSpelling(), getToken().getLoc());
1251 /// Parse a comma-separated list of operation successors in brackets.
1253 /// successor-list ::= `[` successor (`,` successor )* `]`
1256 OperationParser::parseSuccessors(SmallVectorImpl
<Block
*> &destinations
) {
1257 if (parseToken(Token::l_square
, "expected '['"))
1260 auto parseElt
= [this, &destinations
] {
1262 ParseResult res
= parseSuccessor(dest
);
1263 destinations
.push_back(dest
);
1266 return parseCommaSeparatedListUntil(Token::r_square
, parseElt
,
1267 /*allowEmptyList=*/false);
1271 // RAII-style guard for cleaning up the regions in the operation state before
1272 // deleting them. Within the parser, regions may get deleted if parsing failed,
1273 // and other errors may be present, in particular undominated uses. This makes
1274 // sure such uses are deleted.
1275 struct CleanupOpStateRegions
{
1276 ~CleanupOpStateRegions() {
1277 SmallVector
<Region
*, 4> regionsToClean
;
1278 regionsToClean
.reserve(state
.regions
.size());
1279 for (auto ®ion
: state
.regions
)
1281 for (auto &block
: *region
)
1282 block
.dropAllDefinedValueUses();
1284 OperationState
&state
;
1288 ParseResult
OperationParser::parseGenericOperationAfterOpName(
1289 OperationState
&result
,
1290 std::optional
<ArrayRef
<UnresolvedOperand
>> parsedOperandUseInfo
,
1291 std::optional
<ArrayRef
<Block
*>> parsedSuccessors
,
1292 std::optional
<MutableArrayRef
<std::unique_ptr
<Region
>>> parsedRegions
,
1293 std::optional
<ArrayRef
<NamedAttribute
>> parsedAttributes
,
1294 std::optional
<Attribute
> propertiesAttribute
,
1295 std::optional
<FunctionType
> parsedFnType
) {
1297 // Parse the operand list, if not explicitly provided.
1298 SmallVector
<UnresolvedOperand
, 8> opInfo
;
1299 if (!parsedOperandUseInfo
) {
1300 if (parseToken(Token::l_paren
, "expected '(' to start operand list") ||
1301 parseOptionalSSAUseList(opInfo
) ||
1302 parseToken(Token::r_paren
, "expected ')' to end operand list")) {
1305 parsedOperandUseInfo
= opInfo
;
1308 // Parse the successor list, if not explicitly provided.
1309 if (!parsedSuccessors
) {
1310 if (getToken().is(Token::l_square
)) {
1311 // Check if the operation is not a known terminator.
1312 if (!result
.name
.mightHaveTrait
<OpTrait::IsTerminator
>())
1313 return emitError("successors in non-terminator");
1315 SmallVector
<Block
*, 2> successors
;
1316 if (parseSuccessors(successors
))
1318 result
.addSuccessors(successors
);
1321 result
.addSuccessors(*parsedSuccessors
);
1324 // Parse the properties, if not explicitly provided.
1325 if (propertiesAttribute
) {
1326 result
.propertiesAttr
= *propertiesAttribute
;
1327 } else if (consumeIf(Token::less
)) {
1328 result
.propertiesAttr
= parseAttribute();
1329 if (!result
.propertiesAttr
)
1331 if (parseToken(Token::greater
, "expected '>' to close properties"))
1334 // Parse the region list, if not explicitly provided.
1335 if (!parsedRegions
) {
1336 if (consumeIf(Token::l_paren
)) {
1338 // Create temporary regions with the top level region as parent.
1339 result
.regions
.emplace_back(new Region(topLevelOp
));
1340 if (parseRegion(*result
.regions
.back(), /*entryArguments=*/{}))
1342 } while (consumeIf(Token::comma
));
1343 if (parseToken(Token::r_paren
, "expected ')' to end region list"))
1347 result
.addRegions(*parsedRegions
);
1350 // Parse the attributes, if not explicitly provided.
1351 if (!parsedAttributes
) {
1352 if (getToken().is(Token::l_brace
)) {
1353 if (parseAttributeDict(result
.attributes
))
1357 result
.addAttributes(*parsedAttributes
);
1360 // Parse the operation type, if not explicitly provided.
1361 Location typeLoc
= result
.location
;
1362 if (!parsedFnType
) {
1363 if (parseToken(Token::colon
, "expected ':' followed by operation type"))
1366 typeLoc
= getEncodedSourceLocation(getToken().getLoc());
1367 auto type
= parseType();
1370 auto fnType
= dyn_cast
<FunctionType
>(type
);
1372 return mlir::emitError(typeLoc
, "expected function type");
1374 parsedFnType
= fnType
;
1377 result
.addTypes(parsedFnType
->getResults());
1379 // Check that we have the right number of types for the operands.
1380 ArrayRef
<Type
> operandTypes
= parsedFnType
->getInputs();
1381 if (operandTypes
.size() != parsedOperandUseInfo
->size()) {
1382 auto plural
= "s"[parsedOperandUseInfo
->size() == 1];
1383 return mlir::emitError(typeLoc
, "expected ")
1384 << parsedOperandUseInfo
->size() << " operand type" << plural
1385 << " but had " << operandTypes
.size();
1388 // Resolve all of the operands.
1389 for (unsigned i
= 0, e
= parsedOperandUseInfo
->size(); i
!= e
; ++i
) {
1390 result
.operands
.push_back(
1391 resolveSSAUse((*parsedOperandUseInfo
)[i
], operandTypes
[i
]));
1392 if (!result
.operands
.back())
1399 Operation
*OperationParser::parseGenericOperation() {
1400 // Get location information for the operation.
1401 auto srcLocation
= getEncodedSourceLocation(getToken().getLoc());
1403 std::string name
= getToken().getStringValue();
1405 return (emitError("empty operation name is invalid"), nullptr);
1406 if (name
.find('\0') != StringRef::npos
)
1407 return (emitError("null character not allowed in operation name"), nullptr);
1409 consumeToken(Token::string
);
1411 OperationState
result(srcLocation
, name
);
1412 CleanupOpStateRegions guard
{result
};
1414 // Lazy load dialects in the context as needed.
1415 if (!result
.name
.isRegistered()) {
1416 StringRef dialectName
= StringRef(name
).split('.').first
;
1417 if (!getContext()->getLoadedDialect(dialectName
) &&
1418 !getContext()->getOrLoadDialect(dialectName
)) {
1419 if (!getContext()->allowsUnregisteredDialects()) {
1420 // Emit an error if the dialect couldn't be loaded (i.e., it was not
1421 // registered) and unregistered dialects aren't allowed.
1422 emitError("operation being parsed with an unregistered dialect. If "
1423 "this is intended, please use -allow-unregistered-dialect "
1424 "with the MLIR tool used");
1428 // Reload the OperationName now that the dialect is loaded.
1429 result
.name
= OperationName(name
, getContext());
1433 // If we are populating the parser state, start a new operation definition.
1435 state
.asmState
->startOperationDefinition(result
.name
);
1437 if (parseGenericOperationAfterOpName(result
))
1440 // Operation::create() is not allowed to fail, however setting the properties
1441 // from an attribute is a failable operation. So we save the attribute here
1442 // and set it on the operation post-parsing.
1443 Attribute properties
;
1444 std::swap(properties
, result
.propertiesAttr
);
1446 // If we don't have properties in the textual IR, but the operation now has
1447 // support for properties, we support some backward-compatible generic syntax
1448 // for the operation and as such we accept inherent attributes mixed in the
1449 // dictionary of discardable attributes. We pre-validate these here because
1450 // invalid attributes can't be casted to the properties storage and will be
1451 // silently dropped. For example an attribute { foo = 0 : i32 } that is
1452 // declared as F32Attr in ODS would have a C++ type of FloatAttr in the
1453 // properties array. When setting it we would do something like:
1455 // properties.foo = dyn_cast<FloatAttr>(fooAttr);
1457 // which would end up with a null Attribute. The diagnostic from the verifier
1458 // would be "missing foo attribute" instead of something like "expects a 32
1459 // bits float attribute but got a 32 bits integer attribute".
1460 if (!properties
&& !result
.getRawProperties()) {
1461 std::optional
<RegisteredOperationName
> info
=
1462 result
.name
.getRegisteredInfo();
1464 if (failed(info
->verifyInherentAttrs(result
.attributes
, [&]() {
1465 return mlir::emitError(srcLocation
) << "'" << name
<< "' op ";
1471 // Create the operation and try to parse a location for it.
1472 Operation
*op
= opBuilder
.create(result
);
1473 if (parseTrailingLocationSpecifier(op
))
1476 // Try setting the properties for the operation, using a diagnostic to print
1479 auto emitError
= [&]() {
1480 return mlir::emitError(srcLocation
, "invalid properties ")
1481 << properties
<< " for op " << name
<< ": ";
1483 if (failed(op
->setPropertiesFromAttribute(properties
, emitError
)))
1490 Operation
*OperationParser::parseGenericOperation(Block
*insertBlock
,
1491 Block::iterator insertPt
) {
1492 Token nameToken
= getToken();
1494 OpBuilder::InsertionGuard
restoreInsertionPoint(opBuilder
);
1495 opBuilder
.setInsertionPoint(insertBlock
, insertPt
);
1496 Operation
*op
= parseGenericOperation();
1500 // If we are populating the parser asm state, finalize this operation
1503 state
.asmState
->finalizeOperationDefinition(op
, nameToken
.getLocRange(),
1504 /*endLoc=*/getToken().getLoc());
1509 class CustomOpAsmParser
: public AsmParserImpl
<OpAsmParser
> {
1512 SMLoc nameLoc
, ArrayRef
<OperationParser::ResultRecord
> resultIDs
,
1513 function_ref
<ParseResult(OpAsmParser
&, OperationState
&)> parseAssembly
,
1514 bool isIsolatedFromAbove
, StringRef opName
, OperationParser
&parser
)
1515 : AsmParserImpl
<OpAsmParser
>(nameLoc
, parser
), resultIDs(resultIDs
),
1516 parseAssembly(parseAssembly
), isIsolatedFromAbove(isIsolatedFromAbove
),
1517 opName(opName
), parser(parser
) {
1518 (void)isIsolatedFromAbove
; // Only used in assert, silence unused warning.
1521 /// Parse an instance of the operation described by 'opDefinition' into the
1522 /// provided operation state.
1523 ParseResult
parseOperation(OperationState
&opState
) {
1524 if (parseAssembly(*this, opState
))
1526 // Verify that the parsed attributes does not have duplicate attributes.
1527 // This can happen if an attribute set during parsing is also specified in
1528 // the attribute dictionary in the assembly, or the attribute is set
1529 // multiple during parsing.
1530 std::optional
<NamedAttribute
> duplicate
=
1531 opState
.attributes
.findDuplicate();
1533 return emitError(getNameLoc(), "attribute '")
1534 << duplicate
->getName().getValue()
1535 << "' occurs more than once in the attribute list";
1539 Operation
*parseGenericOperation(Block
*insertBlock
,
1540 Block::iterator insertPt
) final
{
1541 return parser
.parseGenericOperation(insertBlock
, insertPt
);
1544 FailureOr
<OperationName
> parseCustomOperationName() final
{
1545 return parser
.parseCustomOperationName();
1548 ParseResult
parseGenericOperationAfterOpName(
1549 OperationState
&result
,
1550 std::optional
<ArrayRef
<UnresolvedOperand
>> parsedUnresolvedOperands
,
1551 std::optional
<ArrayRef
<Block
*>> parsedSuccessors
,
1552 std::optional
<MutableArrayRef
<std::unique_ptr
<Region
>>> parsedRegions
,
1553 std::optional
<ArrayRef
<NamedAttribute
>> parsedAttributes
,
1554 std::optional
<Attribute
> parsedPropertiesAttribute
,
1555 std::optional
<FunctionType
> parsedFnType
) final
{
1556 return parser
.parseGenericOperationAfterOpName(
1557 result
, parsedUnresolvedOperands
, parsedSuccessors
, parsedRegions
,
1558 parsedAttributes
, parsedPropertiesAttribute
, parsedFnType
);
1560 //===--------------------------------------------------------------------===//
1562 //===--------------------------------------------------------------------===//
1564 /// Return the name of the specified result in the specified syntax, as well
1565 /// as the subelement in the name. For example, in this operation:
1567 /// %x, %y:2, %z = foo.op
1569 /// getResultName(0) == {"x", 0 }
1570 /// getResultName(1) == {"y", 0 }
1571 /// getResultName(2) == {"y", 1 }
1572 /// getResultName(3) == {"z", 0 }
1573 std::pair
<StringRef
, unsigned>
1574 getResultName(unsigned resultNo
) const override
{
1575 // Scan for the resultID that contains this result number.
1576 for (const auto &entry
: resultIDs
) {
1577 if (resultNo
< std::get
<1>(entry
)) {
1578 // Don't pass on the leading %.
1579 StringRef name
= std::get
<0>(entry
).drop_front();
1580 return {name
, resultNo
};
1582 resultNo
-= std::get
<1>(entry
);
1585 // Invalid result number.
1589 /// Return the number of declared SSA results. This returns 4 for the foo.op
1590 /// example in the comment for getResultName.
1591 size_t getNumResults() const override
{
1593 for (auto &entry
: resultIDs
)
1594 count
+= std::get
<1>(entry
);
1598 /// Emit a diagnostic at the specified location and return failure.
1599 InFlightDiagnostic
emitError(SMLoc loc
, const Twine
&message
) override
{
1600 return AsmParserImpl
<OpAsmParser
>::emitError(loc
, "custom op '" + opName
+
1604 //===--------------------------------------------------------------------===//
1606 //===--------------------------------------------------------------------===//
1608 /// Parse a single operand.
1609 ParseResult
parseOperand(UnresolvedOperand
&result
,
1610 bool allowResultNumber
= true) override
{
1611 OperationParser::UnresolvedOperand useInfo
;
1612 if (parser
.parseSSAUse(useInfo
, allowResultNumber
))
1615 result
= {useInfo
.location
, useInfo
.name
, useInfo
.number
};
1619 /// Parse a single operand if present.
1621 parseOptionalOperand(UnresolvedOperand
&result
,
1622 bool allowResultNumber
= true) override
{
1623 if (parser
.getToken().isOrIsCodeCompletionFor(Token::percent_identifier
))
1624 return parseOperand(result
, allowResultNumber
);
1625 return std::nullopt
;
1628 /// Parse zero or more SSA comma-separated operand references with a specified
1629 /// surrounding delimiter, and an optional required operand count.
1630 ParseResult
parseOperandList(SmallVectorImpl
<UnresolvedOperand
> &result
,
1631 Delimiter delimiter
= Delimiter::None
,
1632 bool allowResultNumber
= true,
1633 int requiredOperandCount
= -1) override
{
1634 // The no-delimiter case has some special handling for better diagnostics.
1635 if (delimiter
== Delimiter::None
) {
1636 // parseCommaSeparatedList doesn't handle the missing case for "none",
1637 // so we handle it custom here.
1638 Token tok
= parser
.getToken();
1639 if (!tok
.isOrIsCodeCompletionFor(Token::percent_identifier
)) {
1640 // If we didn't require any operands or required exactly zero (weird)
1641 // then this is success.
1642 if (requiredOperandCount
== -1 || requiredOperandCount
== 0)
1645 // Otherwise, try to produce a nice error message.
1646 if (tok
.isAny(Token::l_paren
, Token::l_square
))
1647 return parser
.emitError("unexpected delimiter");
1648 return parser
.emitWrongTokenError("expected operand");
1652 auto parseOneOperand
= [&]() -> ParseResult
{
1653 return parseOperand(result
.emplace_back(), allowResultNumber
);
1656 auto startLoc
= parser
.getToken().getLoc();
1657 if (parseCommaSeparatedList(delimiter
, parseOneOperand
, " in operand list"))
1660 // Check that we got the expected # of elements.
1661 if (requiredOperandCount
!= -1 &&
1662 result
.size() != static_cast<size_t>(requiredOperandCount
))
1663 return emitError(startLoc
, "expected ")
1664 << requiredOperandCount
<< " operands";
1668 /// Resolve an operand to an SSA value, emitting an error on failure.
1669 ParseResult
resolveOperand(const UnresolvedOperand
&operand
, Type type
,
1670 SmallVectorImpl
<Value
> &result
) override
{
1671 if (auto value
= parser
.resolveSSAUse(operand
, type
)) {
1672 result
.push_back(value
);
1678 /// Parse an AffineMap of SSA ids.
1680 parseAffineMapOfSSAIds(SmallVectorImpl
<UnresolvedOperand
> &operands
,
1681 Attribute
&mapAttr
, StringRef attrName
,
1682 NamedAttrList
&attrs
, Delimiter delimiter
) override
{
1683 SmallVector
<UnresolvedOperand
, 2> dimOperands
;
1684 SmallVector
<UnresolvedOperand
, 1> symOperands
;
1686 auto parseElement
= [&](bool isSymbol
) -> ParseResult
{
1687 UnresolvedOperand operand
;
1688 if (parseOperand(operand
))
1691 symOperands
.push_back(operand
);
1693 dimOperands
.push_back(operand
);
1698 if (parser
.parseAffineMapOfSSAIds(map
, parseElement
, delimiter
))
1700 // Add AffineMap attribute.
1702 mapAttr
= AffineMapAttr::get(map
);
1703 attrs
.push_back(parser
.builder
.getNamedAttr(attrName
, mapAttr
));
1706 // Add dim operands before symbol operands in 'operands'.
1707 operands
.assign(dimOperands
.begin(), dimOperands
.end());
1708 operands
.append(symOperands
.begin(), symOperands
.end());
1712 /// Parse an AffineExpr of SSA ids.
1714 parseAffineExprOfSSAIds(SmallVectorImpl
<UnresolvedOperand
> &dimOperands
,
1715 SmallVectorImpl
<UnresolvedOperand
> &symbOperands
,
1716 AffineExpr
&expr
) override
{
1717 auto parseElement
= [&](bool isSymbol
) -> ParseResult
{
1718 UnresolvedOperand operand
;
1719 if (parseOperand(operand
))
1722 symbOperands
.push_back(operand
);
1724 dimOperands
.push_back(operand
);
1728 return parser
.parseAffineExprOfSSAIds(expr
, parseElement
);
1731 //===--------------------------------------------------------------------===//
1733 //===--------------------------------------------------------------------===//
1735 /// Parse a single argument with the following syntax:
1737 /// `%ssaname : !type { optionalAttrDict} loc(optionalSourceLoc)`
1739 /// If `allowType` is false or `allowAttrs` are false then the respective
1740 /// parts of the grammar are not parsed.
1741 ParseResult
parseArgument(Argument
&result
, bool allowType
= false,
1742 bool allowAttrs
= false) override
{
1743 NamedAttrList attrs
;
1744 if (parseOperand(result
.ssaName
, /*allowResultNumber=*/false) ||
1745 (allowType
&& parseColonType(result
.type
)) ||
1746 (allowAttrs
&& parseOptionalAttrDict(attrs
)) ||
1747 parseOptionalLocationSpecifier(result
.sourceLoc
))
1749 result
.attrs
= attrs
.getDictionary(getContext());
1753 /// Parse a single argument if present.
1754 OptionalParseResult
parseOptionalArgument(Argument
&result
, bool allowType
,
1755 bool allowAttrs
) override
{
1756 if (parser
.getToken().is(Token::percent_identifier
))
1757 return parseArgument(result
, allowType
, allowAttrs
);
1758 return std::nullopt
;
1761 ParseResult
parseArgumentList(SmallVectorImpl
<Argument
> &result
,
1762 Delimiter delimiter
, bool allowType
,
1763 bool allowAttrs
) override
{
1764 // The no-delimiter case has some special handling for the empty case.
1765 if (delimiter
== Delimiter::None
&&
1766 parser
.getToken().isNot(Token::percent_identifier
))
1769 auto parseOneArgument
= [&]() -> ParseResult
{
1770 return parseArgument(result
.emplace_back(), allowType
, allowAttrs
);
1772 return parseCommaSeparatedList(delimiter
, parseOneArgument
,
1773 " in argument list");
1776 //===--------------------------------------------------------------------===//
1778 //===--------------------------------------------------------------------===//
1780 /// Parse a region that takes `arguments` of `argTypes` types. This
1781 /// effectively defines the SSA values of `arguments` and assigns their type.
1782 ParseResult
parseRegion(Region
®ion
, ArrayRef
<Argument
> arguments
,
1783 bool enableNameShadowing
) override
{
1784 // Try to parse the region.
1785 (void)isIsolatedFromAbove
;
1786 assert((!enableNameShadowing
|| isIsolatedFromAbove
) &&
1787 "name shadowing is only allowed on isolated regions");
1788 if (parser
.parseRegion(region
, arguments
, enableNameShadowing
))
1793 /// Parses a region if present.
1794 OptionalParseResult
parseOptionalRegion(Region
®ion
,
1795 ArrayRef
<Argument
> arguments
,
1796 bool enableNameShadowing
) override
{
1797 if (parser
.getToken().isNot(Token::l_brace
))
1798 return std::nullopt
;
1799 return parseRegion(region
, arguments
, enableNameShadowing
);
1802 /// Parses a region if present. If the region is present, a new region is
1803 /// allocated and placed in `region`. If no region is present, `region`
1804 /// remains untouched.
1806 parseOptionalRegion(std::unique_ptr
<Region
> ®ion
,
1807 ArrayRef
<Argument
> arguments
,
1808 bool enableNameShadowing
= false) override
{
1809 if (parser
.getToken().isNot(Token::l_brace
))
1810 return std::nullopt
;
1811 std::unique_ptr
<Region
> newRegion
= std::make_unique
<Region
>();
1812 if (parseRegion(*newRegion
, arguments
, enableNameShadowing
))
1815 region
= std::move(newRegion
);
1819 //===--------------------------------------------------------------------===//
1820 // Successor Parsing
1821 //===--------------------------------------------------------------------===//
1823 /// Parse a single operation successor.
1824 ParseResult
parseSuccessor(Block
*&dest
) override
{
1825 return parser
.parseSuccessor(dest
);
1828 /// Parse an optional operation successor and its operand list.
1829 OptionalParseResult
parseOptionalSuccessor(Block
*&dest
) override
{
1830 if (!parser
.getToken().isOrIsCodeCompletionFor(Token::caret_identifier
))
1831 return std::nullopt
;
1832 return parseSuccessor(dest
);
1835 /// Parse a single operation successor and its operand list.
1837 parseSuccessorAndUseList(Block
*&dest
,
1838 SmallVectorImpl
<Value
> &operands
) override
{
1839 if (parseSuccessor(dest
))
1842 // Handle optional arguments.
1843 if (succeeded(parseOptionalLParen()) &&
1844 (parser
.parseOptionalSSAUseAndTypeList(operands
) || parseRParen())) {
1850 //===--------------------------------------------------------------------===//
1852 //===--------------------------------------------------------------------===//
1854 /// Parse a list of assignments of the form
1855 /// (%x1 = %y1, %x2 = %y2, ...).
1856 OptionalParseResult
parseOptionalAssignmentList(
1857 SmallVectorImpl
<Argument
> &lhs
,
1858 SmallVectorImpl
<UnresolvedOperand
> &rhs
) override
{
1859 if (failed(parseOptionalLParen()))
1860 return std::nullopt
;
1862 auto parseElt
= [&]() -> ParseResult
{
1863 if (parseArgument(lhs
.emplace_back()) || parseEqual() ||
1864 parseOperand(rhs
.emplace_back()))
1868 return parser
.parseCommaSeparatedListUntil(Token::r_paren
, parseElt
);
1871 /// Parse a loc(...) specifier if present, filling in result if so.
1873 parseOptionalLocationSpecifier(std::optional
<Location
> &result
) override
{
1874 // If there is a 'loc' we parse a trailing location.
1875 if (!parser
.consumeIf(Token::kw_loc
))
1877 LocationAttr directLoc
;
1878 if (parser
.parseToken(Token::l_paren
, "expected '(' in location"))
1881 Token tok
= parser
.getToken();
1883 // Check to see if we are parsing a location alias.
1884 // Otherwise, we parse the location directly.
1885 if (tok
.is(Token::hash_identifier
)) {
1886 if (parser
.parseLocationAlias(directLoc
))
1888 } else if (parser
.parseLocationInstance(directLoc
)) {
1892 if (parser
.parseToken(Token::r_paren
, "expected ')' in location"))
1900 /// Information about the result name specifiers.
1901 ArrayRef
<OperationParser::ResultRecord
> resultIDs
;
1903 /// The abstract information of the operation.
1904 function_ref
<ParseResult(OpAsmParser
&, OperationState
&)> parseAssembly
;
1905 bool isIsolatedFromAbove
;
1908 /// The backing operation parser.
1909 OperationParser
&parser
;
1913 FailureOr
<OperationName
> OperationParser::parseCustomOperationName() {
1914 Token nameTok
= getToken();
1915 StringRef opName
= nameTok
.getSpelling();
1917 return (emitError("empty operation name is invalid"), failure());
1920 // Check to see if this operation name is already registered.
1921 std::optional
<RegisteredOperationName
> opInfo
=
1922 RegisteredOperationName::lookup(opName
, getContext());
1926 // If the operation doesn't have a dialect prefix try using the default
1928 auto opNameSplit
= opName
.split('.');
1929 StringRef dialectName
= opNameSplit
.first
;
1930 std::string opNameStorage
;
1931 if (opNameSplit
.second
.empty()) {
1932 // If the name didn't have a prefix, check for a code completion request.
1933 if (getToken().isCodeCompletion() && opName
.back() == '.')
1934 return codeCompleteOperationName(dialectName
);
1936 dialectName
= getState().defaultDialectStack
.back();
1937 opNameStorage
= (dialectName
+ "." + opName
).str();
1938 opName
= opNameStorage
;
1941 // Try to load the dialect before returning the operation name to make sure
1942 // the operation has a chance to be registered.
1943 getContext()->getOrLoadDialect(dialectName
);
1944 return OperationName(opName
, getContext());
1948 OperationParser::parseCustomOperation(ArrayRef
<ResultRecord
> resultIDs
) {
1949 SMLoc opLoc
= getToken().getLoc();
1950 StringRef originalOpName
= getTokenSpelling();
1952 FailureOr
<OperationName
> opNameInfo
= parseCustomOperationName();
1953 if (failed(opNameInfo
))
1955 StringRef opName
= opNameInfo
->getStringRef();
1957 // This is the actual hook for the custom op parsing, usually implemented by
1958 // the op itself (`Op::parse()`). We retrieve it either from the
1959 // RegisteredOperationName or from the Dialect.
1960 OperationName::ParseAssemblyFn parseAssemblyFn
;
1961 bool isIsolatedFromAbove
= false;
1963 StringRef defaultDialect
= "";
1964 if (auto opInfo
= opNameInfo
->getRegisteredInfo()) {
1965 parseAssemblyFn
= opInfo
->getParseAssemblyFn();
1966 isIsolatedFromAbove
= opInfo
->hasTrait
<OpTrait::IsIsolatedFromAbove
>();
1967 auto *iface
= opInfo
->getInterface
<OpAsmOpInterface
>();
1968 if (iface
&& !iface
->getDefaultDialect().empty())
1969 defaultDialect
= iface
->getDefaultDialect();
1971 std::optional
<Dialect::ParseOpHook
> dialectHook
;
1972 Dialect
*dialect
= opNameInfo
->getDialect();
1974 InFlightDiagnostic diag
=
1975 emitError(opLoc
) << "Dialect `" << opNameInfo
->getDialectNamespace()
1976 << "' not found for custom op '" << originalOpName
1978 if (originalOpName
!= opName
)
1979 diag
<< " (tried '" << opName
<< "' as well)";
1980 auto ¬e
= diag
.attachNote();
1981 note
<< "Registered dialects: ";
1982 llvm::interleaveComma(getContext()->getAvailableDialects(), note
,
1983 [&](StringRef dialect
) { note
<< dialect
; });
1984 note
<< " ; for more info on dialect registration see "
1985 "https://mlir.llvm.org/getting_started/Faq/"
1986 "#registered-loaded-dependent-whats-up-with-dialects-management";
1989 dialectHook
= dialect
->getParseOperationHook(opName
);
1991 InFlightDiagnostic diag
=
1992 emitError(opLoc
) << "custom op '" << originalOpName
<< "' is unknown";
1993 if (originalOpName
!= opName
)
1994 diag
<< " (tried '" << opName
<< "' as well)";
1997 parseAssemblyFn
= *dialectHook
;
1999 getState().defaultDialectStack
.push_back(defaultDialect
);
2000 auto restoreDefaultDialect
= llvm::make_scope_exit(
2001 [&]() { getState().defaultDialectStack
.pop_back(); });
2003 // If the custom op parser crashes, produce some indication to help
2005 llvm::PrettyStackTraceFormat
fmt("MLIR Parser: custom op parser '%s'",
2006 opNameInfo
->getIdentifier().data());
2008 // Get location information for the operation.
2009 auto srcLocation
= getEncodedSourceLocation(opLoc
);
2010 OperationState
opState(srcLocation
, *opNameInfo
);
2012 // If we are populating the parser state, start a new operation definition.
2014 state
.asmState
->startOperationDefinition(opState
.name
);
2016 // Have the op implementation take a crack and parsing this.
2017 CleanupOpStateRegions guard
{opState
};
2018 CustomOpAsmParser
opAsmParser(opLoc
, resultIDs
, parseAssemblyFn
,
2019 isIsolatedFromAbove
, opName
, *this);
2020 if (opAsmParser
.parseOperation(opState
))
2023 // If it emitted an error, we failed.
2024 if (opAsmParser
.didEmitError())
2027 Attribute properties
= opState
.propertiesAttr
;
2028 opState
.propertiesAttr
= Attribute
{};
2030 // Otherwise, create the operation and try to parse a location for it.
2031 Operation
*op
= opBuilder
.create(opState
);
2032 if (parseTrailingLocationSpecifier(op
))
2035 // Try setting the properties for the operation.
2037 auto emitError
= [&]() {
2038 return mlir::emitError(srcLocation
, "invalid properties ")
2039 << properties
<< " for op " << op
->getName().getStringRef()
2042 if (failed(op
->setPropertiesFromAttribute(properties
, emitError
)))
2048 ParseResult
OperationParser::parseLocationAlias(LocationAttr
&loc
) {
2049 Token tok
= getToken();
2050 consumeToken(Token::hash_identifier
);
2051 StringRef identifier
= tok
.getSpelling().drop_front();
2052 if (identifier
.contains('.')) {
2053 return emitError(tok
.getLoc())
2054 << "expected location, but found dialect attribute: '#" << identifier
2058 state
.asmState
->addAttrAliasUses(identifier
, tok
.getLocRange());
2060 // If this alias can be resolved, do it now.
2061 Attribute attr
= state
.symbols
.attributeAliasDefinitions
.lookup(identifier
);
2063 if (!(loc
= dyn_cast
<LocationAttr
>(attr
)))
2064 return emitError(tok
.getLoc())
2065 << "expected location, but found '" << attr
<< "'";
2067 // Otherwise, remember this operation and resolve its location later.
2068 // In the meantime, use a special OpaqueLoc as a marker.
2069 loc
= OpaqueLoc::get(deferredLocsReferences
.size(),
2070 TypeID::get
<DeferredLocInfo
*>(),
2071 UnknownLoc::get(getContext()));
2072 deferredLocsReferences
.push_back(DeferredLocInfo
{tok
.getLoc(), identifier
});
2078 OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument
) {
2079 // If there is a 'loc' we parse a trailing location.
2080 if (!consumeIf(Token::kw_loc
))
2082 if (parseToken(Token::l_paren
, "expected '(' in location"))
2084 Token tok
= getToken();
2086 // Check to see if we are parsing a location alias.
2087 // Otherwise, we parse the location directly.
2088 LocationAttr directLoc
;
2089 if (tok
.is(Token::hash_identifier
)) {
2090 if (parseLocationAlias(directLoc
))
2092 } else if (parseLocationInstance(directLoc
)) {
2096 if (parseToken(Token::r_paren
, "expected ')' in location"))
2099 if (auto *op
= llvm::dyn_cast_if_present
<Operation
*>(opOrArgument
))
2100 op
->setLoc(directLoc
);
2102 opOrArgument
.get
<BlockArgument
>().setLoc(directLoc
);
2106 //===----------------------------------------------------------------------===//
2108 //===----------------------------------------------------------------------===//
2110 ParseResult
OperationParser::parseRegion(Region
®ion
,
2111 ArrayRef
<Argument
> entryArguments
,
2112 bool isIsolatedNameScope
) {
2114 Token lBraceTok
= getToken();
2115 if (parseToken(Token::l_brace
, "expected '{' to begin a region"))
2118 // If we are populating the parser state, start a new region definition.
2120 state
.asmState
->startRegionDefinition();
2122 // Parse the region body.
2123 if ((!entryArguments
.empty() || getToken().isNot(Token::r_brace
)) &&
2124 parseRegionBody(region
, lBraceTok
.getLoc(), entryArguments
,
2125 isIsolatedNameScope
)) {
2128 consumeToken(Token::r_brace
);
2130 // If we are populating the parser state, finalize this region.
2132 state
.asmState
->finalizeRegionDefinition();
2137 ParseResult
OperationParser::parseRegionBody(Region
®ion
, SMLoc startLoc
,
2138 ArrayRef
<Argument
> entryArguments
,
2139 bool isIsolatedNameScope
) {
2140 auto currentPt
= opBuilder
.saveInsertionPoint();
2142 // Push a new named value scope.
2143 pushSSANameScope(isIsolatedNameScope
);
2145 // Parse the first block directly to allow for it to be unnamed.
2146 auto owningBlock
= std::make_unique
<Block
>();
2147 Block
*block
= owningBlock
.get();
2149 // If this block is not defined in the source file, add a definition for it
2150 // now in the assembly state. Blocks with a name will be defined when the name
2152 if (state
.asmState
&& getToken().isNot(Token::caret_identifier
))
2153 state
.asmState
->addDefinition(block
, startLoc
);
2155 // Add arguments to the entry block if we had the form with explicit names.
2156 if (!entryArguments
.empty() && !entryArguments
[0].ssaName
.name
.empty()) {
2157 // If we had named arguments, then don't allow a block name.
2158 if (getToken().is(Token::caret_identifier
))
2159 return emitError("invalid block name in region with named arguments");
2161 for (auto &entryArg
: entryArguments
) {
2162 auto &argInfo
= entryArg
.ssaName
;
2164 // Ensure that the argument was not already defined.
2165 if (auto defLoc
= getReferenceLoc(argInfo
.name
, argInfo
.number
)) {
2166 return emitError(argInfo
.location
, "region entry argument '" +
2168 "' is already in use")
2169 .attachNote(getEncodedSourceLocation(*defLoc
))
2170 << "previously referenced here";
2172 Location loc
= entryArg
.sourceLoc
.has_value()
2173 ? *entryArg
.sourceLoc
2174 : getEncodedSourceLocation(argInfo
.location
);
2175 BlockArgument arg
= block
->addArgument(entryArg
.type
, loc
);
2177 // Add a definition of this arg to the assembly state if provided.
2179 state
.asmState
->addDefinition(arg
, argInfo
.location
);
2181 // Record the definition for this argument.
2182 if (addDefinition(argInfo
, arg
))
2187 if (parseBlock(block
))
2190 // Verify that no other arguments were parsed.
2191 if (!entryArguments
.empty() &&
2192 block
->getNumArguments() > entryArguments
.size()) {
2193 return emitError("entry block arguments were already defined");
2196 // Parse the rest of the region.
2197 region
.push_back(owningBlock
.release());
2198 while (getToken().isNot(Token::r_brace
)) {
2199 Block
*newBlock
= nullptr;
2200 if (parseBlock(newBlock
))
2202 region
.push_back(newBlock
);
2205 // Pop the SSA value scope for this region.
2206 if (popSSANameScope())
2209 // Reset the original insertion point.
2210 opBuilder
.restoreInsertionPoint(currentPt
);
2214 //===----------------------------------------------------------------------===//
2216 //===----------------------------------------------------------------------===//
2218 /// Block declaration.
2220 /// block ::= block-label? operation*
2221 /// block-label ::= block-id block-arg-list? `:`
2222 /// block-id ::= caret-id
2223 /// block-arg-list ::= `(` ssa-id-and-type-list? `)`
2225 ParseResult
OperationParser::parseBlock(Block
*&block
) {
2226 // The first block of a region may already exist, if it does the caret
2227 // identifier is optional.
2228 if (block
&& getToken().isNot(Token::caret_identifier
))
2229 return parseBlockBody(block
);
2231 SMLoc nameLoc
= getToken().getLoc();
2232 auto name
= getTokenSpelling();
2233 if (parseToken(Token::caret_identifier
, "expected block name"))
2236 // Define the block with the specified name.
2237 auto &blockAndLoc
= getBlockInfoByName(name
);
2238 blockAndLoc
.loc
= nameLoc
;
2240 // Use a unique pointer for in-flight block being parsed. Release ownership
2241 // only in the case of a successful parse. This ensures that the Block
2242 // allocated is released if the parse fails and control returns early.
2243 std::unique_ptr
<Block
> inflightBlock
;
2244 auto cleanupOnFailure
= llvm::make_scope_exit([&] {
2246 inflightBlock
->dropAllDefinedValueUses();
2249 // If a block has yet to be set, this is a new definition. If the caller
2250 // provided a block, use it. Otherwise create a new one.
2251 if (!blockAndLoc
.block
) {
2253 blockAndLoc
.block
= block
;
2255 inflightBlock
= std::make_unique
<Block
>();
2256 blockAndLoc
.block
= inflightBlock
.get();
2259 // Otherwise, the block has a forward declaration. Forward declarations are
2260 // removed once defined, so if we are defining a existing block and it is
2261 // not a forward declaration, then it is a redeclaration. Fail if the block
2262 // was already defined.
2263 } else if (!eraseForwardRef(blockAndLoc
.block
)) {
2264 return emitError(nameLoc
, "redefinition of block '") << name
<< "'";
2266 // This was a forward reference block that is now floating. Keep track of it
2267 // as inflight in case of error, so that it gets cleaned up properly.
2268 inflightBlock
.reset(blockAndLoc
.block
);
2271 // Populate the high level assembly state if necessary.
2273 state
.asmState
->addDefinition(blockAndLoc
.block
, nameLoc
);
2274 block
= blockAndLoc
.block
;
2276 // If an argument list is present, parse it.
2277 if (getToken().is(Token::l_paren
))
2278 if (parseOptionalBlockArgList(block
))
2280 if (parseToken(Token::colon
, "expected ':' after block name"))
2283 // Parse the body of the block.
2284 ParseResult res
= parseBlockBody(block
);
2286 // If parsing was successful, drop the inflight block. We relinquish ownership
2287 // back up to the caller.
2289 (void)inflightBlock
.release();
2293 ParseResult
OperationParser::parseBlockBody(Block
*block
) {
2294 // Set the insertion point to the end of the block to parse.
2295 opBuilder
.setInsertionPointToEnd(block
);
2297 // Parse the list of operations that make up the body of the block.
2298 while (getToken().isNot(Token::caret_identifier
, Token::r_brace
))
2299 if (parseOperation())
2305 /// Get the block with the specified name, creating it if it doesn't already
2306 /// exist. The location specified is the point of use, which allows
2307 /// us to diagnose references to blocks that are not defined precisely.
2308 Block
*OperationParser::getBlockNamed(StringRef name
, SMLoc loc
) {
2309 BlockDefinition
&blockDef
= getBlockInfoByName(name
);
2310 if (!blockDef
.block
) {
2311 blockDef
= {new Block(), loc
};
2312 insertForwardRef(blockDef
.block
, blockDef
.loc
);
2315 // Populate the high level assembly state if necessary.
2317 state
.asmState
->addUses(blockDef
.block
, loc
);
2319 return blockDef
.block
;
2322 /// Parse a (possibly empty) list of SSA operands with types as block arguments
2323 /// enclosed in parentheses.
2325 /// value-id-and-type-list ::= value-id-and-type (`,` ssa-id-and-type)*
2326 /// block-arg-list ::= `(` value-id-and-type-list? `)`
2328 ParseResult
OperationParser::parseOptionalBlockArgList(Block
*owner
) {
2329 if (getToken().is(Token::r_brace
))
2332 // If the block already has arguments, then we're handling the entry block.
2333 // Parse and register the names for the arguments, but do not add them.
2334 bool definingExistingArgs
= owner
->getNumArguments() != 0;
2335 unsigned nextArgument
= 0;
2337 return parseCommaSeparatedList(Delimiter::Paren
, [&]() -> ParseResult
{
2338 return parseSSADefOrUseAndType(
2339 [&](UnresolvedOperand useInfo
, Type type
) -> ParseResult
{
2342 // If we are defining existing arguments, ensure that the argument
2343 // has already been created with the right type.
2344 if (definingExistingArgs
) {
2345 // Otherwise, ensure that this argument has already been created.
2346 if (nextArgument
>= owner
->getNumArguments())
2347 return emitError("too many arguments specified in argument list");
2349 // Finally, make sure the existing argument has the correct type.
2350 arg
= owner
->getArgument(nextArgument
++);
2351 if (arg
.getType() != type
)
2352 return emitError("argument and block argument type mismatch");
2354 auto loc
= getEncodedSourceLocation(useInfo
.location
);
2355 arg
= owner
->addArgument(type
, loc
);
2358 // If the argument has an explicit loc(...) specifier, parse and apply
2360 if (parseTrailingLocationSpecifier(arg
))
2363 // Mark this block argument definition in the parser state if it was
2366 state
.asmState
->addDefinition(arg
, useInfo
.location
);
2368 return addDefinition(useInfo
, arg
);
2373 //===----------------------------------------------------------------------===//
2375 //===----------------------------------------------------------------------===//
2377 ParseResult
OperationParser::codeCompleteSSAUse() {
2378 std::string detailData
;
2379 llvm::raw_string_ostream
detailOS(detailData
);
2380 for (IsolatedSSANameScope
&scope
: isolatedNameScopes
) {
2381 for (auto &it
: scope
.values
) {
2382 if (it
.second
.empty())
2384 Value frontValue
= it
.second
.front().value
;
2386 // If the value isn't a forward reference, we also add the name of the op
2388 if (auto result
= dyn_cast
<OpResult
>(frontValue
)) {
2389 if (!forwardRefPlaceholders
.count(result
))
2390 detailOS
<< result
.getOwner()->getName() << ": ";
2392 detailOS
<< "arg #" << cast
<BlockArgument
>(frontValue
).getArgNumber()
2396 // Emit the type of the values to aid with completion selection.
2397 detailOS
<< frontValue
.getType();
2399 // FIXME: We should define a policy for packed values, e.g. with a limit
2400 // on the detail size, but it isn't clear what would be useful right now.
2401 // For now we just only emit the first type.
2402 if (it
.second
.size() > 1)
2403 detailOS
<< ", ...";
2405 state
.codeCompleteContext
->appendSSAValueCompletion(
2406 it
.getKey(), std::move(detailOS
.str()));
2413 ParseResult
OperationParser::codeCompleteBlock() {
2414 // Don't provide completions if the token isn't empty, e.g. this avoids
2415 // weirdness when we encounter a `.` within the identifier.
2416 StringRef spelling
= getTokenSpelling();
2417 if (!(spelling
.empty() || spelling
== "^"))
2420 for (const auto &it
: blocksByName
.back())
2421 state
.codeCompleteContext
->appendBlockCompletion(it
.getFirst());
2425 //===----------------------------------------------------------------------===//
2426 // Top-level entity parsing.
2427 //===----------------------------------------------------------------------===//
2430 /// This parser handles entities that are only valid at the top level of the
2432 class TopLevelOperationParser
: public Parser
{
2434 explicit TopLevelOperationParser(ParserState
&state
) : Parser(state
) {}
2436 /// Parse a set of operations into the end of the given Block.
2437 ParseResult
parse(Block
*topLevelBlock
, Location parserLoc
);
2440 /// Parse an attribute alias declaration.
2442 /// attribute-alias-def ::= '#' alias-name `=` attribute-value
2444 ParseResult
parseAttributeAliasDef();
2446 /// Parse a type alias declaration.
2448 /// type-alias-def ::= '!' alias-name `=` type
2450 ParseResult
parseTypeAliasDef();
2452 /// Parse a top-level file metadata dictionary.
2454 /// file-metadata-dict ::= '{-#' file-metadata-entry* `#-}'
2456 ParseResult
parseFileMetadataDictionary();
2458 /// Parse a resource metadata dictionary.
2459 ParseResult
parseResourceFileMetadata(
2460 function_ref
<ParseResult(StringRef
, SMLoc
)> parseBody
);
2461 ParseResult
parseDialectResourceFileMetadata();
2462 ParseResult
parseExternalResourceFileMetadata();
2465 /// This class represents an implementation of a resource entry for the MLIR
2467 class ParsedResourceEntry
: public AsmParsedResourceEntry
{
2469 ParsedResourceEntry(StringRef key
, SMLoc keyLoc
, Token value
, Parser
&p
)
2470 : key(key
), keyLoc(keyLoc
), value(value
), p(p
) {}
2471 ~ParsedResourceEntry() override
= default;
2473 StringRef
getKey() const final
{ return key
; }
2475 InFlightDiagnostic
emitError() const final
{ return p
.emitError(keyLoc
); }
2477 AsmResourceEntryKind
getKind() const final
{
2478 if (value
.isAny(Token::kw_true
, Token::kw_false
))
2479 return AsmResourceEntryKind::Bool
;
2480 return value
.getSpelling().starts_with("\"0x")
2481 ? AsmResourceEntryKind::Blob
2482 : AsmResourceEntryKind::String
;
2485 FailureOr
<bool> parseAsBool() const final
{
2486 if (value
.is(Token::kw_true
))
2488 if (value
.is(Token::kw_false
))
2490 return p
.emitError(value
.getLoc(),
2491 "expected 'true' or 'false' value for key '" + key
+
2495 FailureOr
<std::string
> parseAsString() const final
{
2496 if (value
.isNot(Token::string
))
2497 return p
.emitError(value
.getLoc(),
2498 "expected string value for key '" + key
+ "'");
2499 return value
.getStringValue();
2502 FailureOr
<AsmResourceBlob
>
2503 parseAsBlob(BlobAllocatorFn allocator
) const final
{
2504 // Blob data within then textual format is represented as a hex string.
2505 // TODO: We could avoid an additional alloc+copy here if we pre-allocated
2506 // the buffer to use during hex processing.
2507 std::optional
<std::string
> blobData
=
2508 value
.is(Token::string
) ? value
.getHexStringValue() : std::nullopt
;
2510 return p
.emitError(value
.getLoc(),
2511 "expected hex string blob for key '" + key
+ "'");
2513 // Extract the alignment of the blob data, which gets stored at the
2514 // beginning of the string.
2515 if (blobData
->size() < sizeof(uint32_t)) {
2516 return p
.emitError(value
.getLoc(),
2517 "expected hex string blob for key '" + key
+
2518 "' to encode alignment in first 4 bytes");
2520 llvm::support::ulittle32_t align
;
2521 memcpy(&align
, blobData
->data(), sizeof(uint32_t));
2522 if (align
&& !llvm::isPowerOf2_32(align
)) {
2523 return p
.emitError(value
.getLoc(),
2524 "expected hex string blob for key '" + key
+
2525 "' to encode alignment in first 4 bytes, but got "
2526 "non-power-of-2 value: " +
2530 // Get the data portion of the blob.
2531 StringRef data
= StringRef(*blobData
).drop_front(sizeof(uint32_t));
2533 return AsmResourceBlob();
2535 // Allocate memory for the blob using the provided allocator and copy the
2537 AsmResourceBlob blob
= allocator(data
.size(), align
);
2538 assert(llvm::isAddrAligned(llvm::Align(align
), blob
.getData().data()) &&
2540 "blob allocator did not return a properly aligned address");
2541 memcpy(blob
.getMutableData().data(), data
.data(), data
.size());
2553 ParseResult
TopLevelOperationParser::parseAttributeAliasDef() {
2554 assert(getToken().is(Token::hash_identifier
));
2555 StringRef aliasName
= getTokenSpelling().drop_front();
2557 // Check for redefinitions.
2558 if (state
.symbols
.attributeAliasDefinitions
.count(aliasName
) > 0)
2559 return emitError("redefinition of attribute alias id '" + aliasName
+ "'");
2561 // Make sure this isn't invading the dialect attribute namespace.
2562 if (aliasName
.contains('.'))
2563 return emitError("attribute names with a '.' are reserved for "
2564 "dialect-defined names");
2566 SMRange location
= getToken().getLocRange();
2567 consumeToken(Token::hash_identifier
);
2570 if (parseToken(Token::equal
, "expected '=' in attribute alias definition"))
2573 // Parse the attribute value.
2574 Attribute attr
= parseAttribute();
2578 // Register this alias with the parser state.
2580 state
.asmState
->addAttrAliasDefinition(aliasName
, location
, attr
);
2581 state
.symbols
.attributeAliasDefinitions
[aliasName
] = attr
;
2585 ParseResult
TopLevelOperationParser::parseTypeAliasDef() {
2586 assert(getToken().is(Token::exclamation_identifier
));
2587 StringRef aliasName
= getTokenSpelling().drop_front();
2589 // Check for redefinitions.
2590 if (state
.symbols
.typeAliasDefinitions
.count(aliasName
) > 0)
2591 return emitError("redefinition of type alias id '" + aliasName
+ "'");
2593 // Make sure this isn't invading the dialect type namespace.
2594 if (aliasName
.contains('.'))
2595 return emitError("type names with a '.' are reserved for "
2596 "dialect-defined names");
2598 SMRange location
= getToken().getLocRange();
2599 consumeToken(Token::exclamation_identifier
);
2602 if (parseToken(Token::equal
, "expected '=' in type alias definition"))
2606 Type aliasedType
= parseType();
2610 // Register this alias with the parser state.
2612 state
.asmState
->addTypeAliasDefinition(aliasName
, location
, aliasedType
);
2613 state
.symbols
.typeAliasDefinitions
.try_emplace(aliasName
, aliasedType
);
2617 ParseResult
TopLevelOperationParser::parseFileMetadataDictionary() {
2618 consumeToken(Token::file_metadata_begin
);
2619 return parseCommaSeparatedListUntil(
2620 Token::file_metadata_end
, [&]() -> ParseResult
{
2621 // Parse the key of the metadata dictionary.
2622 SMLoc keyLoc
= getToken().getLoc();
2624 if (failed(parseOptionalKeyword(&key
)))
2625 return emitError("expected identifier key in file "
2626 "metadata dictionary");
2627 if (parseToken(Token::colon
, "expected ':'"))
2630 // Process the metadata entry.
2631 if (key
== "dialect_resources")
2632 return parseDialectResourceFileMetadata();
2633 if (key
== "external_resources")
2634 return parseExternalResourceFileMetadata();
2635 return emitError(keyLoc
, "unknown key '" + key
+
2636 "' in file metadata dictionary");
2640 ParseResult
TopLevelOperationParser::parseResourceFileMetadata(
2641 function_ref
<ParseResult(StringRef
, SMLoc
)> parseBody
) {
2642 if (parseToken(Token::l_brace
, "expected '{'"))
2645 return parseCommaSeparatedListUntil(Token::r_brace
, [&]() -> ParseResult
{
2646 // Parse the top-level name entry.
2647 SMLoc nameLoc
= getToken().getLoc();
2649 if (failed(parseOptionalKeyword(&name
)))
2650 return emitError("expected identifier key for 'resource' entry");
2652 if (parseToken(Token::colon
, "expected ':'") ||
2653 parseToken(Token::l_brace
, "expected '{'"))
2655 return parseBody(name
, nameLoc
);
2659 ParseResult
TopLevelOperationParser::parseDialectResourceFileMetadata() {
2660 return parseResourceFileMetadata([&](StringRef name
,
2661 SMLoc nameLoc
) -> ParseResult
{
2662 // Lookup the dialect and check that it can handle a resource entry.
2663 Dialect
*dialect
= getContext()->getOrLoadDialect(name
);
2665 return emitError(nameLoc
, "dialect '" + name
+ "' is unknown");
2666 const auto *handler
= dyn_cast
<OpAsmDialectInterface
>(dialect
);
2668 return emitError() << "unexpected 'resource' section for dialect '"
2669 << dialect
->getNamespace() << "'";
2672 return parseCommaSeparatedListUntil(Token::r_brace
, [&]() -> ParseResult
{
2673 // Parse the name of the resource entry.
2674 SMLoc keyLoc
= getToken().getLoc();
2676 if (failed(parseResourceHandle(handler
, key
)) ||
2677 parseToken(Token::colon
, "expected ':'"))
2679 Token valueTok
= getToken();
2682 ParsedResourceEntry
entry(key
, keyLoc
, valueTok
, *this);
2683 return handler
->parseResource(entry
);
2688 ParseResult
TopLevelOperationParser::parseExternalResourceFileMetadata() {
2689 return parseResourceFileMetadata([&](StringRef name
,
2690 SMLoc nameLoc
) -> ParseResult
{
2691 AsmResourceParser
*handler
= state
.config
.getResourceParser(name
);
2693 // TODO: Should we require handling external resources in some scenarios?
2695 emitWarning(getEncodedSourceLocation(nameLoc
))
2696 << "ignoring unknown external resources for '" << name
<< "'";
2699 return parseCommaSeparatedListUntil(Token::r_brace
, [&]() -> ParseResult
{
2700 // Parse the name of the resource entry.
2701 SMLoc keyLoc
= getToken().getLoc();
2703 if (failed(parseOptionalKeyword(&key
)))
2705 "expected identifier key for 'external_resources' entry");
2706 if (parseToken(Token::colon
, "expected ':'"))
2708 Token valueTok
= getToken();
2713 ParsedResourceEntry
entry(key
, keyLoc
, valueTok
, *this);
2714 return handler
->parseResource(entry
);
2719 ParseResult
TopLevelOperationParser::parse(Block
*topLevelBlock
,
2720 Location parserLoc
) {
2721 // Create a top-level operation to contain the parsed state.
2722 OwningOpRef
<ModuleOp
> topLevelOp(ModuleOp::create(parserLoc
));
2723 OperationParser
opParser(state
, topLevelOp
.get());
2725 switch (getToken().getKind()) {
2727 // Parse a top-level operation.
2728 if (opParser
.parseOperation())
2732 // If we got to the end of the file, then we're done.
2734 if (opParser
.finalize())
2737 // Splice the blocks of the parsed operation over to the provided
2739 auto &parsedOps
= topLevelOp
->getBody()->getOperations();
2740 auto &destOps
= topLevelBlock
->getOperations();
2741 destOps
.splice(destOps
.end(), parsedOps
, parsedOps
.begin(),
2746 // If we got an error token, then the lexer already emitted an error, just
2747 // stop. Someday we could introduce error recovery if there was demand
2752 // Parse an attribute alias.
2753 case Token::hash_identifier
:
2754 if (parseAttributeAliasDef())
2758 // Parse a type alias.
2759 case Token::exclamation_identifier
:
2760 if (parseTypeAliasDef())
2764 // Parse a file-level metadata dictionary.
2765 case Token::file_metadata_begin
:
2766 if (parseFileMetadataDictionary())
2773 //===----------------------------------------------------------------------===//
2776 mlir::parseAsmSourceFile(const llvm::SourceMgr
&sourceMgr
, Block
*block
,
2777 const ParserConfig
&config
, AsmParserState
*asmState
,
2778 AsmParserCodeCompleteContext
*codeCompleteContext
) {
2779 const auto *sourceBuf
= sourceMgr
.getMemoryBuffer(sourceMgr
.getMainFileID());
2781 Location parserLoc
=
2782 FileLineColLoc::get(config
.getContext(), sourceBuf
->getBufferIdentifier(),
2783 /*line=*/0, /*column=*/0);
2785 SymbolState aliasState
;
2786 ParserState
state(sourceMgr
, config
, aliasState
, asmState
,
2787 codeCompleteContext
);
2788 return TopLevelOperationParser(state
).parse(block
, parserLoc
);