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