Bug Summary

File:build/source/mlir/lib/AsmParser/Parser.cpp
Warning:line 1229, column 5
1st function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

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