38#include "llvm/ADT/APFloat.h"
39#include "llvm/ADT/DenseMap.h"
40#include "llvm/ADT/PointerUnion.h"
41#include "llvm/ADT/STLExtras.h"
42#include "llvm/ADT/ScopeExit.h"
43#include "llvm/ADT/Sequence.h"
44#include "llvm/ADT/StringExtras.h"
45#include "llvm/ADT/StringMap.h"
46#include "llvm/ADT/StringSet.h"
47#include "llvm/Support/Alignment.h"
48#include "llvm/Support/Casting.h"
49#include "llvm/Support/Endian.h"
50#include "llvm/Support/Error.h"
51#include "llvm/Support/ErrorHandling.h"
52#include "llvm/Support/MathExtras.h"
53#include "llvm/Support/PrettyStackTrace.h"
54#include "llvm/Support/SourceMgr.h"
55#include "llvm/Support/raw_ostream.h"
87 StringRef contextMessage) {
91 case Delimiter::OptionalParen:
92 if (
getToken().isNot(Token::l_paren))
95 case Delimiter::Paren:
96 if (
parseToken(Token::l_paren,
"expected '('" + contextMessage))
102 case Delimiter::OptionalLessGreater:
107 case Delimiter::LessGreater:
108 if (
parseToken(Token::less,
"expected '<'" + contextMessage))
114 case Delimiter::OptionalSquare:
115 if (
getToken().isNot(Token::l_square))
118 case Delimiter::Square:
119 if (
parseToken(Token::l_square,
"expected '['" + contextMessage))
125 case Delimiter::OptionalBraces:
126 if (
getToken().isNot(Token::l_brace))
129 case Delimiter::Braces:
130 if (
parseToken(Token::l_brace,
"expected '{'" + contextMessage))
139 if (parseElementFn())
144 if (parseElementFn())
149 case Delimiter::None:
151 case Delimiter::OptionalParen:
152 case Delimiter::Paren:
153 return parseToken(Token::r_paren,
"expected ')'" + contextMessage);
154 case Delimiter::OptionalLessGreater:
155 case Delimiter::LessGreater:
156 return parseToken(Token::greater,
"expected '>'" + contextMessage);
157 case Delimiter::OptionalSquare:
158 case Delimiter::Square:
159 return parseToken(Token::r_square,
"expected ']'" + contextMessage);
160 case Delimiter::OptionalBraces:
161 case Delimiter::Braces:
162 return parseToken(Token::r_brace,
"expected '}'" + contextMessage);
164 llvm_unreachable(
"Unknown delimiter");
176 bool allowEmptyList) {
194 auto loc =
state.curToken.getLoc();
195 if (
state.curToken.isNot(Token::eof))
199 return emitError(SMLoc::getFromPointer(loc.getPointer() - 1), message);
207 size_t slashPos = line.find(
"//");
208 if (slashPos == StringRef::npos)
209 return StringRef::npos;
214 size_t quotePos = line.find(
'"');
215 if (quotePos == StringRef::npos || quotePos > slashPos)
219 bool inString =
false;
220 for (
size_t i = 0, e = line.size(); i < e; ++i) {
233 }
else if (c ==
'/' && i + 1 < e && line[i + 1] ==
'/') {
238 return StringRef::npos;
256 auto loc =
state.curToken.getLoc();
259 if (
state.curToken.is(Token::eof))
260 loc = SMLoc::getFromPointer(loc.getPointer() - 1);
263 auto originalLoc = loc;
266 const char *bufferStart =
state.lex.getBufferBegin();
267 const char *curPtr = loc.getPointer();
271 StringRef startOfBuffer(bufferStart, curPtr - bufferStart);
276 startOfBuffer = startOfBuffer.rtrim(
" \t");
280 if (startOfBuffer.empty())
284 if (startOfBuffer.back() !=
'\n' && startOfBuffer.back() !=
'\r')
285 return emitError(SMLoc::getFromPointer(startOfBuffer.end()), message);
288 startOfBuffer = startOfBuffer.drop_back();
291 auto prevLine = startOfBuffer;
292 size_t newLineIndex = prevLine.find_last_of(
"\n\r");
293 if (newLineIndex != StringRef::npos)
294 prevLine = prevLine.drop_front(newLineIndex);
299 if (commentStart != StringRef::npos)
300 startOfBuffer = startOfBuffer.drop_back(prevLine.size() - commentStart);
307 const Twine &message) {
337 if (curToken.
isNot(Token::integer, Token::minus))
342 if (
parseToken(Token::integer,
"expected integer value"))
346 bool isHex = spelling.size() > 1 && spelling[1] ==
'x';
347 if (spelling.getAsInteger(isHex ? 0 : 10,
result))
364 if (curToken.
isNot(Token::integer, Token::minus)) {
370 if (
parseToken(Token::integer,
"expected integer value")) {
378 if (spelling[0] ==
'0' && spelling.size() > 1 &&
379 llvm::toLower(spelling[1]) ==
'x') {
381 state.lex.resetPointer(spelling.data() + 1);
386 if (spelling.getAsInteger(10,
result))
401 const Token &tok,
bool isNegative,
402 const llvm::fltSemantics &semantics) {
404 if (tok.
is(Token::floatliteral)) {
408 if (isNegative && !APFloat::semanticsHasSignedRepr(semantics))
410 <<
"negative floating point literal for a type with no signed "
417 APFloat value(semantics);
418 llvm::cantFail(value.convertFromString(tok.
getSpelling(),
419 APFloat::rmNearestTiesToEven));
423 result.emplace(std::move(value));
428 if (tok.
is(Token::integer))
437 const Token &tok,
bool isNegative,
438 const llvm::fltSemantics &semantics) {
440 bool isHex = spelling.size() > 1 && spelling[1] ==
'x';
442 return emitError(tok.
getLoc(),
"unexpected decimal integer literal for a "
443 "floating point value")
445 <<
"add a trailing dot to make the literal a float";
449 "hexadecimal float literal should not have a "
454 tok.
getSpelling().getAsInteger(isHex ? 0 : 10, intValue);
455 auto typeSizeInBits = APFloat::semanticsSizeInBits(semantics);
456 if (intValue.getActiveBits() > typeSizeInBits) {
458 "hexadecimal float constant out of range for type");
461 APInt truncatedValue(typeSizeInBits,
462 ArrayRef(intValue.getRawData(), intValue.getNumWords()));
463 result.emplace(semantics, truncatedValue);
491FailureOr<AsmDialectResourceHandle>
494 assert(dialect &&
"expected valid dialect interface");
497 return emitError(
"expected identifier key for 'resource' entry");
503 std::pair<std::string, AsmDialectResourceHandle> &entry =
504 resources[dialect][name];
505 if (entry.first.empty()) {
506 FailureOr<AsmDialectResourceHandle>
result = dialect->declareResource(name);
509 <<
"unknown 'resource' key '" << name <<
"' for dialect '"
510 << dialect->getDialect()->getNamespace() <<
"'";
512 entry.first = dialect->getResourceKey(*
result);
520FailureOr<AsmDialectResourceHandle>
522 const auto *
interface = dyn_cast<OpAsmDialectInterface>(dialect);
525 <<
"' does not expect resource handles";
527 std::string resourceName;
536 state.codeCompleteContext->completeDialectName();
544 if (dialectName.empty() || dialectName.contains(
'.'))
546 state.codeCompleteContext->completeOperationName(dialectName);
555 auto shouldIgnoreOpCompletion = [&]() {
556 const char *bufBegin =
state.lex.getBufferBegin();
557 const char *it = loc.getPointer() - 1;
558 for (; it > bufBegin && *it !=
'\n'; --it)
559 if (!StringRef(
" \t\r").
contains(*it))
563 if (shouldIgnoreOpCompletion())
581 if (name.consume_back(
"."))
587 state.codeCompleteContext->completeExpectedTokens(tokens,
false);
591 state.codeCompleteContext->completeExpectedTokens(tokens,
true);
596 state.codeCompleteContext->completeAttribute(
597 state.symbols.attributeAliasDefinitions);
601 state.codeCompleteContext->completeType(
state.symbols.typeAliasDefinitions);
607 state.codeCompleteContext->completeDialectAttributeOrAlias(aliases);
611 state.codeCompleteContext->completeDialectTypeOrAlias(aliases);
622class OperationParser :
public Parser {
624 OperationParser(
ParserState &state, ModuleOp topLevelOp);
629 ParseResult finalize();
638 struct DeferredLocInfo {
640 StringRef identifier;
644 void pushSSANameScope(
bool isIsolated);
647 ParseResult popSSANameScope();
650 ParseResult addDefinition(UnresolvedOperand useInfo,
Value value);
658 ParseResult parseSSAUse(UnresolvedOperand &
result,
659 bool allowResultNumber =
true);
663 Value resolveSSAUse(UnresolvedOperand useInfo,
Type type);
665 ParseResult parseSSADefOrUseAndType(
672 std::optional<SMLoc> getReferenceLoc(StringRef name,
unsigned number) {
673 auto &values = isolatedNameScopes.back().values;
674 if (!values.count(name) || number >= values[name].size())
676 if (values[name][number].value)
677 return values[name][number].loc;
686 ParseResult parseOperation();
689 ParseResult parseSuccessor(
Block *&dest);
692 ParseResult parseSuccessors(SmallVectorImpl<Block *> &destinations);
695 Operation *parseGenericOperation();
702 ParseResult parseGenericOperationAfterOpName(
704 std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo =
706 std::optional<ArrayRef<Block *>> parsedSuccessors = std::nullopt,
707 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions =
709 std::optional<ArrayRef<NamedAttribute>> parsedAttributes = std::nullopt,
710 std::optional<Attribute> propertiesAttribute = std::nullopt,
711 std::optional<FunctionType> parsedFnType = std::nullopt);
715 Operation *parseGenericOperation(
Block *insertBlock,
721 using OpOrArgument = llvm::PointerUnion<Operation *, BlockArgument>;
728 ParseResult parseTrailingLocationSpecifier(OpOrArgument opOrArgument);
734 ParseResult parseLocationAlias(LocationAttr &loc);
738 using ResultRecord = std::tuple<StringRef, unsigned, SMLoc>;
742 Operation *parseCustomOperation(ArrayRef<ResultRecord> resultIDs);
746 FailureOr<OperationName> parseCustomOperationName();
755 ParseResult parseRegion(Region ®ion, ArrayRef<Argument> entryArguments,
756 bool isIsolatedNameScope =
false);
759 ParseResult parseRegionBody(Region ®ion, SMLoc startLoc,
760 ArrayRef<Argument> entryArguments,
761 bool isIsolatedNameScope);
768 ParseResult parseBlock(
Block *&block);
771 ParseResult parseBlockBody(
Block *block);
774 ParseResult parseOptionalBlockArgList(
Block *owner);
779 Block *getBlockNamed(StringRef name, SMLoc loc);
789 ParseResult codeCompleteSSAUse();
790 ParseResult codeCompleteBlock();
794 struct BlockDefinition {
801 struct ValueDefinition {
809 BlockDefinition &getBlockInfoByName(StringRef name) {
810 return blocksByName.back()[name];
814 void insertForwardRef(
Block *block, SMLoc loc) {
815 forwardRef.back().try_emplace(block, loc);
819 bool eraseForwardRef(
Block *block) {
return forwardRef.back().erase(block); }
822 void recordDefinition(StringRef def);
825 SmallVectorImpl<ValueDefinition> &getSSAValueEntry(StringRef name);
829 Value createForwardRefPlaceholder(SMLoc loc, Type type);
832 bool isForwardRefPlaceholder(Value value) {
833 return forwardRefPlaceholders.count(value);
840 struct IsolatedSSANameScope {
842 void recordDefinition(StringRef def) {
843 definitionsPerScope.back().insert(def);
847 void pushSSANameScope() { definitionsPerScope.push_back({}); }
850 void popSSANameScope() {
851 for (
auto &def : definitionsPerScope.pop_back_val())
852 values.erase(def.getKey());
857 llvm::StringMap<SmallVector<ValueDefinition, 1>> values;
860 SmallVector<llvm::StringSet<>, 2> definitionsPerScope;
864 SmallVector<IsolatedSSANameScope, 2> isolatedNameScopes;
869 SmallVector<DenseMap<StringRef, BlockDefinition>, 2> blocksByName;
870 SmallVector<DenseMap<Block *, SMLoc>, 2> forwardRef;
885 std::vector<DeferredLocInfo> deferredLocsReferences;
891 Operation *topLevelOp;
898OperationParser::OperationParser(
ParserState &state, ModuleOp topLevelOp)
899 :
Parser(state), opBuilder(topLevelOp.getRegion()), topLevelOp(topLevelOp) {
901 pushSSANameScope(
true);
905 state.asmState->initialize(topLevelOp);
908OperationParser::~OperationParser() {
909 for (Operation *op : forwardRefOps) {
915 for (
const auto &scope : forwardRef) {
916 for (
const auto &fwd : scope) {
919 fwd.first->dropAllUses();
927ParseResult OperationParser::finalize() {
930 if (!forwardRefPlaceholders.empty()) {
931 SmallVector<const char *, 4> errors;
933 for (
auto entry : forwardRefPlaceholders)
934 errors.push_back(entry.second.getPointer());
935 llvm::array_pod_sort(errors.begin(), errors.end());
937 for (
const char *entry : errors) {
938 auto loc = SMLoc::getFromPointer(entry);
939 emitError(loc,
"use of undeclared SSA value name");
947 auto resolveLocation = [&,
this](
auto &opOrArgument) -> LogicalResult {
948 auto fwdLoc = dyn_cast<OpaqueLoc>(opOrArgument.getLoc());
949 if (!fwdLoc || fwdLoc.getUnderlyingTypeID() != locID)
951 auto locInfo = deferredLocsReferences[fwdLoc.getUnderlyingLocation()];
952 Attribute attr = attributeAliases.lookup(locInfo.identifier);
955 <<
"operation location alias was never defined";
956 auto locAttr = dyn_cast<LocationAttr>(attr);
959 <<
"expected location, but found '" << attr <<
"'";
960 opOrArgument.setLoc(locAttr);
964 auto walkRes = topLevelOp->walk([&](Operation *op) {
968 for (
Block &block : region.getBlocks())
974 if (walkRes.wasInterrupted())
978 if (
failed(popSSANameScope()))
995void OperationParser::pushSSANameScope(
bool isIsolated) {
1001 isolatedNameScopes.push_back({});
1002 isolatedNameScopes.back().pushSSANameScope();
1005ParseResult OperationParser::popSSANameScope() {
1006 auto forwardRefInCurrentScope = forwardRef.pop_back_val();
1009 if (!forwardRefInCurrentScope.empty()) {
1010 SmallVector<std::pair<const char *, Block *>, 4> errors;
1012 for (
auto entry : forwardRefInCurrentScope) {
1013 errors.push_back({entry.second.getPointer(), entry.first});
1015 topLevelOp->getRegion(0).push_back(entry.first);
1017 llvm::array_pod_sort(errors.begin(), errors.end());
1019 for (
auto entry : errors) {
1020 auto loc = SMLoc::getFromPointer(entry.first);
1021 emitError(loc,
"reference to an undefined block");
1028 auto ¤tNameScope = isolatedNameScopes.back();
1029 if (currentNameScope.definitionsPerScope.size() == 1)
1030 isolatedNameScopes.pop_back();
1032 currentNameScope.popSSANameScope();
1034 blocksByName.pop_back();
1039ParseResult OperationParser::addDefinition(UnresolvedOperand useInfo,
1041 auto &entries = getSSAValueEntry(useInfo.name);
1044 if (entries.size() <= useInfo.number)
1045 entries.resize(useInfo.number + 1);
1049 if (
auto existing = entries[useInfo.number].value) {
1050 if (!isForwardRefPlaceholder(existing)) {
1052 .
append(
"redefinition of SSA value '", useInfo.name,
"'")
1053 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1054 .
append(
"previously defined here");
1057 if (existing.getType() != value.
getType()) {
1059 .
append(
"definition of SSA value '", useInfo.name,
"#",
1060 useInfo.number,
"' has type ", value.
getType())
1061 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1062 .
append(
"previously used here with type ", existing.getType());
1068 existing.replaceAllUsesWith(value);
1069 forwardRefPlaceholders.erase(existing);
1078 entries[useInfo.number] = {value, useInfo.location};
1079 recordDefinition(useInfo.name);
1088ParseResult OperationParser::parseOptionalSSAUseList(
1089 SmallVectorImpl<UnresolvedOperand> &results) {
1090 if (!getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
1093 UnresolvedOperand
result;
1096 results.push_back(
result);
1105ParseResult OperationParser::parseSSAUse(UnresolvedOperand &
result,
1106 bool allowResultNumber) {
1107 if (getToken().isCodeCompletion())
1108 return codeCompleteSSAUse();
1110 result.name = getTokenSpelling();
1112 result.location = getToken().getLoc();
1113 if (parseToken(Token::percent_identifier,
"expected SSA operand"))
1117 if (getToken().is(Token::hash_identifier)) {
1118 if (!allowResultNumber)
1119 return emitError(
"result number not allowed in argument list");
1121 if (
auto value = getToken().getHashIdentifierNumber())
1124 return emitError(
"invalid SSA value result number");
1125 consumeToken(Token::hash_identifier);
1133Value OperationParser::resolveSSAUse(UnresolvedOperand useInfo, Type type) {
1134 auto &entries = getSSAValueEntry(useInfo.name);
1138 auto maybeRecordUse = [&](Value value) {
1145 if (useInfo.number < entries.size() && entries[useInfo.number].value) {
1146 Value
result = entries[useInfo.number].value;
1148 if (
result.getType() == type)
1149 return maybeRecordUse(
result);
1151 emitError(useInfo.location,
"use of value '")
1153 "' expects different type than prior uses: ", type,
" vs ",
1155 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1156 .
append(
"prior use here");
1161 if (entries.size() <= useInfo.number)
1162 entries.resize(useInfo.number + 1);
1166 if (entries[0].value && !isForwardRefPlaceholder(entries[0].value))
1167 return (
emitError(useInfo.location,
"reference to invalid result number"),
1172 Value
result = createForwardRefPlaceholder(useInfo.location, type);
1173 entries[useInfo.number] = {
result, useInfo.location};
1174 return maybeRecordUse(
result);
1180ParseResult OperationParser::parseSSADefOrUseAndType(
1181 function_ref<ParseResult(UnresolvedOperand, Type)> action) {
1182 UnresolvedOperand useInfo;
1183 if (parseSSAUse(useInfo) ||
1184 parseToken(Token::colon,
"expected ':' and type for SSA operand"))
1191 return action(useInfo, type);
1200ParseResult OperationParser::parseOptionalSSAUseAndTypeList(
1201 SmallVectorImpl<Value> &results) {
1202 SmallVector<UnresolvedOperand, 4> valueIDs;
1203 if (parseOptionalSSAUseList(valueIDs))
1207 if (valueIDs.empty())
1210 SmallVector<Type, 4> types;
1211 if (parseToken(Token::colon,
"expected ':' in operand list") ||
1212 parseTypeListNoParens(types))
1215 if (valueIDs.size() != types.size())
1217 << valueIDs.size() <<
" types to match operand list";
1219 results.reserve(valueIDs.size());
1220 for (
unsigned i = 0, e = valueIDs.size(); i != e; ++i) {
1221 if (
auto value = resolveSSAUse(valueIDs[i], types[i]))
1222 results.push_back(value);
1231void OperationParser::recordDefinition(StringRef def) {
1232 isolatedNameScopes.back().recordDefinition(def);
1236auto OperationParser::getSSAValueEntry(StringRef name)
1237 -> SmallVectorImpl<ValueDefinition> & {
1238 return isolatedNameScopes.back().values[name];
1242Value OperationParser::createForwardRefPlaceholder(SMLoc loc, Type type) {
1249 auto name = OperationName(
"builtin.unrealized_conversion_cast",
getContext());
1251 getEncodedSourceLocation(loc), name, type, {},
1252 NamedAttrList(), PropertyRef(),
1254 forwardRefPlaceholders[op->
getResult(0)] = loc;
1255 forwardRefOps.insert(op);
1275ParseResult OperationParser::parseOperation() {
1276 auto loc = getToken().getLoc();
1277 SmallVector<ResultRecord, 1> resultIDs;
1278 size_t numExpectedResults = 0;
1279 if (getToken().is(Token::percent_identifier)) {
1281 auto parseNextResult = [&]() -> ParseResult {
1283 Token nameTok = getToken();
1284 if (parseToken(Token::percent_identifier,
1285 "expected valid ssa identifier"))
1289 size_t expectedSubResults = 1;
1290 if (consumeIf(Token::colon)) {
1292 if (!getToken().is(Token::integer))
1293 return emitWrongTokenError(
"expected integer number of results");
1296 auto val = getToken().getUInt64IntegerValue();
1297 if (!val || *val < 1)
1299 "expected named operation to have at least 1 result");
1300 consumeToken(Token::integer);
1301 expectedSubResults = *val;
1304 resultIDs.emplace_back(nameTok.
getSpelling(), expectedSubResults,
1306 numExpectedResults += expectedSubResults;
1312 if (parseToken(Token::equal,
"expected '=' after SSA name"))
1317 Token nameTok = getToken();
1318 if (nameTok.
is(Token::bare_identifier) || nameTok.
isKeyword())
1319 op = parseCustomOperation(resultIDs);
1320 else if (nameTok.
is(Token::string))
1321 op = parseGenericOperation();
1323 return codeCompleteStringDialectOrOperationName(nameTok.
getStringValue());
1325 return codeCompleteDialectOrElidedOpName(loc);
1327 return emitWrongTokenError(
"expected operation name in quotes");
1334 if (!resultIDs.empty()) {
1336 return emitError(loc,
"cannot name an operation with no results");
1338 return emitError(loc,
"operation defines ")
1340 << numExpectedResults <<
" to bind";
1344 unsigned resultIt = 0;
1345 SmallVector<std::pair<unsigned, SMLoc>> asmResultGroups;
1346 asmResultGroups.reserve(resultIDs.size());
1347 for (ResultRecord &record : resultIDs) {
1348 asmResultGroups.emplace_back(resultIt, std::get<2>(record));
1349 resultIt += std::get<1>(record);
1352 op, nameTok.
getLocRange(), getLastToken().getEndLoc(),
1357 unsigned opResI = 0;
1358 for (ResultRecord &resIt : resultIDs) {
1359 for (
unsigned subRes : llvm::seq<unsigned>(0, std::get<1>(resIt))) {
1360 if (addDefinition({std::get<2>(resIt), std::get<0>(resIt), subRes},
1370 getLastToken().getEndLoc());
1380ParseResult OperationParser::parseSuccessor(
Block *&dest) {
1381 if (getToken().isCodeCompletion())
1382 return codeCompleteBlock();
1385 if (!getToken().is(Token::caret_identifier))
1386 return emitWrongTokenError(
"expected block name");
1387 dest = getBlockNamed(getTokenSpelling(), getToken().getLoc());
1397OperationParser::parseSuccessors(SmallVectorImpl<Block *> &destinations) {
1398 if (parseToken(Token::l_square,
"expected '['"))
1401 auto parseElt = [
this, &destinations] {
1403 ParseResult res = parseSuccessor(dest);
1404 destinations.push_back(dest);
1407 return parseCommaSeparatedListUntil(Token::r_square, parseElt,
1416struct CleanupOpStateRegions {
1417 ~CleanupOpStateRegions() {
1418 SmallVector<Region *, 4> regionsToClean;
1419 regionsToClean.reserve(state.regions.size());
1420 for (
auto ®ion : state.regions)
1422 for (
auto &block : *region)
1425 OperationState &state;
1429ParseResult OperationParser::parseGenericOperationAfterOpName(
1431 std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo,
1432 std::optional<ArrayRef<Block *>> parsedSuccessors,
1433 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1434 std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1435 std::optional<Attribute> propertiesAttribute,
1436 std::optional<FunctionType> parsedFnType) {
1439 SmallVector<UnresolvedOperand, 8> opInfo;
1440 if (!parsedOperandUseInfo) {
1441 if (parseToken(Token::l_paren,
"expected '(' to start operand list") ||
1442 parseOptionalSSAUseList(opInfo) ||
1443 parseToken(Token::r_paren,
"expected ')' to end operand list")) {
1446 parsedOperandUseInfo = opInfo;
1450 if (!parsedSuccessors) {
1451 if (getToken().is(Token::l_square)) {
1453 if (!
result.name.mightHaveTrait<OpTrait::IsTerminator>())
1454 return emitError(
"successors in non-terminator");
1456 SmallVector<Block *, 2> successors;
1457 if (parseSuccessors(successors))
1459 result.addSuccessors(successors);
1462 result.addSuccessors(*parsedSuccessors);
1466 if (propertiesAttribute) {
1467 result.propertiesAttr = *propertiesAttribute;
1468 }
else if (consumeIf(Token::less)) {
1470 if (!
result.propertiesAttr)
1472 if (parseToken(Token::greater,
"expected '>' to close properties"))
1476 if (!parsedRegions) {
1477 if (consumeIf(Token::l_paren)) {
1480 result.regions.emplace_back(
new Region(topLevelOp));
1481 if (parseRegion(*
result.regions.back(), {}))
1483 }
while (consumeIf(Token::comma));
1484 if (parseToken(Token::r_paren,
"expected ')' to end region list"))
1488 result.addRegions(*parsedRegions);
1492 if (!parsedAttributes) {
1493 if (getToken().is(Token::l_brace)) {
1494 if (parseAttributeDict(
result.attributes))
1498 result.addAttributes(*parsedAttributes);
1502 Location typeLoc =
result.location;
1503 if (!parsedFnType) {
1504 if (parseToken(Token::colon,
"expected ':' followed by operation type"))
1507 typeLoc = getEncodedSourceLocation(getToken().getLoc());
1511 auto fnType = dyn_cast<FunctionType>(type);
1515 parsedFnType = fnType;
1518 result.addTypes(parsedFnType->getResults());
1521 ArrayRef<Type> operandTypes = parsedFnType->getInputs();
1522 if (operandTypes.size() != parsedOperandUseInfo->size()) {
1523 auto plural =
"s"[parsedOperandUseInfo->size() == 1];
1525 << parsedOperandUseInfo->size() <<
" operand type" << plural
1526 <<
" but had " << operandTypes.size();
1530 for (
unsigned i = 0, e = parsedOperandUseInfo->size(); i != e; ++i) {
1531 result.operands.push_back(
1532 resolveSSAUse((*parsedOperandUseInfo)[i], operandTypes[i]));
1533 if (!
result.operands.back())
1540Operation *OperationParser::parseGenericOperation() {
1542 auto srcLocation = getEncodedSourceLocation(getToken().getLoc());
1544 std::string name = getToken().getStringValue();
1546 return (
emitError(
"empty operation name is invalid"),
nullptr);
1547 if (name.find(
'\0') != StringRef::npos)
1548 return (
emitError(
"null character not allowed in operation name"),
nullptr);
1550 consumeToken(Token::string);
1552 OperationState
result(srcLocation, name);
1553 CleanupOpStateRegions guard{
result};
1556 if (!
result.name.isRegistered()) {
1557 StringRef dialectName = StringRef(name).split(
'.').first;
1558 if (!
getContext()->getLoadedDialect(dialectName) &&
1559 !
getContext()->getOrLoadDialect(dialectName)) {
1560 if (!
getContext()->allowsUnregisteredDialects()) {
1563 emitError(
"operation being parsed with an unregistered dialect. If "
1564 "this is intended, please use -allow-unregistered-dialect "
1565 "with the MLIR tool used");
1578 if (parseGenericOperationAfterOpName(
result))
1584 Attribute properties;
1585 std::swap(properties,
result.propertiesAttr);
1601 if (!properties && !
result.getRawProperties()) {
1602 std::optional<RegisteredOperationName> info =
1603 result.name.getRegisteredInfo();
1605 if (
failed(info->verifyInherentAttrs(
result.attributes, [&]() {
1606 return mlir::emitError(srcLocation) <<
"'" << name <<
"' op ";
1614 if (parseTrailingLocationSpecifier(op))
1622 << properties <<
" for op " << name <<
": ";
1631Operation *OperationParser::parseGenericOperation(
Block *insertBlock,
1633 Token nameToken = getToken();
1635 OpBuilder::InsertionGuard restoreInsertionPoint(opBuilder);
1636 opBuilder.setInsertionPoint(insertBlock, insertPt);
1637 Operation *op = parseGenericOperation();
1646 getLastToken().getEndLoc());
1651class CustomOpAsmParser :
public AsmParserImpl<OpAsmParser> {
1654 SMLoc nameLoc, ArrayRef<OperationParser::ResultRecord> resultIDs,
1655 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly,
1656 bool isIsolatedFromAbove, StringRef opName, OperationParser &parser)
1657 : AsmParserImpl<OpAsmParser>(nameLoc, parser), resultIDs(resultIDs),
1658 parseAssembly(parseAssembly), isIsolatedFromAbove(isIsolatedFromAbove),
1659 opName(opName), parser(parser) {
1660 (void)isIsolatedFromAbove;
1665 ParseResult parseOperation(OperationState &opState) {
1666 if (parseAssembly(*
this, opState))
1672 std::optional<NamedAttribute> duplicate =
1675 return emitError(getNameLoc(),
"attribute '")
1676 << duplicate->getName().getValue()
1677 <<
"' occurs more than once in the attribute list";
1681 Operation *parseGenericOperation(
Block *insertBlock,
1683 return parser.parseGenericOperation(insertBlock, insertPt);
1686 FailureOr<OperationName> parseCustomOperationName() final {
1687 return parser.parseCustomOperationName();
1690 ParseResult parseGenericOperationAfterOpName(
1692 std::optional<ArrayRef<UnresolvedOperand>> parsedUnresolvedOperands,
1693 std::optional<ArrayRef<Block *>> parsedSuccessors,
1694 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1695 std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1696 std::optional<Attribute> parsedPropertiesAttribute,
1697 std::optional<FunctionType> parsedFnType)
final {
1698 return parser.parseGenericOperationAfterOpName(
1699 result, parsedUnresolvedOperands, parsedSuccessors, parsedRegions,
1700 parsedAttributes, parsedPropertiesAttribute, parsedFnType);
1715 std::pair<StringRef, unsigned>
1716 getResultName(
unsigned resultNo)
const override {
1718 for (
const auto &entry : resultIDs) {
1719 if (resultNo < std::get<1>(entry)) {
1721 StringRef name = std::get<0>(entry).drop_front();
1722 return {name, resultNo};
1724 resultNo -= std::get<1>(entry);
1733 size_t getNumResults()
const override {
1735 for (
auto &entry : resultIDs)
1736 count += std::get<1>(entry);
1741 InFlightDiagnostic
emitError(SMLoc loc,
const Twine &message)
override {
1751 ParseResult parseOperand(UnresolvedOperand &
result,
1752 bool allowResultNumber =
true)
override {
1753 OperationParser::UnresolvedOperand useInfo;
1754 if (parser.parseSSAUse(useInfo, allowResultNumber))
1763 parseOptionalOperand(UnresolvedOperand &
result,
1764 bool allowResultNumber =
true)
override {
1765 if (parser.getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
1766 return parseOperand(
result, allowResultNumber);
1767 return std::nullopt;
1772 ParseResult parseOperandList(SmallVectorImpl<UnresolvedOperand> &
result,
1773 Delimiter delimiter = Delimiter::None,
1774 bool allowResultNumber =
true,
1775 int requiredOperandCount = -1)
override {
1777 if (delimiter == Delimiter::None) {
1780 Token tok = parser.getToken();
1784 if (requiredOperandCount == -1 || requiredOperandCount == 0)
1788 if (tok.
isAny(Token::l_paren, Token::l_square))
1789 return parser.emitError(
"unexpected delimiter");
1790 return parser.emitWrongTokenError(
"expected operand");
1794 auto parseOneOperand = [&]() -> ParseResult {
1795 return parseOperand(
result.emplace_back(), allowResultNumber);
1798 auto startLoc = parser.getToken().getLoc();
1803 if (requiredOperandCount != -1 &&
1804 result.size() !=
static_cast<size_t>(requiredOperandCount))
1806 << requiredOperandCount <<
" operands";
1811 ParseResult resolveOperand(
const UnresolvedOperand &operand, Type type,
1812 SmallVectorImpl<Value> &
result)
override {
1813 if (
auto value = parser.resolveSSAUse(operand, type)) {
1822 parseAffineMapOfSSAIds(SmallVectorImpl<UnresolvedOperand> &operands,
1823 Attribute &mapAttr, StringRef attrName,
1824 NamedAttrList &attrs, Delimiter delimiter)
override {
1825 SmallVector<UnresolvedOperand, 2> dimOperands;
1826 SmallVector<UnresolvedOperand, 1> symOperands;
1828 auto parseElement = [&]() -> FailureOr<UnresolvedOperand> {
1829 UnresolvedOperand operand;
1830 if (parseOperand(operand))
1834 auto addOperand = [&](
bool isSymbol, UnresolvedOperand operand) {
1836 symOperands.push_back(operand);
1838 dimOperands.push_back(operand);
1842 if (parser.parseAffineMapOfSSAIds(map, parseElement, addOperand, delimiter))
1846 mapAttr = AffineMapAttr::get(map);
1847 attrs.
push_back(parser.builder.getNamedAttr(attrName, mapAttr));
1851 operands.assign(dimOperands.begin(), dimOperands.end());
1852 operands.append(symOperands.begin(), symOperands.end());
1858 parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands,
1859 SmallVectorImpl<UnresolvedOperand> &symOperands,
1860 AffineExpr &expr)
override {
1861 auto parseElement = [&]() -> FailureOr<UnresolvedOperand> {
1862 UnresolvedOperand operand;
1863 if (parseOperand(operand))
1867 auto addOperand = [&](
bool isSymbol, UnresolvedOperand operand) {
1869 symOperands.push_back(operand);
1871 dimOperands.push_back(operand);
1874 return parser.parseAffineExprOfSSAIds(expr, parseElement, addOperand);
1887 ParseResult parseArgument(Argument &
result,
bool allowType =
false,
1888 bool allowAttrs =
false)
override {
1889 NamedAttrList attrs;
1890 if (parseOperand(
result.ssaName,
false) ||
1891 (allowType && parseColonType(
result.type)) ||
1892 (allowAttrs && parseOptionalAttrDict(attrs)) ||
1893 parseOptionalLocationSpecifier(
result.sourceLoc))
1900 OptionalParseResult parseOptionalArgument(Argument &
result,
bool allowType,
1901 bool allowAttrs)
override {
1902 if (parser.getToken().is(Token::percent_identifier))
1903 return parseArgument(
result, allowType, allowAttrs);
1904 return std::nullopt;
1907 ParseResult parseArgumentList(SmallVectorImpl<Argument> &
result,
1908 Delimiter delimiter,
bool allowType,
1909 bool allowAttrs)
override {
1911 if (delimiter == Delimiter::None &&
1912 parser.getToken().isNot(Token::percent_identifier))
1915 auto parseOneArgument = [&]() -> ParseResult {
1916 return parseArgument(
result.emplace_back(), allowType, allowAttrs);
1919 " in argument list");
1928 ParseResult parseRegion(Region ®ion, ArrayRef<Argument> arguments,
1929 bool enableNameShadowing)
override {
1931 (void)isIsolatedFromAbove;
1932 assert((!enableNameShadowing || isIsolatedFromAbove) &&
1933 "name shadowing is only allowed on isolated regions");
1934 if (parser.parseRegion(region, arguments, enableNameShadowing))
1940 OptionalParseResult parseOptionalRegion(Region ®ion,
1941 ArrayRef<Argument> arguments,
1942 bool enableNameShadowing)
override {
1943 if (parser.getToken().isNot(Token::l_brace))
1944 return std::nullopt;
1945 return parseRegion(region, arguments, enableNameShadowing);
1952 parseOptionalRegion(std::unique_ptr<Region> ®ion,
1953 ArrayRef<Argument> arguments,
1954 bool enableNameShadowing =
false)
override {
1955 if (parser.getToken().isNot(Token::l_brace))
1956 return std::nullopt;
1957 std::unique_ptr<Region> newRegion = std::make_unique<Region>();
1958 if (parseRegion(*newRegion, arguments, enableNameShadowing))
1961 region = std::move(newRegion);
1970 ParseResult parseSuccessor(
Block *&dest)
override {
1971 return parser.parseSuccessor(dest);
1975 OptionalParseResult parseOptionalSuccessor(
Block *&dest)
override {
1976 if (!parser.getToken().isOrIsCodeCompletionFor(Token::caret_identifier))
1977 return std::nullopt;
1978 return parseSuccessor(dest);
1983 parseSuccessorAndUseList(
Block *&dest,
1984 SmallVectorImpl<Value> &operands)
override {
1985 if (parseSuccessor(dest))
1989 if (succeeded(parseOptionalLParen()) &&
1990 (parser.parseOptionalSSAUseAndTypeList(operands) || parseRParen())) {
2002 OptionalParseResult parseOptionalAssignmentList(
2003 SmallVectorImpl<Argument> &
lhs,
2004 SmallVectorImpl<UnresolvedOperand> &
rhs)
override {
2005 if (
failed(parseOptionalLParen()))
2006 return std::nullopt;
2008 auto parseElt = [&]() -> ParseResult {
2009 if (parseArgument(
lhs.emplace_back()) || parseEqual() ||
2010 parseOperand(
rhs.emplace_back()))
2014 return parser.parseCommaSeparatedListUntil(Token::r_paren, parseElt);
2019 parseOptionalLocationSpecifier(std::optional<Location> &
result)
override {
2021 if (!parser.consumeIf(Token::kw_loc))
2023 LocationAttr directLoc;
2024 if (parser.parseToken(Token::l_paren,
"expected '(' in location"))
2027 Token tok = parser.getToken();
2033 if (tok.
is(Token::hash_identifier) && !tok.
getSpelling().contains(
'.')) {
2034 if (parser.parseLocationAlias(directLoc))
2036 }
else if (parser.parseLocationInstance(directLoc)) {
2040 if (parser.parseToken(Token::r_paren,
"expected ')' in location"))
2049 ArrayRef<OperationParser::ResultRecord> resultIDs;
2052 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly;
2053 bool isIsolatedFromAbove;
2057 OperationParser &parser;
2061FailureOr<OperationName> OperationParser::parseCustomOperationName() {
2062 Token nameTok = getToken();
2067 return emitError(
"expected bare identifier or keyword");
2070 return (
emitError(
"empty operation name is invalid"), failure());
2074 std::optional<RegisteredOperationName> opInfo =
2081 auto opNameSplit = opName.split(
'.');
2082 StringRef dialectName = opNameSplit.first;
2083 std::string opNameStorage;
2084 if (opNameSplit.second.empty()) {
2086 if (getToken().isCodeCompletion() && opName.back() ==
'.')
2087 return codeCompleteOperationName(dialectName);
2089 dialectName = getState().defaultDialectStack.back();
2090 opNameStorage = (dialectName +
"." + opName).str();
2091 opName = opNameStorage;
2101OperationParser::parseCustomOperation(ArrayRef<ResultRecord> resultIDs) {
2102 SMLoc opLoc = getToken().getLoc();
2103 StringRef originalOpName = getTokenSpelling();
2105 FailureOr<OperationName> opNameInfo = parseCustomOperationName();
2108 StringRef opName = opNameInfo->getStringRef();
2114 bool isIsolatedFromAbove =
false;
2116 StringRef defaultDialect =
"";
2117 if (
auto opInfo = opNameInfo->getRegisteredInfo()) {
2118 parseAssemblyFn = opInfo->getParseAssemblyFn();
2119 isIsolatedFromAbove = opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>();
2120 auto *iface = opInfo->getInterface<OpAsmOpInterface>();
2121 if (iface && !iface->getDefaultDialect().empty())
2122 defaultDialect = iface->getDefaultDialect();
2124 std::optional<Dialect::ParseOpHook> dialectHook;
2125 Dialect *dialect = opNameInfo->getDialect();
2127 InFlightDiagnostic diag =
2128 emitError(opLoc) <<
"Dialect `" << opNameInfo->getDialectNamespace()
2129 <<
"' not found for custom op '" << originalOpName
2131 if (originalOpName != opName)
2132 diag <<
" (tried '" << opName <<
"' as well)";
2134 note <<
"Available dialects: ";
2135 std::vector<StringRef> registered =
getContext()->getAvailableDialects();
2136 auto loaded =
getContext()->getLoadedDialects();
2139 SmallVector<std::pair<StringRef, bool>> mergedDialects;
2140 auto regIt = registered.begin(), regEnd = registered.end();
2141 auto loadIt = loaded.rbegin(), loadEnd = loaded.rend();
2142 bool isRegistered =
false;
2143 bool isOnlyLoaded =
true;
2144 while (regIt != regEnd && loadIt != loadEnd) {
2145 StringRef reg = *regIt;
2146 StringRef
load = (*loadIt)->getNamespace();
2148 mergedDialects.emplace_back(
load, isOnlyLoaded);
2151 mergedDialects.emplace_back(reg, isRegistered);
2157 for (; regIt != regEnd; ++regIt)
2158 mergedDialects.emplace_back(*regIt, isRegistered);
2159 for (; loadIt != loadEnd; ++loadIt)
2160 mergedDialects.emplace_back((*loadIt)->getNamespace(), isOnlyLoaded);
2162 bool loadedUnregistered =
false;
2163 llvm::interleaveComma(mergedDialects, note, [&](
auto &pair) {
2166 loadedUnregistered =
true;
2171 if (loadedUnregistered)
2172 note <<
"(* corresponding to loaded but unregistered dialects)";
2173 note <<
"; for more info on dialect registration see "
2174 "https://mlir.llvm.org/getting_started/Faq/"
2175 "#registered-loaded-dependent-whats-up-with-dialects-management";
2180 InFlightDiagnostic diag =
2181 emitError(opLoc) <<
"custom op '" << originalOpName <<
"' is unknown";
2182 if (originalOpName != opName)
2183 diag <<
" (tried '" << opName <<
"' as well)";
2186 parseAssemblyFn = *dialectHook;
2188 getState().defaultDialectStack.push_back(defaultDialect);
2189 llvm::scope_exit restoreDefaultDialect(
2190 [&]() { getState().defaultDialectStack.pop_back(); });
2194 llvm::PrettyStackTraceFormat fmt(
"MLIR Parser: custom op parser '%s'",
2195 opNameInfo->getIdentifier().data());
2198 auto srcLocation = getEncodedSourceLocation(opLoc);
2199 OperationState opState(srcLocation, *opNameInfo);
2206 CleanupOpStateRegions guard{opState};
2207 CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn,
2208 isIsolatedFromAbove, opName, *
this);
2209 if (opAsmParser.parseOperation(opState))
2213 if (opAsmParser.didEmitError())
2220 Operation *op = opBuilder.
create(opState);
2221 if (parseTrailingLocationSpecifier(op))
2237ParseResult OperationParser::parseLocationAlias(LocationAttr &loc) {
2238 Token tok = getToken();
2239 consumeToken(Token::hash_identifier);
2240 StringRef identifier = tok.
getSpelling().drop_front();
2241 assert(!identifier.contains(
'.') &&
2242 "unexpected dialect attribute token, expected alias");
2250 if (!(loc = dyn_cast<LocationAttr>(attr)))
2252 <<
"expected location, but found '" << attr <<
"'";
2256 loc = OpaqueLoc::get(deferredLocsReferences.size(),
2259 deferredLocsReferences.push_back(DeferredLocInfo{tok.
getLoc(), identifier});
2265OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) {
2267 if (!consumeIf(Token::kw_loc))
2269 if (parseToken(Token::l_paren,
"expected '(' in location"))
2271 Token tok = getToken();
2276 LocationAttr directLoc;
2277 if (tok.
is(Token::hash_identifier) && !tok.
getSpelling().contains(
'.')) {
2278 if (parseLocationAlias(directLoc))
2280 }
else if (parseLocationInstance(directLoc)) {
2284 if (parseToken(Token::r_paren,
"expected ')' in location"))
2287 if (
auto *op = llvm::dyn_cast_if_present<Operation *>(opOrArgument))
2290 cast<BlockArgument>(opOrArgument).setLoc(directLoc);
2298ParseResult OperationParser::parseRegion(Region ®ion,
2299 ArrayRef<Argument> entryArguments,
2300 bool isIsolatedNameScope) {
2302 Token lBraceTok = getToken();
2303 if (parseToken(Token::l_brace,
"expected '{' to begin a region"))
2311 if ((!entryArguments.empty() || getToken().isNot(Token::r_brace)) &&
2312 parseRegionBody(region, lBraceTok.
getLoc(), entryArguments,
2313 isIsolatedNameScope)) {
2316 consumeToken(Token::r_brace);
2325ParseResult OperationParser::parseRegionBody(Region ®ion, SMLoc startLoc,
2326 ArrayRef<Argument> entryArguments,
2327 bool isIsolatedNameScope) {
2328 auto currentPt = opBuilder.saveInsertionPoint();
2331 pushSSANameScope(isIsolatedNameScope);
2334 auto owningBlock = std::make_unique<Block>();
2335 llvm::scope_exit failureCleanup([&] {
2340 owningBlock->dropAllDefinedValueUses();
2343 Block *block = owningBlock.get();
2348 if (state.
asmState && getToken().isNot(Token::caret_identifier))
2352 if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) {
2354 if (getToken().is(Token::caret_identifier))
2355 return emitError(
"invalid block name in region with named arguments");
2357 for (
auto &entryArg : entryArguments) {
2358 auto &argInfo = entryArg.ssaName;
2361 if (
auto defLoc = getReferenceLoc(argInfo.name, argInfo.number)) {
2362 return emitError(argInfo.location,
"region entry argument '" +
2364 "' is already in use")
2365 .
attachNote(getEncodedSourceLocation(*defLoc))
2366 <<
"previously referenced here";
2368 Location loc = entryArg.sourceLoc.has_value()
2369 ? *entryArg.sourceLoc
2370 : getEncodedSourceLocation(argInfo.location);
2371 BlockArgument arg = block->addArgument(entryArg.type, loc);
2378 if (addDefinition(argInfo, arg))
2383 if (parseBlock(block))
2387 if (!entryArguments.empty() &&
2388 block->getNumArguments() > entryArguments.size()) {
2389 return emitError(
"entry block arguments were already defined");
2393 region.
push_back(owningBlock.release());
2394 while (getToken().isNot(Token::r_brace)) {
2395 Block *newBlock =
nullptr;
2396 if (parseBlock(newBlock))
2402 if (popSSANameScope())
2406 opBuilder.restoreInsertionPoint(currentPt);
2421ParseResult OperationParser::parseBlock(
Block *&block) {
2424 if (block && getToken().isNot(Token::caret_identifier))
2425 return parseBlockBody(block);
2427 SMLoc nameLoc = getToken().getLoc();
2428 auto name = getTokenSpelling();
2429 if (parseToken(Token::caret_identifier,
"expected block name"))
2433 auto &blockAndLoc = getBlockInfoByName(name);
2434 blockAndLoc.loc = nameLoc;
2439 std::unique_ptr<Block> inflightBlock;
2440 llvm::scope_exit cleanupOnFailure([&] {
2442 inflightBlock->dropAllDefinedValueUses();
2447 if (!blockAndLoc.block) {
2449 blockAndLoc.block = block;
2451 inflightBlock = std::make_unique<Block>();
2452 blockAndLoc.block = inflightBlock.get();
2459 }
else if (!eraseForwardRef(blockAndLoc.block)) {
2460 return emitError(nameLoc,
"redefinition of block '") << name <<
"'";
2464 inflightBlock.reset(blockAndLoc.block);
2470 block = blockAndLoc.block;
2473 if (getToken().is(Token::l_paren))
2474 if (parseOptionalBlockArgList(block))
2476 if (parseToken(Token::colon,
"expected ':' after block name"))
2480 ParseResult res = parseBlockBody(block);
2485 (void)inflightBlock.release();
2489ParseResult OperationParser::parseBlockBody(
Block *block) {
2491 opBuilder.setInsertionPointToEnd(block);
2494 while (getToken().isNot(Token::caret_identifier, Token::r_brace))
2495 if (parseOperation())
2504Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
2505 BlockDefinition &blockDef = getBlockInfoByName(name);
2506 if (!blockDef.block) {
2507 blockDef = {
new Block(), loc};
2508 insertForwardRef(blockDef.block, blockDef.loc);
2515 return blockDef.block;
2524ParseResult OperationParser::parseOptionalBlockArgList(
Block *owner) {
2525 if (getToken().is(Token::r_brace))
2531 unsigned nextArgument = 0;
2534 return parseSSADefOrUseAndType(
2535 [&](UnresolvedOperand useInfo, Type type) -> ParseResult {
2540 if (definingExistingArgs) {
2543 return emitError(
"too many arguments specified in argument list");
2548 return emitError(
"argument and block argument type mismatch");
2550 auto loc = getEncodedSourceLocation(useInfo.location);
2556 if (parseTrailingLocationSpecifier(arg))
2564 return addDefinition(useInfo, arg);
2573ParseResult OperationParser::codeCompleteSSAUse() {
2574 for (IsolatedSSANameScope &scope : isolatedNameScopes) {
2576 SmallVector<StringRef> sortedNames;
2577 for (
auto &it : scope.values)
2578 if (!it.second.empty())
2579 sortedNames.push_back(it.getKey());
2580 llvm::sort(sortedNames);
2582 for (StringRef name : sortedNames) {
2583 Value frontValue = scope.values[name].front().value;
2585 std::string detailData;
2586 llvm::raw_string_ostream detailOS(detailData);
2590 if (
auto result = dyn_cast<OpResult>(frontValue)) {
2591 if (!forwardRefPlaceholders.count(
result))
2592 detailOS <<
result.getOwner()->getName() <<
": ";
2594 detailOS <<
"arg #" << cast<BlockArgument>(frontValue).getArgNumber()
2599 detailOS << frontValue.
getType();
2604 if (scope.values[name].size() > 1)
2605 detailOS <<
", ...";
2608 name, std::move(detailData));
2615ParseResult OperationParser::codeCompleteBlock() {
2618 StringRef spelling = getTokenSpelling();
2619 if (!(spelling.empty() || spelling ==
"^"))
2622 for (
const auto &it : blocksByName.back())
2634class TopLevelOperationParser :
public Parser {
2636 explicit TopLevelOperationParser(ParserState &state) : Parser(state) {}
2639 ParseResult
parse(
Block *topLevelBlock, Location parserLoc);
2646 ParseResult parseAttributeAliasDef();
2652 ParseResult parseTypeAliasDef();
2658 ParseResult parseFileMetadataDictionary();
2661 ParseResult parseResourceFileMetadata(
2662 function_ref<ParseResult(StringRef, SMLoc)> parseBody);
2663 ParseResult parseDialectResourceFileMetadata();
2664 ParseResult parseExternalResourceFileMetadata();
2669class ParsedResourceEntry :
public AsmParsedResourceEntry {
2671 ParsedResourceEntry(std::string key, SMLoc keyLoc, Token value, Parser &p)
2672 : key(std::move(key)), keyLoc(keyLoc), value(value), p(p) {}
2673 ~ParsedResourceEntry()
override =
default;
2675 StringRef getKey() const final {
return key; }
2677 InFlightDiagnostic
emitError() const final {
return p.emitError(keyLoc); }
2680 if (value.isAny(Token::kw_true, Token::kw_false))
2681 return AsmResourceEntryKind::Bool;
2682 return value.getSpelling().starts_with(
"\"0x")
2683 ? AsmResourceEntryKind::Blob
2684 : AsmResourceEntryKind::String;
2687 FailureOr<bool> parseAsBool() const final {
2688 if (value.is(Token::kw_true))
2690 if (value.is(Token::kw_false))
2692 return p.emitError(value.getLoc(),
2693 "expected 'true' or 'false' value for key '" + key +
2697 FailureOr<std::string> parseAsString() const final {
2698 if (value.isNot(Token::string))
2699 return p.emitError(value.getLoc(),
2700 "expected string value for key '" + key +
"'");
2701 return value.getStringValue();
2704 FailureOr<AsmResourceBlob>
2705 parseAsBlob(BlobAllocatorFn allocator)
const final {
2709 std::optional<std::string> blobData =
2710 value.is(Token::string) ? value.getHexStringValue() : std::nullopt;
2712 return p.emitError(value.getLoc(),
2713 "expected hex string blob for key '" + key +
"'");
2717 if (blobData->size() <
sizeof(uint32_t)) {
2718 return p.emitError(value.getLoc(),
2719 "expected hex string blob for key '" + key +
2720 "' to encode alignment in first 4 bytes");
2722 llvm::support::ulittle32_t align;
2723 memcpy(&align, blobData->data(),
sizeof(uint32_t));
2724 if (align && !llvm::isPowerOf2_32(align)) {
2725 return p.emitError(value.getLoc(),
2726 "expected hex string blob for key '" + key +
2727 "' to encode alignment in first 4 bytes, but got "
2728 "non-power-of-2 value: " +
2733 StringRef data = StringRef(*blobData).drop_front(
sizeof(uint32_t));
2735 return AsmResourceBlob();
2739 AsmResourceBlob blob = allocator(data.size(), align);
2740 assert(llvm::isAddrAligned(llvm::Align(align), blob.
getData().data()) &&
2742 "blob allocator did not return a properly aligned address");
2755ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
2756 assert(getToken().is(Token::hash_identifier));
2757 StringRef aliasName = getTokenSpelling().drop_front();
2761 return emitError(
"redefinition of attribute alias id '" + aliasName +
"'");
2764 if (aliasName.contains(
'.'))
2765 return emitError(
"attribute names with a '.' are reserved for "
2766 "dialect-defined names");
2768 SMRange location = getToken().getLocRange();
2769 consumeToken(Token::hash_identifier);
2772 if (parseToken(Token::equal,
"expected '=' in attribute alias definition"))
2787ParseResult TopLevelOperationParser::parseTypeAliasDef() {
2788 assert(getToken().is(Token::exclamation_identifier));
2789 StringRef aliasName = getTokenSpelling().drop_front();
2793 return emitError(
"redefinition of type alias id '" + aliasName +
"'");
2796 if (aliasName.contains(
'.'))
2797 return emitError(
"type names with a '.' are reserved for "
2798 "dialect-defined names");
2800 SMRange location = getToken().getLocRange();
2801 consumeToken(Token::exclamation_identifier);
2804 if (parseToken(Token::equal,
"expected '=' in type alias definition"))
2819ParseResult TopLevelOperationParser::parseFileMetadataDictionary() {
2820 consumeToken(Token::file_metadata_begin);
2821 return parseCommaSeparatedListUntil(
2822 Token::file_metadata_end, [&]() -> ParseResult {
2824 SMLoc keyLoc = getToken().getLoc();
2826 if (
failed(parseOptionalKeyword(&key)))
2827 return emitError(
"expected identifier key in file "
2828 "metadata dictionary");
2829 if (parseToken(Token::colon,
"expected ':'"))
2833 if (key ==
"dialect_resources")
2834 return parseDialectResourceFileMetadata();
2835 if (key ==
"external_resources")
2836 return parseExternalResourceFileMetadata();
2837 return emitError(keyLoc,
"unknown key '" + key +
2838 "' in file metadata dictionary");
2842ParseResult TopLevelOperationParser::parseResourceFileMetadata(
2843 function_ref<ParseResult(StringRef, SMLoc)> parseBody) {
2844 if (parseToken(Token::l_brace,
"expected '{'"))
2847 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2849 SMLoc nameLoc = getToken().getLoc();
2851 if (
failed(parseOptionalKeyword(&name)))
2852 return emitError(
"expected identifier key for 'resource' entry");
2854 if (parseToken(Token::colon,
"expected ':'") ||
2855 parseToken(Token::l_brace,
"expected '{'"))
2857 return parseBody(name, nameLoc);
2861ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() {
2862 return parseResourceFileMetadata([&](StringRef name,
2863 SMLoc nameLoc) -> ParseResult {
2865 Dialect *dialect =
getContext()->getOrLoadDialect(name);
2867 return emitError(nameLoc,
"dialect '" + name +
"' is unknown");
2868 const auto *handler = dyn_cast<OpAsmDialectInterface>(dialect);
2870 return emitError() <<
"unexpected 'resource' section for dialect '"
2874 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2876 SMLoc keyLoc = getToken().getLoc();
2878 if (
failed(parseResourceHandle(handler, key)) ||
2879 parseToken(Token::colon,
"expected ':'"))
2881 Token valueTok = getToken();
2884 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2885 return handler->parseResource(entry);
2890ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() {
2891 return parseResourceFileMetadata([&](StringRef name,
2892 SMLoc nameLoc) -> ParseResult {
2898 <<
"ignoring unknown external resources for '" << name <<
"'";
2901 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2903 SMLoc keyLoc = getToken().getLoc();
2905 if (
failed(parseOptionalKeywordOrString(&key)))
2907 "expected identifier key for 'external_resources' entry");
2908 if (parseToken(Token::colon,
"expected ':'"))
2910 Token valueTok = getToken();
2915 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2921ParseResult TopLevelOperationParser::parse(
Block *topLevelBlock,
2922 Location parserLoc) {
2924 OwningOpRef<ModuleOp> topLevelOp(ModuleOp::create(parserLoc));
2925 OperationParser opParser(state, topLevelOp.get());
2927 switch (getToken().getKind()) {
2930 if (opParser.parseOperation())
2936 if (opParser.finalize())
2941 auto &parsedOps = topLevelOp->getBody()->getOperations();
2943 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(),
2955 case Token::hash_identifier:
2956 if (parseAttributeAliasDef())
2961 case Token::exclamation_identifier:
2962 if (parseTypeAliasDef())
2967 case Token::file_metadata_begin:
2968 if (parseFileMetadataDictionary())
2981 const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
2988 ParserState state(sourceMgr, config, aliasState, asmState,
2989 codeCompleteContext);
2990 return TopLevelOperationParser(state).parse(block, parserLoc);
static size_t findCommentStart(StringRef line)
Find the start of a line comment (//) in the given string, ignoring occurrences inside string literal...
static bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
#define MLIR_DECLARE_EXPLICIT_SELF_OWNING_TYPE_ID(CLASS_NAME)
#define MLIR_DEFINE_EXPLICIT_SELF_OWNING_TYPE_ID(CLASS_NAME)
This class provides an abstract interface into the parser for hooking in code completion events.
virtual void appendBlockCompletion(StringRef name)=0
Append the given block as a code completion result for block name completions.
virtual void appendSSAValueCompletion(StringRef name, std::string typeData)=0
Append the given SSA value as a code completion result for SSA value completions.
virtual ~AsmParserCodeCompleteContext()
This class represents state from a parsed MLIR textual format string.
void startRegionDefinition()
Start a definition for a region nested under the current operation.
void startOperationDefinition(const OperationName &opName)
Start a definition for an operation with the given name.
void finalizeOperationDefinition(Operation *op, SMRange nameLoc, SMLoc endLoc, ArrayRef< std::pair< unsigned, SMLoc > > resultGroups={})
Finalize the most recently started operation definition.
void addAttrAliasUses(StringRef name, SMRange locations)
void addAttrAliasDefinition(StringRef name, SMRange location, Attribute value)
void finalize(Operation *topLevelOp)
Finalize any in-progress parser state under the given top-level operation.
void addUses(Value value, ArrayRef< SMLoc > locations)
Add a source uses of the given value.
void refineDefinition(Value oldValue, Value newValue)
Refine the oldValue to the newValue.
void finalizeRegionDefinition()
Finalize the most recently started region definition.
void addTypeAliasDefinition(StringRef name, SMRange location, Type value)
void addDefinition(Block *block, SMLoc location)
Add a definition of the given entity.
MutableArrayRef< char > getMutableData()
Return a mutable reference to the raw underlying data of this blob.
ArrayRef< char > getData() const
Return the raw underlying data of this blob.
bool isMutable() const
Return if the data of this blob is mutable.
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry)=0
Parse the given resource entry.
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
OpListType::iterator iterator
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
OpListType & getOperations()
void dropAllDefinedValueUses()
This drops all uses of values defined in this block or in the blocks of nested regions wherever the u...
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
BlockArgListType getArguments()
Diagnostic & append(Arg1 &&arg1, Arg2 &&arg2, Args &&...args)
Append arguments to the diagnostic.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
virtual std::optional< ParseOpHook > getParseOperationHook(StringRef opName) const
Return the hook to parse an operation registered to this dialect, if any.
StringRef getNamespace() const
static FileLineColLoc get(StringAttr filename, unsigned line, unsigned column)
This class represents a diagnostic that is inflight and set to be reported.
InFlightDiagnostic & append(Args &&...args) &
Append arguments to the diagnostic.
Diagnostic & attachNote(std::optional< Location > noteLoc=std::nullopt)
Attaches a note to this diagnostic.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
void push_back(NamedAttribute newAttribute)
Add an attribute with the specified name.
std::optional< NamedAttribute > findDuplicate() const
Returns an entry with a duplicate name the list, if it exists, else returns std::nullopt.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
llvm::unique_function< ParseResult(OpAsmParser &, OperationState &)> ParseAssemblyFn
void setLoc(Location loc)
Set the source location the operation was defined or derived from.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
OperationName getName()
The name of an operation is the key identifier for it.
LogicalResult setPropertiesFromAttribute(Attribute attr, function_ref< InFlightDiagnostic()> emitError)
Set the properties from the provided attribute.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, PropertyRef properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
unsigned getNumResults()
Return the number of results held by this operation.
This class implements Optional functionality for ParseResult.
This class represents a configuration for the MLIR assembly parser.
MLIRContext * getContext() const
Return the MLIRContext to be used when parsing.
bool shouldVerifyAfterParse() const
Returns if the parser should verify the IR after parsing.
AsmResourceParser * getResourceParser(StringRef name) const
Return the resource parser registered to the given name, or nullptr if no parser with name is registe...
void push_back(Block *block)
static std::optional< RegisteredOperationName > lookup(StringRef name, MLIRContext *ctx)
Lookup the registered operation information for the given operation.
This represents a token in the MLIR syntax.
bool isCodeCompletionFor(Kind kind) const
Returns true if the current token represents a code completion for the "normal" token type.
SMRange getLocRange() const
bool isKeyword() const
Return true if this is one of the keyword token kinds (e.g. kw_if).
static StringRef getTokenSpelling(Kind kind)
Given a punctuation or keyword token kind, return the spelling of the token as a string.
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
bool isAny(Kind k1, Kind k2) const
bool isCodeCompletion() const
Returns true if the current token represents a code completion.
StringRef getSpelling() const
bool isOrIsCodeCompletionFor(Kind kind) const
Returns true if the current token is the given type, or represents a code completion for that type.
static TypeID get()
Construct a type info object for the given type T.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
static WalkResult advance()
static WalkResult interrupt()
This class provides the implementation of the generic parser methods within AsmParser.
InFlightDiagnostic emitError(SMLoc loc, const Twine &message) override
Emit a diagnostic at the specified location and return failure.
This class implement support for parsing global entities like attributes and types.
ParseResult parseFloatFromLiteral(std::optional< APFloat > &result, const Token &tok, bool isNegative, const llvm::fltSemantics &semantics)
Parse a floating point value from a literal.
ParseResult parseOptionalKeywordOrString(std::string *result)
Parse an optional keyword or string and set instance into 'result'.`.
ParseResult parseOptionalKeyword(StringRef *keyword)
Parse a keyword, if present, into 'keyword'.
OpAsmParser::Delimiter Delimiter
ParseResult parseToken(Token::Kind expectedToken, const Twine &message)
Consume the specified token if present and return success.
ParseResult parseCommaSeparatedListUntil(Token::Kind rightToken, function_ref< ParseResult()> parseElement, bool allowEmptyList=true)
Parse a comma-separated list of elements up until the specified end token.
ParseResult codeCompleteOperationName(StringRef dialectName)
OptionalParseResult parseOptionalDecimalInteger(APInt &result)
Parse an optional integer value only in decimal format from the stream.
Location getEncodedSourceLocation(SMLoc loc)
Encode the specified source location information into an attribute for attachment to the IR.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error and return failure.
ParserState & state
The Parser is subclassed and reinstantiated.
ParseResult codeCompleteDialectName()
The set of various code completion methods. Every completion method returns failure to signal that pa...
StringRef getTokenSpelling() const
ParserState & getState() const
FailureOr< AsmDialectResourceHandle > parseResourceHandle(const OpAsmDialectInterface *dialect, std::string &name)
Parse a handle to a dialect resource within the assembly format.
void consumeToken()
Advance the current lexer onto the next token.
ParseResult codeCompleteExpectedTokens(ArrayRef< StringRef > tokens)
Attribute codeCompleteAttribute()
ParseResult parseOptionalString(std::string *string)
Parses a quoted string token if present.
ParseResult codeCompleteDialectOrElidedOpName(SMLoc loc)
InFlightDiagnostic emitWrongTokenError(const Twine &message={})
Emit an error about a "wrong token".
ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())
Parse a list of comma-separated items with an optional delimiter.
OptionalParseResult parseOptionalInteger(APInt &result)
Parse an optional integer value from the stream.
bool isCurrentTokenAKeyword() const
Returns true if the current token corresponds to a keyword.
ParseResult codeCompleteStringDialectOrOperationName(StringRef name)
ParseResult codeCompleteOptionalTokens(ArrayRef< StringRef > tokens)
ParseResult parseFloatFromIntegerLiteral(std::optional< APFloat > &result, const Token &tok, bool isNegative, const llvm::fltSemantics &semantics)
Parse a floating point value from an integer literal token.
const Token & getToken() const
Return the current token the parser is inspecting.
bool consumeIf(Token::Kind kind)
If the current token has the specified kind, consume it and return true.
Attribute codeCompleteDialectSymbol(const llvm::StringMap< Attribute > &aliases)
LogicalResult parseCommaSeparatedList(llvm::cl::Option &opt, StringRef argName, StringRef optionStr, function_ref< LogicalResult(StringRef)> elementParseFn)
Parse a string containing a list of comma-delimited elements, invoking the given parser for each sub-...
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Include the generated interface declarations.
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
LogicalResult parseAsmSourceFile(const llvm::SourceMgr &sourceMgr, Block *block, const ParserConfig &config, AsmParserState *asmState=nullptr, AsmParserCodeCompleteContext *codeCompleteContext=nullptr)
This parses the file specified by the indicated SourceMgr and appends parsed operations to the given ...
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
Attribute parseAttribute(llvm::StringRef attrStr, MLIRContext *context, Type type={}, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR attribute to an MLIR context if it was valid.
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
AsmResourceEntryKind
This enum represents the different kinds of resource values.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
llvm::function_ref< Fn > function_ref
This is the representation of an operand reference.
Attribute propertiesAttr
This Attribute is used to opaquely construct the properties of the operation.
This class refers to all of the state maintained globally by the parser, such as the current lexer po...
SymbolState & symbols
The current state for symbol parsing.
const ParserConfig & config
The configuration used to setup the parser.
AsmParserCodeCompleteContext * codeCompleteContext
An optional code completion context.
AsmParserState * asmState
An optional pointer to a struct containing high level parser state to be populated during parsing.
This class contains record of any parsed top-level symbols.
llvm::StringMap< Attribute > attributeAliasDefinitions
A map from attribute alias identifier to Attribute.
DenseMap< const OpAsmDialectInterface *, llvm::StringMap< std::pair< std::string, AsmDialectResourceHandle > > > dialectResources
A map of dialect resource keys to the resolved resource name and handle to use during parsing.
llvm::StringMap< Type > typeAliasDefinitions
A map from type alias identifier to Type.