38#include "llvm/ADT/APFloat.h"
39#include "llvm/ADT/DenseMap.h"
40#include "llvm/ADT/PointerUnion.h"
41#include "llvm/ADT/STLExtras.h"
42#include "llvm/ADT/ScopeExit.h"
43#include "llvm/ADT/Sequence.h"
44#include "llvm/ADT/StringExtras.h"
45#include "llvm/ADT/StringMap.h"
46#include "llvm/ADT/StringSet.h"
47#include "llvm/Support/Alignment.h"
48#include "llvm/Support/Casting.h"
49#include "llvm/Support/Endian.h"
50#include "llvm/Support/ErrorHandling.h"
51#include "llvm/Support/MathExtras.h"
52#include "llvm/Support/PrettyStackTrace.h"
53#include "llvm/Support/SourceMgr.h"
54#include "llvm/Support/raw_ostream.h"
86 StringRef contextMessage) {
90 case Delimiter::OptionalParen:
91 if (
getToken().isNot(Token::l_paren))
94 case Delimiter::Paren:
95 if (
parseToken(Token::l_paren,
"expected '('" + contextMessage))
101 case Delimiter::OptionalLessGreater:
106 case Delimiter::LessGreater:
107 if (
parseToken(Token::less,
"expected '<'" + contextMessage))
113 case Delimiter::OptionalSquare:
114 if (
getToken().isNot(Token::l_square))
117 case Delimiter::Square:
118 if (
parseToken(Token::l_square,
"expected '['" + contextMessage))
124 case Delimiter::OptionalBraces:
125 if (
getToken().isNot(Token::l_brace))
128 case Delimiter::Braces:
129 if (
parseToken(Token::l_brace,
"expected '{'" + contextMessage))
138 if (parseElementFn())
143 if (parseElementFn())
148 case Delimiter::None:
150 case Delimiter::OptionalParen:
151 case Delimiter::Paren:
152 return parseToken(Token::r_paren,
"expected ')'" + contextMessage);
153 case Delimiter::OptionalLessGreater:
154 case Delimiter::LessGreater:
155 return parseToken(Token::greater,
"expected '>'" + contextMessage);
156 case Delimiter::OptionalSquare:
157 case Delimiter::Square:
158 return parseToken(Token::r_square,
"expected ']'" + contextMessage);
159 case Delimiter::OptionalBraces:
160 case Delimiter::Braces:
161 return parseToken(Token::r_brace,
"expected '}'" + contextMessage);
163 llvm_unreachable(
"Unknown delimiter");
175 bool allowEmptyList) {
193 auto loc =
state.curToken.getLoc();
194 if (
state.curToken.isNot(Token::eof))
198 return emitError(SMLoc::getFromPointer(loc.getPointer() - 1), message);
206 size_t slashPos = line.find(
"//");
207 if (slashPos == StringRef::npos)
208 return StringRef::npos;
213 size_t quotePos = line.find(
'"');
214 if (quotePos == StringRef::npos || quotePos > slashPos)
218 bool inString =
false;
219 for (
size_t i = 0, e = line.size(); i < e; ++i) {
232 }
else if (c ==
'/' && i + 1 < e && line[i + 1] ==
'/') {
237 return StringRef::npos;
255 auto loc =
state.curToken.getLoc();
258 if (
state.curToken.is(Token::eof))
259 loc = SMLoc::getFromPointer(loc.getPointer() - 1);
262 auto originalLoc = loc;
265 const char *bufferStart =
state.lex.getBufferBegin();
266 const char *curPtr = loc.getPointer();
270 StringRef startOfBuffer(bufferStart, curPtr - bufferStart);
275 startOfBuffer = startOfBuffer.rtrim(
" \t");
279 if (startOfBuffer.empty())
283 if (startOfBuffer.back() !=
'\n' && startOfBuffer.back() !=
'\r')
284 return emitError(SMLoc::getFromPointer(startOfBuffer.end()), message);
287 startOfBuffer = startOfBuffer.drop_back();
290 auto prevLine = startOfBuffer;
291 size_t newLineIndex = prevLine.find_last_of(
"\n\r");
292 if (newLineIndex != StringRef::npos)
293 prevLine = prevLine.drop_front(newLineIndex);
298 if (commentStart != StringRef::npos)
299 startOfBuffer = startOfBuffer.drop_back(prevLine.size() - commentStart);
306 const Twine &message) {
336 if (curToken.
isNot(Token::integer, Token::minus))
341 if (
parseToken(Token::integer,
"expected integer value"))
345 bool isHex = spelling.size() > 1 && spelling[1] ==
'x';
346 if (spelling.getAsInteger(isHex ? 0 : 10,
result))
363 if (curToken.
isNot(Token::integer, Token::minus)) {
369 if (
parseToken(Token::integer,
"expected integer value")) {
377 if (spelling[0] ==
'0' && spelling.size() > 1 &&
378 llvm::toLower(spelling[1]) ==
'x') {
380 state.lex.resetPointer(spelling.data() + 1);
385 if (spelling.getAsInteger(10,
result))
400 const Token &tok,
bool isNegative,
401 const llvm::fltSemantics &semantics) {
403 if (tok.
is(Token::floatliteral)) {
411 if (isNegative && !APFloat::semanticsHasSignedRepr(semantics))
413 <<
"negative floating point literal for a type with no signed "
416 result.emplace(isNegative ? -*val : *val);
418 result->convert(semantics, APFloat::rmNearestTiesToEven, &unused);
423 if (tok.
is(Token::integer))
432 const Token &tok,
bool isNegative,
433 const llvm::fltSemantics &semantics) {
435 bool isHex = spelling.size() > 1 && spelling[1] ==
'x';
437 return emitError(tok.
getLoc(),
"unexpected decimal integer literal for a "
438 "floating point value")
440 <<
"add a trailing dot to make the literal a float";
444 "hexadecimal float literal should not have a "
449 tok.
getSpelling().getAsInteger(isHex ? 0 : 10, intValue);
450 auto typeSizeInBits = APFloat::semanticsSizeInBits(semantics);
451 if (intValue.getActiveBits() > typeSizeInBits) {
453 "hexadecimal float constant out of range for type");
456 APInt truncatedValue(typeSizeInBits,
457 ArrayRef(intValue.getRawData(), intValue.getNumWords()));
458 result.emplace(semantics, truncatedValue);
486FailureOr<AsmDialectResourceHandle>
489 assert(dialect &&
"expected valid dialect interface");
492 return emitError(
"expected identifier key for 'resource' entry");
498 std::pair<std::string, AsmDialectResourceHandle> &entry =
499 resources[dialect][name];
500 if (entry.first.empty()) {
501 FailureOr<AsmDialectResourceHandle>
result = dialect->declareResource(name);
504 <<
"unknown 'resource' key '" << name <<
"' for dialect '"
505 << dialect->getDialect()->getNamespace() <<
"'";
507 entry.first = dialect->getResourceKey(*
result);
515FailureOr<AsmDialectResourceHandle>
517 const auto *
interface = dyn_cast<OpAsmDialectInterface>(dialect);
520 <<
"' does not expect resource handles";
522 std::string resourceName;
531 state.codeCompleteContext->completeDialectName();
539 if (dialectName.empty() || dialectName.contains(
'.'))
541 state.codeCompleteContext->completeOperationName(dialectName);
550 auto shouldIgnoreOpCompletion = [&]() {
551 const char *bufBegin =
state.lex.getBufferBegin();
552 const char *it = loc.getPointer() - 1;
553 for (; it > bufBegin && *it !=
'\n'; --it)
554 if (!StringRef(
" \t\r").
contains(*it))
558 if (shouldIgnoreOpCompletion())
576 if (name.consume_back(
"."))
582 state.codeCompleteContext->completeExpectedTokens(tokens,
false);
586 state.codeCompleteContext->completeExpectedTokens(tokens,
true);
591 state.codeCompleteContext->completeAttribute(
592 state.symbols.attributeAliasDefinitions);
596 state.codeCompleteContext->completeType(
state.symbols.typeAliasDefinitions);
602 state.codeCompleteContext->completeDialectAttributeOrAlias(aliases);
606 state.codeCompleteContext->completeDialectTypeOrAlias(aliases);
617class OperationParser :
public Parser {
619 OperationParser(
ParserState &state, ModuleOp topLevelOp);
624 ParseResult finalize();
633 struct DeferredLocInfo {
635 StringRef identifier;
639 void pushSSANameScope(
bool isIsolated);
642 ParseResult popSSANameScope();
645 ParseResult addDefinition(UnresolvedOperand useInfo,
Value value);
653 ParseResult parseSSAUse(UnresolvedOperand &
result,
654 bool allowResultNumber =
true);
658 Value resolveSSAUse(UnresolvedOperand useInfo,
Type type);
660 ParseResult parseSSADefOrUseAndType(
667 std::optional<SMLoc> getReferenceLoc(StringRef name,
unsigned number) {
668 auto &values = isolatedNameScopes.back().values;
669 if (!values.count(name) || number >= values[name].size())
671 if (values[name][number].value)
672 return values[name][number].loc;
681 ParseResult parseOperation();
684 ParseResult parseSuccessor(
Block *&dest);
687 ParseResult parseSuccessors(SmallVectorImpl<Block *> &destinations);
690 Operation *parseGenericOperation();
697 ParseResult parseGenericOperationAfterOpName(
699 std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo =
701 std::optional<ArrayRef<Block *>> parsedSuccessors = std::nullopt,
702 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions =
704 std::optional<ArrayRef<NamedAttribute>> parsedAttributes = std::nullopt,
705 std::optional<Attribute> propertiesAttribute = std::nullopt,
706 std::optional<FunctionType> parsedFnType = std::nullopt);
710 Operation *parseGenericOperation(
Block *insertBlock,
716 using OpOrArgument = llvm::PointerUnion<Operation *, BlockArgument>;
723 ParseResult parseTrailingLocationSpecifier(OpOrArgument opOrArgument);
729 ParseResult parseLocationAlias(LocationAttr &loc);
733 using ResultRecord = std::tuple<StringRef, unsigned, SMLoc>;
737 Operation *parseCustomOperation(ArrayRef<ResultRecord> resultIDs);
741 FailureOr<OperationName> parseCustomOperationName();
750 ParseResult parseRegion(Region ®ion, ArrayRef<Argument> entryArguments,
751 bool isIsolatedNameScope =
false);
754 ParseResult parseRegionBody(Region ®ion, SMLoc startLoc,
755 ArrayRef<Argument> entryArguments,
756 bool isIsolatedNameScope);
763 ParseResult parseBlock(
Block *&block);
766 ParseResult parseBlockBody(
Block *block);
769 ParseResult parseOptionalBlockArgList(
Block *owner);
774 Block *getBlockNamed(StringRef name, SMLoc loc);
784 ParseResult codeCompleteSSAUse();
785 ParseResult codeCompleteBlock();
789 struct BlockDefinition {
796 struct ValueDefinition {
804 BlockDefinition &getBlockInfoByName(StringRef name) {
805 return blocksByName.back()[name];
809 void insertForwardRef(
Block *block, SMLoc loc) {
810 forwardRef.back().try_emplace(block, loc);
814 bool eraseForwardRef(
Block *block) {
return forwardRef.back().erase(block); }
817 void recordDefinition(StringRef def);
820 SmallVectorImpl<ValueDefinition> &getSSAValueEntry(StringRef name);
824 Value createForwardRefPlaceholder(SMLoc loc, Type type);
827 bool isForwardRefPlaceholder(Value value) {
828 return forwardRefPlaceholders.count(value);
835 struct IsolatedSSANameScope {
837 void recordDefinition(StringRef def) {
838 definitionsPerScope.back().insert(def);
842 void pushSSANameScope() { definitionsPerScope.push_back({}); }
845 void popSSANameScope() {
846 for (
auto &def : definitionsPerScope.pop_back_val())
847 values.erase(def.getKey());
852 llvm::StringMap<SmallVector<ValueDefinition, 1>> values;
855 SmallVector<llvm::StringSet<>, 2> definitionsPerScope;
859 SmallVector<IsolatedSSANameScope, 2> isolatedNameScopes;
864 SmallVector<DenseMap<StringRef, BlockDefinition>, 2> blocksByName;
865 SmallVector<DenseMap<Block *, SMLoc>, 2> forwardRef;
880 std::vector<DeferredLocInfo> deferredLocsReferences;
886 Operation *topLevelOp;
893OperationParser::OperationParser(
ParserState &state, ModuleOp topLevelOp)
894 :
Parser(state), opBuilder(topLevelOp.getRegion()), topLevelOp(topLevelOp) {
896 pushSSANameScope(
true);
900 state.asmState->initialize(topLevelOp);
903OperationParser::~OperationParser() {
904 for (Operation *op : forwardRefOps) {
910 for (
const auto &scope : forwardRef) {
911 for (
const auto &fwd : scope) {
914 fwd.first->dropAllUses();
922ParseResult OperationParser::finalize() {
925 if (!forwardRefPlaceholders.empty()) {
926 SmallVector<const char *, 4> errors;
928 for (
auto entry : forwardRefPlaceholders)
929 errors.push_back(entry.second.getPointer());
930 llvm::array_pod_sort(errors.begin(), errors.end());
932 for (
const char *entry : errors) {
933 auto loc = SMLoc::getFromPointer(entry);
934 emitError(loc,
"use of undeclared SSA value name");
942 auto resolveLocation = [&,
this](
auto &opOrArgument) -> LogicalResult {
943 auto fwdLoc = dyn_cast<OpaqueLoc>(opOrArgument.getLoc());
944 if (!fwdLoc || fwdLoc.getUnderlyingTypeID() != locID)
946 auto locInfo = deferredLocsReferences[fwdLoc.getUnderlyingLocation()];
947 Attribute attr = attributeAliases.lookup(locInfo.identifier);
950 <<
"operation location alias was never defined";
951 auto locAttr = dyn_cast<LocationAttr>(attr);
954 <<
"expected location, but found '" << attr <<
"'";
955 opOrArgument.setLoc(locAttr);
959 auto walkRes = topLevelOp->walk([&](Operation *op) {
963 for (
Block &block : region.getBlocks())
969 if (walkRes.wasInterrupted())
973 if (
failed(popSSANameScope()))
990void OperationParser::pushSSANameScope(
bool isIsolated) {
996 isolatedNameScopes.push_back({});
997 isolatedNameScopes.back().pushSSANameScope();
1000ParseResult OperationParser::popSSANameScope() {
1001 auto forwardRefInCurrentScope = forwardRef.pop_back_val();
1004 if (!forwardRefInCurrentScope.empty()) {
1005 SmallVector<std::pair<const char *, Block *>, 4> errors;
1007 for (
auto entry : forwardRefInCurrentScope) {
1008 errors.push_back({entry.second.getPointer(), entry.first});
1010 topLevelOp->getRegion(0).push_back(entry.first);
1012 llvm::array_pod_sort(errors.begin(), errors.end());
1014 for (
auto entry : errors) {
1015 auto loc = SMLoc::getFromPointer(entry.first);
1016 emitError(loc,
"reference to an undefined block");
1023 auto ¤tNameScope = isolatedNameScopes.back();
1024 if (currentNameScope.definitionsPerScope.size() == 1)
1025 isolatedNameScopes.pop_back();
1027 currentNameScope.popSSANameScope();
1029 blocksByName.pop_back();
1034ParseResult OperationParser::addDefinition(UnresolvedOperand useInfo,
1036 auto &entries = getSSAValueEntry(useInfo.name);
1039 if (entries.size() <= useInfo.number)
1040 entries.resize(useInfo.number + 1);
1044 if (
auto existing = entries[useInfo.number].value) {
1045 if (!isForwardRefPlaceholder(existing)) {
1047 .
append(
"redefinition of SSA value '", useInfo.name,
"'")
1048 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1049 .
append(
"previously defined here");
1052 if (existing.getType() != value.
getType()) {
1054 .
append(
"definition of SSA value '", useInfo.name,
"#",
1055 useInfo.number,
"' has type ", value.
getType())
1056 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1057 .
append(
"previously used here with type ", existing.getType());
1063 existing.replaceAllUsesWith(value);
1064 forwardRefPlaceholders.erase(existing);
1073 entries[useInfo.number] = {value, useInfo.location};
1074 recordDefinition(useInfo.name);
1083ParseResult OperationParser::parseOptionalSSAUseList(
1084 SmallVectorImpl<UnresolvedOperand> &results) {
1085 if (!getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
1088 UnresolvedOperand
result;
1091 results.push_back(
result);
1100ParseResult OperationParser::parseSSAUse(UnresolvedOperand &
result,
1101 bool allowResultNumber) {
1102 if (getToken().isCodeCompletion())
1103 return codeCompleteSSAUse();
1105 result.name = getTokenSpelling();
1107 result.location = getToken().getLoc();
1108 if (parseToken(Token::percent_identifier,
"expected SSA operand"))
1112 if (getToken().is(Token::hash_identifier)) {
1113 if (!allowResultNumber)
1114 return emitError(
"result number not allowed in argument list");
1116 if (
auto value = getToken().getHashIdentifierNumber())
1119 return emitError(
"invalid SSA value result number");
1120 consumeToken(Token::hash_identifier);
1128Value OperationParser::resolveSSAUse(UnresolvedOperand useInfo, Type type) {
1129 auto &entries = getSSAValueEntry(useInfo.name);
1133 auto maybeRecordUse = [&](Value value) {
1140 if (useInfo.number < entries.size() && entries[useInfo.number].value) {
1141 Value
result = entries[useInfo.number].value;
1143 if (
result.getType() == type)
1144 return maybeRecordUse(
result);
1146 emitError(useInfo.location,
"use of value '")
1148 "' expects different type than prior uses: ", type,
" vs ",
1150 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1151 .
append(
"prior use here");
1156 if (entries.size() <= useInfo.number)
1157 entries.resize(useInfo.number + 1);
1161 if (entries[0].value && !isForwardRefPlaceholder(entries[0].value))
1162 return (
emitError(useInfo.location,
"reference to invalid result number"),
1167 Value
result = createForwardRefPlaceholder(useInfo.location, type);
1168 entries[useInfo.number] = {
result, useInfo.location};
1169 return maybeRecordUse(
result);
1175ParseResult OperationParser::parseSSADefOrUseAndType(
1176 function_ref<ParseResult(UnresolvedOperand, Type)> action) {
1177 UnresolvedOperand useInfo;
1178 if (parseSSAUse(useInfo) ||
1179 parseToken(Token::colon,
"expected ':' and type for SSA operand"))
1186 return action(useInfo, type);
1195ParseResult OperationParser::parseOptionalSSAUseAndTypeList(
1196 SmallVectorImpl<Value> &results) {
1197 SmallVector<UnresolvedOperand, 4> valueIDs;
1198 if (parseOptionalSSAUseList(valueIDs))
1202 if (valueIDs.empty())
1205 SmallVector<Type, 4> types;
1206 if (parseToken(Token::colon,
"expected ':' in operand list") ||
1207 parseTypeListNoParens(types))
1210 if (valueIDs.size() != types.size())
1212 << valueIDs.size() <<
" types to match operand list";
1214 results.reserve(valueIDs.size());
1215 for (
unsigned i = 0, e = valueIDs.size(); i != e; ++i) {
1216 if (
auto value = resolveSSAUse(valueIDs[i], types[i]))
1217 results.push_back(value);
1226void OperationParser::recordDefinition(StringRef def) {
1227 isolatedNameScopes.back().recordDefinition(def);
1231auto OperationParser::getSSAValueEntry(StringRef name)
1232 -> SmallVectorImpl<ValueDefinition> & {
1233 return isolatedNameScopes.back().values[name];
1237Value OperationParser::createForwardRefPlaceholder(SMLoc loc, Type type) {
1244 auto name = OperationName(
"builtin.unrealized_conversion_cast",
getContext());
1246 getEncodedSourceLocation(loc), name, type, {},
1247 NamedAttrList(), PropertyRef(),
1249 forwardRefPlaceholders[op->
getResult(0)] = loc;
1250 forwardRefOps.insert(op);
1270ParseResult OperationParser::parseOperation() {
1271 auto loc = getToken().getLoc();
1272 SmallVector<ResultRecord, 1> resultIDs;
1273 size_t numExpectedResults = 0;
1274 if (getToken().is(Token::percent_identifier)) {
1276 auto parseNextResult = [&]() -> ParseResult {
1278 Token nameTok = getToken();
1279 if (parseToken(Token::percent_identifier,
1280 "expected valid ssa identifier"))
1284 size_t expectedSubResults = 1;
1285 if (consumeIf(Token::colon)) {
1287 if (!getToken().is(Token::integer))
1288 return emitWrongTokenError(
"expected integer number of results");
1291 auto val = getToken().getUInt64IntegerValue();
1292 if (!val || *val < 1)
1294 "expected named operation to have at least 1 result");
1295 consumeToken(Token::integer);
1296 expectedSubResults = *val;
1299 resultIDs.emplace_back(nameTok.
getSpelling(), expectedSubResults,
1301 numExpectedResults += expectedSubResults;
1307 if (parseToken(Token::equal,
"expected '=' after SSA name"))
1312 Token nameTok = getToken();
1313 if (nameTok.
is(Token::bare_identifier) || nameTok.
isKeyword())
1314 op = parseCustomOperation(resultIDs);
1315 else if (nameTok.
is(Token::string))
1316 op = parseGenericOperation();
1318 return codeCompleteStringDialectOrOperationName(nameTok.
getStringValue());
1320 return codeCompleteDialectOrElidedOpName(loc);
1322 return emitWrongTokenError(
"expected operation name in quotes");
1329 if (!resultIDs.empty()) {
1331 return emitError(loc,
"cannot name an operation with no results");
1333 return emitError(loc,
"operation defines ")
1335 << numExpectedResults <<
" to bind";
1339 unsigned resultIt = 0;
1340 SmallVector<std::pair<unsigned, SMLoc>> asmResultGroups;
1341 asmResultGroups.reserve(resultIDs.size());
1342 for (ResultRecord &record : resultIDs) {
1343 asmResultGroups.emplace_back(resultIt, std::get<2>(record));
1344 resultIt += std::get<1>(record);
1347 op, nameTok.
getLocRange(), getLastToken().getEndLoc(),
1352 unsigned opResI = 0;
1353 for (ResultRecord &resIt : resultIDs) {
1354 for (
unsigned subRes : llvm::seq<unsigned>(0, std::get<1>(resIt))) {
1355 if (addDefinition({std::get<2>(resIt), std::get<0>(resIt), subRes},
1365 getLastToken().getEndLoc());
1375ParseResult OperationParser::parseSuccessor(
Block *&dest) {
1376 if (getToken().isCodeCompletion())
1377 return codeCompleteBlock();
1380 if (!getToken().is(Token::caret_identifier))
1381 return emitWrongTokenError(
"expected block name");
1382 dest = getBlockNamed(getTokenSpelling(), getToken().getLoc());
1392OperationParser::parseSuccessors(SmallVectorImpl<Block *> &destinations) {
1393 if (parseToken(Token::l_square,
"expected '['"))
1396 auto parseElt = [
this, &destinations] {
1398 ParseResult res = parseSuccessor(dest);
1399 destinations.push_back(dest);
1402 return parseCommaSeparatedListUntil(Token::r_square, parseElt,
1411struct CleanupOpStateRegions {
1412 ~CleanupOpStateRegions() {
1413 SmallVector<Region *, 4> regionsToClean;
1414 regionsToClean.reserve(state.regions.size());
1415 for (
auto ®ion : state.regions)
1417 for (
auto &block : *region)
1420 OperationState &state;
1424ParseResult OperationParser::parseGenericOperationAfterOpName(
1426 std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo,
1427 std::optional<ArrayRef<Block *>> parsedSuccessors,
1428 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1429 std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1430 std::optional<Attribute> propertiesAttribute,
1431 std::optional<FunctionType> parsedFnType) {
1434 SmallVector<UnresolvedOperand, 8> opInfo;
1435 if (!parsedOperandUseInfo) {
1436 if (parseToken(Token::l_paren,
"expected '(' to start operand list") ||
1437 parseOptionalSSAUseList(opInfo) ||
1438 parseToken(Token::r_paren,
"expected ')' to end operand list")) {
1441 parsedOperandUseInfo = opInfo;
1445 if (!parsedSuccessors) {
1446 if (getToken().is(Token::l_square)) {
1448 if (!
result.name.mightHaveTrait<OpTrait::IsTerminator>())
1449 return emitError(
"successors in non-terminator");
1451 SmallVector<Block *, 2> successors;
1452 if (parseSuccessors(successors))
1454 result.addSuccessors(successors);
1457 result.addSuccessors(*parsedSuccessors);
1461 if (propertiesAttribute) {
1462 result.propertiesAttr = *propertiesAttribute;
1463 }
else if (consumeIf(Token::less)) {
1465 if (!
result.propertiesAttr)
1467 if (parseToken(Token::greater,
"expected '>' to close properties"))
1471 if (!parsedRegions) {
1472 if (consumeIf(Token::l_paren)) {
1475 result.regions.emplace_back(
new Region(topLevelOp));
1476 if (parseRegion(*
result.regions.back(), {}))
1478 }
while (consumeIf(Token::comma));
1479 if (parseToken(Token::r_paren,
"expected ')' to end region list"))
1483 result.addRegions(*parsedRegions);
1487 if (!parsedAttributes) {
1488 if (getToken().is(Token::l_brace)) {
1489 if (parseAttributeDict(
result.attributes))
1493 result.addAttributes(*parsedAttributes);
1497 Location typeLoc =
result.location;
1498 if (!parsedFnType) {
1499 if (parseToken(Token::colon,
"expected ':' followed by operation type"))
1502 typeLoc = getEncodedSourceLocation(getToken().getLoc());
1506 auto fnType = dyn_cast<FunctionType>(type);
1510 parsedFnType = fnType;
1513 result.addTypes(parsedFnType->getResults());
1516 ArrayRef<Type> operandTypes = parsedFnType->getInputs();
1517 if (operandTypes.size() != parsedOperandUseInfo->size()) {
1518 auto plural =
"s"[parsedOperandUseInfo->size() == 1];
1520 << parsedOperandUseInfo->size() <<
" operand type" << plural
1521 <<
" but had " << operandTypes.size();
1525 for (
unsigned i = 0, e = parsedOperandUseInfo->size(); i != e; ++i) {
1526 result.operands.push_back(
1527 resolveSSAUse((*parsedOperandUseInfo)[i], operandTypes[i]));
1528 if (!
result.operands.back())
1535Operation *OperationParser::parseGenericOperation() {
1537 auto srcLocation = getEncodedSourceLocation(getToken().getLoc());
1539 std::string name = getToken().getStringValue();
1541 return (
emitError(
"empty operation name is invalid"),
nullptr);
1542 if (name.find(
'\0') != StringRef::npos)
1543 return (
emitError(
"null character not allowed in operation name"),
nullptr);
1545 consumeToken(Token::string);
1547 OperationState
result(srcLocation, name);
1548 CleanupOpStateRegions guard{
result};
1551 if (!
result.name.isRegistered()) {
1552 StringRef dialectName = StringRef(name).split(
'.').first;
1553 if (!
getContext()->getLoadedDialect(dialectName) &&
1554 !
getContext()->getOrLoadDialect(dialectName)) {
1555 if (!
getContext()->allowsUnregisteredDialects()) {
1558 emitError(
"operation being parsed with an unregistered dialect. If "
1559 "this is intended, please use -allow-unregistered-dialect "
1560 "with the MLIR tool used");
1573 if (parseGenericOperationAfterOpName(
result))
1579 Attribute properties;
1580 std::swap(properties,
result.propertiesAttr);
1596 if (!properties && !
result.getRawProperties()) {
1597 std::optional<RegisteredOperationName> info =
1598 result.name.getRegisteredInfo();
1600 if (
failed(info->verifyInherentAttrs(
result.attributes, [&]() {
1601 return mlir::emitError(srcLocation) <<
"'" << name <<
"' op ";
1609 if (parseTrailingLocationSpecifier(op))
1617 << properties <<
" for op " << name <<
": ";
1626Operation *OperationParser::parseGenericOperation(
Block *insertBlock,
1628 Token nameToken = getToken();
1630 OpBuilder::InsertionGuard restoreInsertionPoint(opBuilder);
1631 opBuilder.setInsertionPoint(insertBlock, insertPt);
1632 Operation *op = parseGenericOperation();
1641 getLastToken().getEndLoc());
1646class CustomOpAsmParser :
public AsmParserImpl<OpAsmParser> {
1649 SMLoc nameLoc, ArrayRef<OperationParser::ResultRecord> resultIDs,
1650 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly,
1651 bool isIsolatedFromAbove, StringRef opName, OperationParser &parser)
1652 : AsmParserImpl<OpAsmParser>(nameLoc, parser), resultIDs(resultIDs),
1653 parseAssembly(parseAssembly), isIsolatedFromAbove(isIsolatedFromAbove),
1654 opName(opName), parser(parser) {
1655 (void)isIsolatedFromAbove;
1660 ParseResult parseOperation(OperationState &opState) {
1661 if (parseAssembly(*
this, opState))
1667 std::optional<NamedAttribute> duplicate =
1670 return emitError(getNameLoc(),
"attribute '")
1671 << duplicate->getName().getValue()
1672 <<
"' occurs more than once in the attribute list";
1676 Operation *parseGenericOperation(
Block *insertBlock,
1678 return parser.parseGenericOperation(insertBlock, insertPt);
1681 FailureOr<OperationName> parseCustomOperationName() final {
1682 return parser.parseCustomOperationName();
1685 ParseResult parseGenericOperationAfterOpName(
1687 std::optional<ArrayRef<UnresolvedOperand>> parsedUnresolvedOperands,
1688 std::optional<ArrayRef<Block *>> parsedSuccessors,
1689 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1690 std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1691 std::optional<Attribute> parsedPropertiesAttribute,
1692 std::optional<FunctionType> parsedFnType)
final {
1693 return parser.parseGenericOperationAfterOpName(
1694 result, parsedUnresolvedOperands, parsedSuccessors, parsedRegions,
1695 parsedAttributes, parsedPropertiesAttribute, parsedFnType);
1710 std::pair<StringRef, unsigned>
1711 getResultName(
unsigned resultNo)
const override {
1713 for (
const auto &entry : resultIDs) {
1714 if (resultNo < std::get<1>(entry)) {
1716 StringRef name = std::get<0>(entry).drop_front();
1717 return {name, resultNo};
1719 resultNo -= std::get<1>(entry);
1728 size_t getNumResults()
const override {
1730 for (
auto &entry : resultIDs)
1731 count += std::get<1>(entry);
1736 InFlightDiagnostic
emitError(SMLoc loc,
const Twine &message)
override {
1746 ParseResult parseOperand(UnresolvedOperand &
result,
1747 bool allowResultNumber =
true)
override {
1748 OperationParser::UnresolvedOperand useInfo;
1749 if (parser.parseSSAUse(useInfo, allowResultNumber))
1758 parseOptionalOperand(UnresolvedOperand &
result,
1759 bool allowResultNumber =
true)
override {
1760 if (parser.getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
1761 return parseOperand(
result, allowResultNumber);
1762 return std::nullopt;
1767 ParseResult parseOperandList(SmallVectorImpl<UnresolvedOperand> &
result,
1768 Delimiter delimiter = Delimiter::None,
1769 bool allowResultNumber =
true,
1770 int requiredOperandCount = -1)
override {
1772 if (delimiter == Delimiter::None) {
1775 Token tok = parser.getToken();
1779 if (requiredOperandCount == -1 || requiredOperandCount == 0)
1783 if (tok.
isAny(Token::l_paren, Token::l_square))
1784 return parser.emitError(
"unexpected delimiter");
1785 return parser.emitWrongTokenError(
"expected operand");
1789 auto parseOneOperand = [&]() -> ParseResult {
1790 return parseOperand(
result.emplace_back(), allowResultNumber);
1793 auto startLoc = parser.getToken().getLoc();
1798 if (requiredOperandCount != -1 &&
1799 result.size() !=
static_cast<size_t>(requiredOperandCount))
1801 << requiredOperandCount <<
" operands";
1806 ParseResult resolveOperand(
const UnresolvedOperand &operand, Type type,
1807 SmallVectorImpl<Value> &
result)
override {
1808 if (
auto value = parser.resolveSSAUse(operand, type)) {
1817 parseAffineMapOfSSAIds(SmallVectorImpl<UnresolvedOperand> &operands,
1818 Attribute &mapAttr, StringRef attrName,
1819 NamedAttrList &attrs, Delimiter delimiter)
override {
1820 SmallVector<UnresolvedOperand, 2> dimOperands;
1821 SmallVector<UnresolvedOperand, 1> symOperands;
1823 auto parseElement = [&]() -> FailureOr<UnresolvedOperand> {
1824 UnresolvedOperand operand;
1825 if (parseOperand(operand))
1829 auto addOperand = [&](
bool isSymbol, UnresolvedOperand operand) {
1831 symOperands.push_back(operand);
1833 dimOperands.push_back(operand);
1837 if (parser.parseAffineMapOfSSAIds(map, parseElement, addOperand, delimiter))
1841 mapAttr = AffineMapAttr::get(map);
1842 attrs.
push_back(parser.builder.getNamedAttr(attrName, mapAttr));
1846 operands.assign(dimOperands.begin(), dimOperands.end());
1847 operands.append(symOperands.begin(), symOperands.end());
1853 parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands,
1854 SmallVectorImpl<UnresolvedOperand> &symOperands,
1855 AffineExpr &expr)
override {
1856 auto parseElement = [&]() -> FailureOr<UnresolvedOperand> {
1857 UnresolvedOperand operand;
1858 if (parseOperand(operand))
1862 auto addOperand = [&](
bool isSymbol, UnresolvedOperand operand) {
1864 symOperands.push_back(operand);
1866 dimOperands.push_back(operand);
1869 return parser.parseAffineExprOfSSAIds(expr, parseElement, addOperand);
1882 ParseResult parseArgument(Argument &
result,
bool allowType =
false,
1883 bool allowAttrs =
false)
override {
1884 NamedAttrList attrs;
1885 if (parseOperand(
result.ssaName,
false) ||
1886 (allowType && parseColonType(
result.type)) ||
1887 (allowAttrs && parseOptionalAttrDict(attrs)) ||
1888 parseOptionalLocationSpecifier(
result.sourceLoc))
1895 OptionalParseResult parseOptionalArgument(Argument &
result,
bool allowType,
1896 bool allowAttrs)
override {
1897 if (parser.getToken().is(Token::percent_identifier))
1898 return parseArgument(
result, allowType, allowAttrs);
1899 return std::nullopt;
1902 ParseResult parseArgumentList(SmallVectorImpl<Argument> &
result,
1903 Delimiter delimiter,
bool allowType,
1904 bool allowAttrs)
override {
1906 if (delimiter == Delimiter::None &&
1907 parser.getToken().isNot(Token::percent_identifier))
1910 auto parseOneArgument = [&]() -> ParseResult {
1911 return parseArgument(
result.emplace_back(), allowType, allowAttrs);
1914 " in argument list");
1923 ParseResult parseRegion(Region ®ion, ArrayRef<Argument> arguments,
1924 bool enableNameShadowing)
override {
1926 (void)isIsolatedFromAbove;
1927 assert((!enableNameShadowing || isIsolatedFromAbove) &&
1928 "name shadowing is only allowed on isolated regions");
1929 if (parser.parseRegion(region, arguments, enableNameShadowing))
1935 OptionalParseResult parseOptionalRegion(Region ®ion,
1936 ArrayRef<Argument> arguments,
1937 bool enableNameShadowing)
override {
1938 if (parser.getToken().isNot(Token::l_brace))
1939 return std::nullopt;
1940 return parseRegion(region, arguments, enableNameShadowing);
1947 parseOptionalRegion(std::unique_ptr<Region> ®ion,
1948 ArrayRef<Argument> arguments,
1949 bool enableNameShadowing =
false)
override {
1950 if (parser.getToken().isNot(Token::l_brace))
1951 return std::nullopt;
1952 std::unique_ptr<Region> newRegion = std::make_unique<Region>();
1953 if (parseRegion(*newRegion, arguments, enableNameShadowing))
1956 region = std::move(newRegion);
1965 ParseResult parseSuccessor(
Block *&dest)
override {
1966 return parser.parseSuccessor(dest);
1970 OptionalParseResult parseOptionalSuccessor(
Block *&dest)
override {
1971 if (!parser.getToken().isOrIsCodeCompletionFor(Token::caret_identifier))
1972 return std::nullopt;
1973 return parseSuccessor(dest);
1978 parseSuccessorAndUseList(
Block *&dest,
1979 SmallVectorImpl<Value> &operands)
override {
1980 if (parseSuccessor(dest))
1984 if (succeeded(parseOptionalLParen()) &&
1985 (parser.parseOptionalSSAUseAndTypeList(operands) || parseRParen())) {
1997 OptionalParseResult parseOptionalAssignmentList(
1998 SmallVectorImpl<Argument> &
lhs,
1999 SmallVectorImpl<UnresolvedOperand> &
rhs)
override {
2000 if (
failed(parseOptionalLParen()))
2001 return std::nullopt;
2003 auto parseElt = [&]() -> ParseResult {
2004 if (parseArgument(
lhs.emplace_back()) || parseEqual() ||
2005 parseOperand(
rhs.emplace_back()))
2009 return parser.parseCommaSeparatedListUntil(Token::r_paren, parseElt);
2014 parseOptionalLocationSpecifier(std::optional<Location> &
result)
override {
2016 if (!parser.consumeIf(Token::kw_loc))
2018 LocationAttr directLoc;
2019 if (parser.parseToken(Token::l_paren,
"expected '(' in location"))
2022 Token tok = parser.getToken();
2028 if (tok.
is(Token::hash_identifier) && !tok.
getSpelling().contains(
'.')) {
2029 if (parser.parseLocationAlias(directLoc))
2031 }
else if (parser.parseLocationInstance(directLoc)) {
2035 if (parser.parseToken(Token::r_paren,
"expected ')' in location"))
2044 ArrayRef<OperationParser::ResultRecord> resultIDs;
2047 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly;
2048 bool isIsolatedFromAbove;
2052 OperationParser &parser;
2056FailureOr<OperationName> OperationParser::parseCustomOperationName() {
2057 Token nameTok = getToken();
2062 return emitError(
"expected bare identifier or keyword");
2065 return (
emitError(
"empty operation name is invalid"), failure());
2069 std::optional<RegisteredOperationName> opInfo =
2076 auto opNameSplit = opName.split(
'.');
2077 StringRef dialectName = opNameSplit.first;
2078 std::string opNameStorage;
2079 if (opNameSplit.second.empty()) {
2081 if (getToken().isCodeCompletion() && opName.back() ==
'.')
2082 return codeCompleteOperationName(dialectName);
2084 dialectName = getState().defaultDialectStack.back();
2085 opNameStorage = (dialectName +
"." + opName).str();
2086 opName = opNameStorage;
2096OperationParser::parseCustomOperation(ArrayRef<ResultRecord> resultIDs) {
2097 SMLoc opLoc = getToken().getLoc();
2098 StringRef originalOpName = getTokenSpelling();
2100 FailureOr<OperationName> opNameInfo = parseCustomOperationName();
2103 StringRef opName = opNameInfo->getStringRef();
2109 bool isIsolatedFromAbove =
false;
2111 StringRef defaultDialect =
"";
2112 if (
auto opInfo = opNameInfo->getRegisteredInfo()) {
2113 parseAssemblyFn = opInfo->getParseAssemblyFn();
2114 isIsolatedFromAbove = opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>();
2115 auto *iface = opInfo->getInterface<OpAsmOpInterface>();
2116 if (iface && !iface->getDefaultDialect().empty())
2117 defaultDialect = iface->getDefaultDialect();
2119 std::optional<Dialect::ParseOpHook> dialectHook;
2120 Dialect *dialect = opNameInfo->getDialect();
2122 InFlightDiagnostic
diag =
2123 emitError(opLoc) <<
"Dialect `" << opNameInfo->getDialectNamespace()
2124 <<
"' not found for custom op '" << originalOpName
2126 if (originalOpName != opName)
2127 diag <<
" (tried '" << opName <<
"' as well)";
2128 auto ¬e =
diag.attachNote();
2129 note <<
"Available dialects: ";
2130 std::vector<StringRef> registered =
getContext()->getAvailableDialects();
2131 auto loaded =
getContext()->getLoadedDialects();
2134 SmallVector<std::pair<StringRef, bool>> mergedDialects;
2135 auto regIt = registered.begin(), regEnd = registered.end();
2136 auto loadIt = loaded.rbegin(), loadEnd = loaded.rend();
2137 bool isRegistered =
false;
2138 bool isOnlyLoaded =
true;
2139 while (regIt != regEnd && loadIt != loadEnd) {
2140 StringRef reg = *regIt;
2141 StringRef
load = (*loadIt)->getNamespace();
2143 mergedDialects.emplace_back(
load, isOnlyLoaded);
2146 mergedDialects.emplace_back(reg, isRegistered);
2152 for (; regIt != regEnd; ++regIt)
2153 mergedDialects.emplace_back(*regIt, isRegistered);
2154 for (; loadIt != loadEnd; ++loadIt)
2155 mergedDialects.emplace_back((*loadIt)->getNamespace(), isOnlyLoaded);
2157 bool loadedUnregistered =
false;
2158 llvm::interleaveComma(mergedDialects, note, [&](
auto &pair) {
2161 loadedUnregistered =
true;
2166 if (loadedUnregistered)
2167 note <<
"(* corresponding to loaded but unregistered dialects)";
2168 note <<
"; for more info on dialect registration see "
2169 "https://mlir.llvm.org/getting_started/Faq/"
2170 "#registered-loaded-dependent-whats-up-with-dialects-management";
2175 InFlightDiagnostic
diag =
2176 emitError(opLoc) <<
"custom op '" << originalOpName <<
"' is unknown";
2177 if (originalOpName != opName)
2178 diag <<
" (tried '" << opName <<
"' as well)";
2181 parseAssemblyFn = *dialectHook;
2183 getState().defaultDialectStack.push_back(defaultDialect);
2184 llvm::scope_exit restoreDefaultDialect(
2185 [&]() { getState().defaultDialectStack.pop_back(); });
2189 llvm::PrettyStackTraceFormat fmt(
"MLIR Parser: custom op parser '%s'",
2190 opNameInfo->getIdentifier().data());
2193 auto srcLocation = getEncodedSourceLocation(opLoc);
2194 OperationState opState(srcLocation, *opNameInfo);
2201 CleanupOpStateRegions guard{opState};
2202 CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn,
2203 isIsolatedFromAbove, opName, *
this);
2204 if (opAsmParser.parseOperation(opState))
2208 if (opAsmParser.didEmitError())
2215 Operation *op = opBuilder.
create(opState);
2216 if (parseTrailingLocationSpecifier(op))
2232ParseResult OperationParser::parseLocationAlias(LocationAttr &loc) {
2233 Token tok = getToken();
2234 consumeToken(Token::hash_identifier);
2235 StringRef identifier = tok.
getSpelling().drop_front();
2236 assert(!identifier.contains(
'.') &&
2237 "unexpected dialect attribute token, expected alias");
2245 if (!(loc = dyn_cast<LocationAttr>(attr)))
2247 <<
"expected location, but found '" << attr <<
"'";
2251 loc = OpaqueLoc::get(deferredLocsReferences.size(),
2254 deferredLocsReferences.push_back(DeferredLocInfo{tok.
getLoc(), identifier});
2260OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) {
2262 if (!consumeIf(Token::kw_loc))
2264 if (parseToken(Token::l_paren,
"expected '(' in location"))
2266 Token tok = getToken();
2271 LocationAttr directLoc;
2272 if (tok.
is(Token::hash_identifier) && !tok.
getSpelling().contains(
'.')) {
2273 if (parseLocationAlias(directLoc))
2275 }
else if (parseLocationInstance(directLoc)) {
2279 if (parseToken(Token::r_paren,
"expected ')' in location"))
2282 if (
auto *op = llvm::dyn_cast_if_present<Operation *>(opOrArgument))
2285 cast<BlockArgument>(opOrArgument).setLoc(directLoc);
2293ParseResult OperationParser::parseRegion(Region ®ion,
2294 ArrayRef<Argument> entryArguments,
2295 bool isIsolatedNameScope) {
2297 Token lBraceTok = getToken();
2298 if (parseToken(Token::l_brace,
"expected '{' to begin a region"))
2306 if ((!entryArguments.empty() || getToken().isNot(Token::r_brace)) &&
2307 parseRegionBody(region, lBraceTok.
getLoc(), entryArguments,
2308 isIsolatedNameScope)) {
2311 consumeToken(Token::r_brace);
2320ParseResult OperationParser::parseRegionBody(Region ®ion, SMLoc startLoc,
2321 ArrayRef<Argument> entryArguments,
2322 bool isIsolatedNameScope) {
2323 auto currentPt = opBuilder.saveInsertionPoint();
2326 pushSSANameScope(isIsolatedNameScope);
2329 auto owningBlock = std::make_unique<Block>();
2330 llvm::scope_exit failureCleanup([&] {
2335 owningBlock->dropAllDefinedValueUses();
2338 Block *block = owningBlock.get();
2343 if (state.
asmState && getToken().isNot(Token::caret_identifier))
2347 if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) {
2349 if (getToken().is(Token::caret_identifier))
2350 return emitError(
"invalid block name in region with named arguments");
2352 for (
auto &entryArg : entryArguments) {
2353 auto &argInfo = entryArg.ssaName;
2356 if (
auto defLoc = getReferenceLoc(argInfo.name, argInfo.number)) {
2357 return emitError(argInfo.location,
"region entry argument '" +
2359 "' is already in use")
2360 .
attachNote(getEncodedSourceLocation(*defLoc))
2361 <<
"previously referenced here";
2363 Location loc = entryArg.sourceLoc.has_value()
2364 ? *entryArg.sourceLoc
2365 : getEncodedSourceLocation(argInfo.location);
2366 BlockArgument arg = block->addArgument(entryArg.type, loc);
2373 if (addDefinition(argInfo, arg))
2378 if (parseBlock(block))
2382 if (!entryArguments.empty() &&
2383 block->getNumArguments() > entryArguments.size()) {
2384 return emitError(
"entry block arguments were already defined");
2388 region.
push_back(owningBlock.release());
2389 while (getToken().isNot(Token::r_brace)) {
2390 Block *newBlock =
nullptr;
2391 if (parseBlock(newBlock))
2397 if (popSSANameScope())
2401 opBuilder.restoreInsertionPoint(currentPt);
2416ParseResult OperationParser::parseBlock(
Block *&block) {
2419 if (block && getToken().isNot(Token::caret_identifier))
2420 return parseBlockBody(block);
2422 SMLoc nameLoc = getToken().getLoc();
2423 auto name = getTokenSpelling();
2424 if (parseToken(Token::caret_identifier,
"expected block name"))
2428 auto &blockAndLoc = getBlockInfoByName(name);
2429 blockAndLoc.loc = nameLoc;
2434 std::unique_ptr<Block> inflightBlock;
2435 llvm::scope_exit cleanupOnFailure([&] {
2437 inflightBlock->dropAllDefinedValueUses();
2442 if (!blockAndLoc.block) {
2444 blockAndLoc.block = block;
2446 inflightBlock = std::make_unique<Block>();
2447 blockAndLoc.block = inflightBlock.get();
2454 }
else if (!eraseForwardRef(blockAndLoc.block)) {
2455 return emitError(nameLoc,
"redefinition of block '") << name <<
"'";
2459 inflightBlock.reset(blockAndLoc.block);
2465 block = blockAndLoc.block;
2468 if (getToken().is(Token::l_paren))
2469 if (parseOptionalBlockArgList(block))
2471 if (parseToken(Token::colon,
"expected ':' after block name"))
2475 ParseResult res = parseBlockBody(block);
2480 (void)inflightBlock.release();
2484ParseResult OperationParser::parseBlockBody(
Block *block) {
2486 opBuilder.setInsertionPointToEnd(block);
2489 while (getToken().isNot(Token::caret_identifier, Token::r_brace))
2490 if (parseOperation())
2499Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
2500 BlockDefinition &blockDef = getBlockInfoByName(name);
2501 if (!blockDef.block) {
2502 blockDef = {
new Block(), loc};
2503 insertForwardRef(blockDef.block, blockDef.loc);
2510 return blockDef.block;
2519ParseResult OperationParser::parseOptionalBlockArgList(
Block *owner) {
2520 if (getToken().is(Token::r_brace))
2526 unsigned nextArgument = 0;
2529 return parseSSADefOrUseAndType(
2530 [&](UnresolvedOperand useInfo, Type type) -> ParseResult {
2535 if (definingExistingArgs) {
2538 return emitError(
"too many arguments specified in argument list");
2543 return emitError(
"argument and block argument type mismatch");
2545 auto loc = getEncodedSourceLocation(useInfo.location);
2551 if (parseTrailingLocationSpecifier(arg))
2559 return addDefinition(useInfo, arg);
2568ParseResult OperationParser::codeCompleteSSAUse() {
2569 for (IsolatedSSANameScope &scope : isolatedNameScopes) {
2571 SmallVector<StringRef> sortedNames;
2572 for (
auto &it : scope.values)
2573 if (!it.second.empty())
2574 sortedNames.push_back(it.getKey());
2575 llvm::sort(sortedNames);
2577 for (StringRef name : sortedNames) {
2578 Value frontValue = scope.values[name].front().value;
2580 std::string detailData;
2581 llvm::raw_string_ostream detailOS(detailData);
2585 if (
auto result = dyn_cast<OpResult>(frontValue)) {
2586 if (!forwardRefPlaceholders.count(
result))
2587 detailOS <<
result.getOwner()->getName() <<
": ";
2589 detailOS <<
"arg #" << cast<BlockArgument>(frontValue).getArgNumber()
2594 detailOS << frontValue.
getType();
2599 if (scope.values[name].size() > 1)
2600 detailOS <<
", ...";
2603 name, std::move(detailData));
2610ParseResult OperationParser::codeCompleteBlock() {
2613 StringRef spelling = getTokenSpelling();
2614 if (!(spelling.empty() || spelling ==
"^"))
2617 for (
const auto &it : blocksByName.back())
2629class TopLevelOperationParser :
public Parser {
2631 explicit TopLevelOperationParser(ParserState &state) : Parser(state) {}
2634 ParseResult
parse(
Block *topLevelBlock, Location parserLoc);
2641 ParseResult parseAttributeAliasDef();
2647 ParseResult parseTypeAliasDef();
2653 ParseResult parseFileMetadataDictionary();
2656 ParseResult parseResourceFileMetadata(
2657 function_ref<ParseResult(StringRef, SMLoc)> parseBody);
2658 ParseResult parseDialectResourceFileMetadata();
2659 ParseResult parseExternalResourceFileMetadata();
2664class ParsedResourceEntry :
public AsmParsedResourceEntry {
2666 ParsedResourceEntry(std::string key, SMLoc keyLoc, Token value, Parser &p)
2667 : key(std::move(key)), keyLoc(keyLoc), value(value), p(p) {}
2668 ~ParsedResourceEntry()
override =
default;
2670 StringRef getKey() const final {
return key; }
2672 InFlightDiagnostic
emitError() const final {
return p.emitError(keyLoc); }
2675 if (value.isAny(Token::kw_true, Token::kw_false))
2676 return AsmResourceEntryKind::Bool;
2677 return value.getSpelling().starts_with(
"\"0x")
2678 ? AsmResourceEntryKind::Blob
2679 : AsmResourceEntryKind::String;
2682 FailureOr<bool> parseAsBool() const final {
2683 if (value.is(Token::kw_true))
2685 if (value.is(Token::kw_false))
2687 return p.emitError(value.getLoc(),
2688 "expected 'true' or 'false' value for key '" + key +
2692 FailureOr<std::string> parseAsString() const final {
2693 if (value.isNot(Token::string))
2694 return p.emitError(value.getLoc(),
2695 "expected string value for key '" + key +
"'");
2696 return value.getStringValue();
2699 FailureOr<AsmResourceBlob>
2700 parseAsBlob(BlobAllocatorFn allocator)
const final {
2704 std::optional<std::string> blobData =
2705 value.is(Token::string) ? value.getHexStringValue() : std::nullopt;
2707 return p.emitError(value.getLoc(),
2708 "expected hex string blob for key '" + key +
"'");
2712 if (blobData->size() <
sizeof(uint32_t)) {
2713 return p.emitError(value.getLoc(),
2714 "expected hex string blob for key '" + key +
2715 "' to encode alignment in first 4 bytes");
2717 llvm::support::ulittle32_t align;
2718 memcpy(&align, blobData->data(),
sizeof(uint32_t));
2719 if (align && !llvm::isPowerOf2_32(align)) {
2720 return p.emitError(value.getLoc(),
2721 "expected hex string blob for key '" + key +
2722 "' to encode alignment in first 4 bytes, but got "
2723 "non-power-of-2 value: " +
2728 StringRef data = StringRef(*blobData).drop_front(
sizeof(uint32_t));
2730 return AsmResourceBlob();
2734 AsmResourceBlob blob = allocator(data.size(), align);
2735 assert(llvm::isAddrAligned(llvm::Align(align), blob.
getData().data()) &&
2737 "blob allocator did not return a properly aligned address");
2750ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
2751 assert(getToken().is(Token::hash_identifier));
2752 StringRef aliasName = getTokenSpelling().drop_front();
2756 return emitError(
"redefinition of attribute alias id '" + aliasName +
"'");
2759 if (aliasName.contains(
'.'))
2760 return emitError(
"attribute names with a '.' are reserved for "
2761 "dialect-defined names");
2763 SMRange location = getToken().getLocRange();
2764 consumeToken(Token::hash_identifier);
2767 if (parseToken(Token::equal,
"expected '=' in attribute alias definition"))
2782ParseResult TopLevelOperationParser::parseTypeAliasDef() {
2783 assert(getToken().is(Token::exclamation_identifier));
2784 StringRef aliasName = getTokenSpelling().drop_front();
2788 return emitError(
"redefinition of type alias id '" + aliasName +
"'");
2791 if (aliasName.contains(
'.'))
2792 return emitError(
"type names with a '.' are reserved for "
2793 "dialect-defined names");
2795 SMRange location = getToken().getLocRange();
2796 consumeToken(Token::exclamation_identifier);
2799 if (parseToken(Token::equal,
"expected '=' in type alias definition"))
2814ParseResult TopLevelOperationParser::parseFileMetadataDictionary() {
2815 consumeToken(Token::file_metadata_begin);
2816 return parseCommaSeparatedListUntil(
2817 Token::file_metadata_end, [&]() -> ParseResult {
2819 SMLoc keyLoc = getToken().getLoc();
2821 if (
failed(parseOptionalKeyword(&key)))
2822 return emitError(
"expected identifier key in file "
2823 "metadata dictionary");
2824 if (parseToken(Token::colon,
"expected ':'"))
2828 if (key ==
"dialect_resources")
2829 return parseDialectResourceFileMetadata();
2830 if (key ==
"external_resources")
2831 return parseExternalResourceFileMetadata();
2832 return emitError(keyLoc,
"unknown key '" + key +
2833 "' in file metadata dictionary");
2837ParseResult TopLevelOperationParser::parseResourceFileMetadata(
2838 function_ref<ParseResult(StringRef, SMLoc)> parseBody) {
2839 if (parseToken(Token::l_brace,
"expected '{'"))
2842 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2844 SMLoc nameLoc = getToken().getLoc();
2846 if (
failed(parseOptionalKeyword(&name)))
2847 return emitError(
"expected identifier key for 'resource' entry");
2849 if (parseToken(Token::colon,
"expected ':'") ||
2850 parseToken(Token::l_brace,
"expected '{'"))
2852 return parseBody(name, nameLoc);
2856ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() {
2857 return parseResourceFileMetadata([&](StringRef name,
2858 SMLoc nameLoc) -> ParseResult {
2860 Dialect *dialect =
getContext()->getOrLoadDialect(name);
2862 return emitError(nameLoc,
"dialect '" + name +
"' is unknown");
2863 const auto *handler = dyn_cast<OpAsmDialectInterface>(dialect);
2865 return emitError() <<
"unexpected 'resource' section for dialect '"
2869 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2871 SMLoc keyLoc = getToken().getLoc();
2873 if (
failed(parseResourceHandle(handler, key)) ||
2874 parseToken(Token::colon,
"expected ':'"))
2876 Token valueTok = getToken();
2879 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2880 return handler->parseResource(entry);
2885ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() {
2886 return parseResourceFileMetadata([&](StringRef name,
2887 SMLoc nameLoc) -> ParseResult {
2893 <<
"ignoring unknown external resources for '" << name <<
"'";
2896 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2898 SMLoc keyLoc = getToken().getLoc();
2900 if (
failed(parseOptionalKeywordOrString(&key)))
2902 "expected identifier key for 'external_resources' entry");
2903 if (parseToken(Token::colon,
"expected ':'"))
2905 Token valueTok = getToken();
2910 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2916ParseResult TopLevelOperationParser::parse(
Block *topLevelBlock,
2917 Location parserLoc) {
2919 OwningOpRef<ModuleOp> topLevelOp(ModuleOp::create(parserLoc));
2920 OperationParser opParser(state, topLevelOp.get());
2922 switch (getToken().getKind()) {
2925 if (opParser.parseOperation())
2931 if (opParser.finalize())
2936 auto &parsedOps = topLevelOp->getBody()->getOperations();
2938 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(),
2950 case Token::hash_identifier:
2951 if (parseAttributeAliasDef())
2956 case Token::exclamation_identifier:
2957 if (parseTypeAliasDef())
2962 case Token::file_metadata_begin:
2963 if (parseFileMetadataDictionary())
2976 const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
2983 ParserState state(sourceMgr, config, aliasState, asmState,
2984 codeCompleteContext);
2985 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.
static std::string diag(const llvm::Value &value)
#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 ...
std::optional< double > getFloatingPointValue() const
For a floatliteral token, return its value as a double.
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.