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) {
960 if (
failed(resolveLocation(*op)))
963 for (
Block &block : region.getBlocks())
965 if (
failed(resolveLocation(arg)))
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 = [&](
bool isSymbol) -> ParseResult {
1824 UnresolvedOperand operand;
1825 if (parseOperand(operand))
1828 symOperands.push_back(operand);
1830 dimOperands.push_back(operand);
1835 if (parser.parseAffineMapOfSSAIds(map, parseElement, delimiter))
1839 mapAttr = AffineMapAttr::get(map);
1840 attrs.
push_back(parser.builder.getNamedAttr(attrName, mapAttr));
1844 operands.assign(dimOperands.begin(), dimOperands.end());
1845 operands.append(symOperands.begin(), symOperands.end());
1851 parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands,
1852 SmallVectorImpl<UnresolvedOperand> &symbOperands,
1853 AffineExpr &expr)
override {
1854 auto parseElement = [&](
bool isSymbol) -> ParseResult {
1855 UnresolvedOperand operand;
1856 if (parseOperand(operand))
1859 symbOperands.push_back(operand);
1861 dimOperands.push_back(operand);
1865 return parser.parseAffineExprOfSSAIds(expr, parseElement);
1878 ParseResult parseArgument(Argument &
result,
bool allowType =
false,
1879 bool allowAttrs =
false)
override {
1880 NamedAttrList attrs;
1881 if (parseOperand(
result.ssaName,
false) ||
1882 (allowType && parseColonType(
result.type)) ||
1883 (allowAttrs && parseOptionalAttrDict(attrs)) ||
1884 parseOptionalLocationSpecifier(
result.sourceLoc))
1891 OptionalParseResult parseOptionalArgument(Argument &
result,
bool allowType,
1892 bool allowAttrs)
override {
1893 if (parser.getToken().is(Token::percent_identifier))
1894 return parseArgument(
result, allowType, allowAttrs);
1895 return std::nullopt;
1898 ParseResult parseArgumentList(SmallVectorImpl<Argument> &
result,
1899 Delimiter delimiter,
bool allowType,
1900 bool allowAttrs)
override {
1902 if (delimiter == Delimiter::None &&
1903 parser.getToken().isNot(Token::percent_identifier))
1906 auto parseOneArgument = [&]() -> ParseResult {
1907 return parseArgument(
result.emplace_back(), allowType, allowAttrs);
1910 " in argument list");
1919 ParseResult parseRegion(Region ®ion, ArrayRef<Argument> arguments,
1920 bool enableNameShadowing)
override {
1922 (void)isIsolatedFromAbove;
1923 assert((!enableNameShadowing || isIsolatedFromAbove) &&
1924 "name shadowing is only allowed on isolated regions");
1925 if (parser.parseRegion(region, arguments, enableNameShadowing))
1931 OptionalParseResult parseOptionalRegion(Region ®ion,
1932 ArrayRef<Argument> arguments,
1933 bool enableNameShadowing)
override {
1934 if (parser.getToken().isNot(Token::l_brace))
1935 return std::nullopt;
1936 return parseRegion(region, arguments, enableNameShadowing);
1943 parseOptionalRegion(std::unique_ptr<Region> ®ion,
1944 ArrayRef<Argument> arguments,
1945 bool enableNameShadowing =
false)
override {
1946 if (parser.getToken().isNot(Token::l_brace))
1947 return std::nullopt;
1948 std::unique_ptr<Region> newRegion = std::make_unique<Region>();
1949 if (parseRegion(*newRegion, arguments, enableNameShadowing))
1952 region = std::move(newRegion);
1961 ParseResult parseSuccessor(
Block *&dest)
override {
1962 return parser.parseSuccessor(dest);
1966 OptionalParseResult parseOptionalSuccessor(
Block *&dest)
override {
1967 if (!parser.getToken().isOrIsCodeCompletionFor(Token::caret_identifier))
1968 return std::nullopt;
1969 return parseSuccessor(dest);
1974 parseSuccessorAndUseList(
Block *&dest,
1975 SmallVectorImpl<Value> &operands)
override {
1976 if (parseSuccessor(dest))
1980 if (succeeded(parseOptionalLParen()) &&
1981 (parser.parseOptionalSSAUseAndTypeList(operands) || parseRParen())) {
1993 OptionalParseResult parseOptionalAssignmentList(
1994 SmallVectorImpl<Argument> &
lhs,
1995 SmallVectorImpl<UnresolvedOperand> &
rhs)
override {
1996 if (
failed(parseOptionalLParen()))
1997 return std::nullopt;
1999 auto parseElt = [&]() -> ParseResult {
2000 if (parseArgument(
lhs.emplace_back()) || parseEqual() ||
2001 parseOperand(
rhs.emplace_back()))
2005 return parser.parseCommaSeparatedListUntil(Token::r_paren, parseElt);
2010 parseOptionalLocationSpecifier(std::optional<Location> &
result)
override {
2012 if (!parser.consumeIf(Token::kw_loc))
2014 LocationAttr directLoc;
2015 if (parser.parseToken(Token::l_paren,
"expected '(' in location"))
2018 Token tok = parser.getToken();
2024 if (tok.
is(Token::hash_identifier) && !tok.
getSpelling().contains(
'.')) {
2025 if (parser.parseLocationAlias(directLoc))
2027 }
else if (parser.parseLocationInstance(directLoc)) {
2031 if (parser.parseToken(Token::r_paren,
"expected ')' in location"))
2040 ArrayRef<OperationParser::ResultRecord> resultIDs;
2043 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly;
2044 bool isIsolatedFromAbove;
2048 OperationParser &parser;
2052FailureOr<OperationName> OperationParser::parseCustomOperationName() {
2053 Token nameTok = getToken();
2058 return emitError(
"expected bare identifier or keyword");
2061 return (
emitError(
"empty operation name is invalid"), failure());
2065 std::optional<RegisteredOperationName> opInfo =
2072 auto opNameSplit = opName.split(
'.');
2073 StringRef dialectName = opNameSplit.first;
2074 std::string opNameStorage;
2075 if (opNameSplit.second.empty()) {
2077 if (getToken().isCodeCompletion() && opName.back() ==
'.')
2078 return codeCompleteOperationName(dialectName);
2080 dialectName = getState().defaultDialectStack.back();
2081 opNameStorage = (dialectName +
"." + opName).str();
2082 opName = opNameStorage;
2092OperationParser::parseCustomOperation(ArrayRef<ResultRecord> resultIDs) {
2093 SMLoc opLoc = getToken().getLoc();
2094 StringRef originalOpName = getTokenSpelling();
2096 FailureOr<OperationName> opNameInfo = parseCustomOperationName();
2099 StringRef opName = opNameInfo->getStringRef();
2105 bool isIsolatedFromAbove =
false;
2107 StringRef defaultDialect =
"";
2108 if (
auto opInfo = opNameInfo->getRegisteredInfo()) {
2109 parseAssemblyFn = opInfo->getParseAssemblyFn();
2110 isIsolatedFromAbove = opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>();
2111 auto *iface = opInfo->getInterface<OpAsmOpInterface>();
2112 if (iface && !iface->getDefaultDialect().empty())
2113 defaultDialect = iface->getDefaultDialect();
2115 std::optional<Dialect::ParseOpHook> dialectHook;
2116 Dialect *dialect = opNameInfo->getDialect();
2118 InFlightDiagnostic
diag =
2119 emitError(opLoc) <<
"Dialect `" << opNameInfo->getDialectNamespace()
2120 <<
"' not found for custom op '" << originalOpName
2122 if (originalOpName != opName)
2123 diag <<
" (tried '" << opName <<
"' as well)";
2124 auto ¬e =
diag.attachNote();
2125 note <<
"Available dialects: ";
2126 std::vector<StringRef> registered =
getContext()->getAvailableDialects();
2127 auto loaded =
getContext()->getLoadedDialects();
2130 SmallVector<std::pair<StringRef, bool>> mergedDialects;
2131 auto regIt = registered.begin(), regEnd = registered.end();
2132 auto loadIt = loaded.rbegin(), loadEnd = loaded.rend();
2133 bool isRegistered =
false;
2134 bool isOnlyLoaded =
true;
2135 while (regIt != regEnd && loadIt != loadEnd) {
2136 StringRef reg = *regIt;
2137 StringRef
load = (*loadIt)->getNamespace();
2139 mergedDialects.emplace_back(
load, isOnlyLoaded);
2142 mergedDialects.emplace_back(reg, isRegistered);
2148 for (; regIt != regEnd; ++regIt)
2149 mergedDialects.emplace_back(*regIt, isRegistered);
2150 for (; loadIt != loadEnd; ++loadIt)
2151 mergedDialects.emplace_back((*loadIt)->getNamespace(), isOnlyLoaded);
2153 bool loadedUnregistered =
false;
2154 llvm::interleaveComma(mergedDialects, note, [&](
auto &pair) {
2157 loadedUnregistered =
true;
2162 if (loadedUnregistered)
2163 note <<
"(* corresponding to loaded but unregistered dialects)";
2164 note <<
"; for more info on dialect registration see "
2165 "https://mlir.llvm.org/getting_started/Faq/"
2166 "#registered-loaded-dependent-whats-up-with-dialects-management";
2171 InFlightDiagnostic
diag =
2172 emitError(opLoc) <<
"custom op '" << originalOpName <<
"' is unknown";
2173 if (originalOpName != opName)
2174 diag <<
" (tried '" << opName <<
"' as well)";
2177 parseAssemblyFn = *dialectHook;
2179 getState().defaultDialectStack.push_back(defaultDialect);
2180 llvm::scope_exit restoreDefaultDialect(
2181 [&]() { getState().defaultDialectStack.pop_back(); });
2185 llvm::PrettyStackTraceFormat fmt(
"MLIR Parser: custom op parser '%s'",
2186 opNameInfo->getIdentifier().data());
2189 auto srcLocation = getEncodedSourceLocation(opLoc);
2190 OperationState opState(srcLocation, *opNameInfo);
2197 CleanupOpStateRegions guard{opState};
2198 CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn,
2199 isIsolatedFromAbove, opName, *
this);
2200 if (opAsmParser.parseOperation(opState))
2204 if (opAsmParser.didEmitError())
2211 Operation *op = opBuilder.
create(opState);
2212 if (parseTrailingLocationSpecifier(op))
2228ParseResult OperationParser::parseLocationAlias(LocationAttr &loc) {
2229 Token tok = getToken();
2230 consumeToken(Token::hash_identifier);
2231 StringRef identifier = tok.
getSpelling().drop_front();
2232 assert(!identifier.contains(
'.') &&
2233 "unexpected dialect attribute token, expected alias");
2241 if (!(loc = dyn_cast<LocationAttr>(attr)))
2243 <<
"expected location, but found '" << attr <<
"'";
2247 loc = OpaqueLoc::get(deferredLocsReferences.size(),
2250 deferredLocsReferences.push_back(DeferredLocInfo{tok.
getLoc(), identifier});
2256OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) {
2258 if (!consumeIf(Token::kw_loc))
2260 if (parseToken(Token::l_paren,
"expected '(' in location"))
2262 Token tok = getToken();
2267 LocationAttr directLoc;
2268 if (tok.
is(Token::hash_identifier) && !tok.
getSpelling().contains(
'.')) {
2269 if (parseLocationAlias(directLoc))
2271 }
else if (parseLocationInstance(directLoc)) {
2275 if (parseToken(Token::r_paren,
"expected ')' in location"))
2278 if (
auto *op = llvm::dyn_cast_if_present<Operation *>(opOrArgument))
2281 cast<BlockArgument>(opOrArgument).setLoc(directLoc);
2289ParseResult OperationParser::parseRegion(Region ®ion,
2290 ArrayRef<Argument> entryArguments,
2291 bool isIsolatedNameScope) {
2293 Token lBraceTok = getToken();
2294 if (parseToken(Token::l_brace,
"expected '{' to begin a region"))
2302 if ((!entryArguments.empty() || getToken().isNot(Token::r_brace)) &&
2303 parseRegionBody(region, lBraceTok.
getLoc(), entryArguments,
2304 isIsolatedNameScope)) {
2307 consumeToken(Token::r_brace);
2316ParseResult OperationParser::parseRegionBody(Region ®ion, SMLoc startLoc,
2317 ArrayRef<Argument> entryArguments,
2318 bool isIsolatedNameScope) {
2319 auto currentPt = opBuilder.saveInsertionPoint();
2322 pushSSANameScope(isIsolatedNameScope);
2325 auto owningBlock = std::make_unique<Block>();
2326 llvm::scope_exit failureCleanup([&] {
2331 owningBlock->dropAllDefinedValueUses();
2334 Block *block = owningBlock.get();
2339 if (state.
asmState && getToken().isNot(Token::caret_identifier))
2343 if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) {
2345 if (getToken().is(Token::caret_identifier))
2346 return emitError(
"invalid block name in region with named arguments");
2348 for (
auto &entryArg : entryArguments) {
2349 auto &argInfo = entryArg.ssaName;
2352 if (
auto defLoc = getReferenceLoc(argInfo.name, argInfo.number)) {
2353 return emitError(argInfo.location,
"region entry argument '" +
2355 "' is already in use")
2356 .
attachNote(getEncodedSourceLocation(*defLoc))
2357 <<
"previously referenced here";
2359 Location loc = entryArg.sourceLoc.has_value()
2360 ? *entryArg.sourceLoc
2361 : getEncodedSourceLocation(argInfo.location);
2362 BlockArgument arg = block->addArgument(entryArg.type, loc);
2369 if (addDefinition(argInfo, arg))
2374 if (parseBlock(block))
2378 if (!entryArguments.empty() &&
2379 block->getNumArguments() > entryArguments.size()) {
2380 return emitError(
"entry block arguments were already defined");
2384 region.
push_back(owningBlock.release());
2385 while (getToken().isNot(Token::r_brace)) {
2386 Block *newBlock =
nullptr;
2387 if (parseBlock(newBlock))
2393 if (popSSANameScope())
2397 opBuilder.restoreInsertionPoint(currentPt);
2412ParseResult OperationParser::parseBlock(
Block *&block) {
2415 if (block && getToken().isNot(Token::caret_identifier))
2416 return parseBlockBody(block);
2418 SMLoc nameLoc = getToken().getLoc();
2419 auto name = getTokenSpelling();
2420 if (parseToken(Token::caret_identifier,
"expected block name"))
2424 auto &blockAndLoc = getBlockInfoByName(name);
2425 blockAndLoc.loc = nameLoc;
2430 std::unique_ptr<Block> inflightBlock;
2431 llvm::scope_exit cleanupOnFailure([&] {
2433 inflightBlock->dropAllDefinedValueUses();
2438 if (!blockAndLoc.block) {
2440 blockAndLoc.block = block;
2442 inflightBlock = std::make_unique<Block>();
2443 blockAndLoc.block = inflightBlock.get();
2450 }
else if (!eraseForwardRef(blockAndLoc.block)) {
2451 return emitError(nameLoc,
"redefinition of block '") << name <<
"'";
2455 inflightBlock.reset(blockAndLoc.block);
2461 block = blockAndLoc.block;
2464 if (getToken().is(Token::l_paren))
2465 if (parseOptionalBlockArgList(block))
2467 if (parseToken(Token::colon,
"expected ':' after block name"))
2471 ParseResult res = parseBlockBody(block);
2476 (void)inflightBlock.release();
2480ParseResult OperationParser::parseBlockBody(
Block *block) {
2482 opBuilder.setInsertionPointToEnd(block);
2485 while (getToken().isNot(Token::caret_identifier, Token::r_brace))
2486 if (parseOperation())
2495Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
2496 BlockDefinition &blockDef = getBlockInfoByName(name);
2497 if (!blockDef.block) {
2498 blockDef = {
new Block(), loc};
2499 insertForwardRef(blockDef.block, blockDef.loc);
2506 return blockDef.block;
2515ParseResult OperationParser::parseOptionalBlockArgList(
Block *owner) {
2516 if (getToken().is(Token::r_brace))
2522 unsigned nextArgument = 0;
2525 return parseSSADefOrUseAndType(
2526 [&](UnresolvedOperand useInfo, Type type) -> ParseResult {
2531 if (definingExistingArgs) {
2534 return emitError(
"too many arguments specified in argument list");
2539 return emitError(
"argument and block argument type mismatch");
2541 auto loc = getEncodedSourceLocation(useInfo.location);
2547 if (parseTrailingLocationSpecifier(arg))
2555 return addDefinition(useInfo, arg);
2564ParseResult OperationParser::codeCompleteSSAUse() {
2565 for (IsolatedSSANameScope &scope : isolatedNameScopes) {
2567 SmallVector<StringRef> sortedNames;
2568 for (
auto &it : scope.values)
2569 if (!it.second.empty())
2570 sortedNames.push_back(it.getKey());
2571 llvm::sort(sortedNames);
2573 for (StringRef name : sortedNames) {
2574 Value frontValue = scope.values[name].front().value;
2576 std::string detailData;
2577 llvm::raw_string_ostream detailOS(detailData);
2581 if (
auto result = dyn_cast<OpResult>(frontValue)) {
2582 if (!forwardRefPlaceholders.count(
result))
2583 detailOS <<
result.getOwner()->getName() <<
": ";
2585 detailOS <<
"arg #" << cast<BlockArgument>(frontValue).getArgNumber()
2590 detailOS << frontValue.
getType();
2595 if (scope.values[name].size() > 1)
2596 detailOS <<
", ...";
2599 name, std::move(detailData));
2606ParseResult OperationParser::codeCompleteBlock() {
2609 StringRef spelling = getTokenSpelling();
2610 if (!(spelling.empty() || spelling ==
"^"))
2613 for (
const auto &it : blocksByName.back())
2625class TopLevelOperationParser :
public Parser {
2627 explicit TopLevelOperationParser(ParserState &state) : Parser(state) {}
2630 ParseResult
parse(
Block *topLevelBlock, Location parserLoc);
2637 ParseResult parseAttributeAliasDef();
2643 ParseResult parseTypeAliasDef();
2649 ParseResult parseFileMetadataDictionary();
2652 ParseResult parseResourceFileMetadata(
2653 function_ref<ParseResult(StringRef, SMLoc)> parseBody);
2654 ParseResult parseDialectResourceFileMetadata();
2655 ParseResult parseExternalResourceFileMetadata();
2660class ParsedResourceEntry :
public AsmParsedResourceEntry {
2662 ParsedResourceEntry(std::string key, SMLoc keyLoc, Token value, Parser &p)
2663 : key(std::move(key)), keyLoc(keyLoc), value(value), p(p) {}
2664 ~ParsedResourceEntry()
override =
default;
2666 StringRef getKey() const final {
return key; }
2668 InFlightDiagnostic
emitError() const final {
return p.emitError(keyLoc); }
2671 if (value.isAny(Token::kw_true, Token::kw_false))
2672 return AsmResourceEntryKind::Bool;
2673 return value.getSpelling().starts_with(
"\"0x")
2674 ? AsmResourceEntryKind::Blob
2675 : AsmResourceEntryKind::String;
2678 FailureOr<bool> parseAsBool() const final {
2679 if (value.is(Token::kw_true))
2681 if (value.is(Token::kw_false))
2683 return p.emitError(value.getLoc(),
2684 "expected 'true' or 'false' value for key '" + key +
2688 FailureOr<std::string> parseAsString() const final {
2689 if (value.isNot(Token::string))
2690 return p.emitError(value.getLoc(),
2691 "expected string value for key '" + key +
"'");
2692 return value.getStringValue();
2695 FailureOr<AsmResourceBlob>
2696 parseAsBlob(BlobAllocatorFn allocator)
const final {
2700 std::optional<std::string> blobData =
2701 value.is(Token::string) ? value.getHexStringValue() : std::nullopt;
2703 return p.emitError(value.getLoc(),
2704 "expected hex string blob for key '" + key +
"'");
2708 if (blobData->size() <
sizeof(uint32_t)) {
2709 return p.emitError(value.getLoc(),
2710 "expected hex string blob for key '" + key +
2711 "' to encode alignment in first 4 bytes");
2713 llvm::support::ulittle32_t align;
2714 memcpy(&align, blobData->data(),
sizeof(uint32_t));
2715 if (align && !llvm::isPowerOf2_32(align)) {
2716 return p.emitError(value.getLoc(),
2717 "expected hex string blob for key '" + key +
2718 "' to encode alignment in first 4 bytes, but got "
2719 "non-power-of-2 value: " +
2724 StringRef data = StringRef(*blobData).drop_front(
sizeof(uint32_t));
2726 return AsmResourceBlob();
2730 AsmResourceBlob blob = allocator(data.size(), align);
2731 assert(llvm::isAddrAligned(llvm::Align(align), blob.
getData().data()) &&
2733 "blob allocator did not return a properly aligned address");
2746ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
2747 assert(getToken().is(Token::hash_identifier));
2748 StringRef aliasName = getTokenSpelling().drop_front();
2752 return emitError(
"redefinition of attribute alias id '" + aliasName +
"'");
2755 if (aliasName.contains(
'.'))
2756 return emitError(
"attribute names with a '.' are reserved for "
2757 "dialect-defined names");
2759 SMRange location = getToken().getLocRange();
2760 consumeToken(Token::hash_identifier);
2763 if (parseToken(Token::equal,
"expected '=' in attribute alias definition"))
2778ParseResult TopLevelOperationParser::parseTypeAliasDef() {
2779 assert(getToken().is(Token::exclamation_identifier));
2780 StringRef aliasName = getTokenSpelling().drop_front();
2784 return emitError(
"redefinition of type alias id '" + aliasName +
"'");
2787 if (aliasName.contains(
'.'))
2788 return emitError(
"type names with a '.' are reserved for "
2789 "dialect-defined names");
2791 SMRange location = getToken().getLocRange();
2792 consumeToken(Token::exclamation_identifier);
2795 if (parseToken(Token::equal,
"expected '=' in type alias definition"))
2810ParseResult TopLevelOperationParser::parseFileMetadataDictionary() {
2811 consumeToken(Token::file_metadata_begin);
2812 return parseCommaSeparatedListUntil(
2813 Token::file_metadata_end, [&]() -> ParseResult {
2815 SMLoc keyLoc = getToken().getLoc();
2817 if (
failed(parseOptionalKeyword(&key)))
2818 return emitError(
"expected identifier key in file "
2819 "metadata dictionary");
2820 if (parseToken(Token::colon,
"expected ':'"))
2824 if (key ==
"dialect_resources")
2825 return parseDialectResourceFileMetadata();
2826 if (key ==
"external_resources")
2827 return parseExternalResourceFileMetadata();
2828 return emitError(keyLoc,
"unknown key '" + key +
2829 "' in file metadata dictionary");
2833ParseResult TopLevelOperationParser::parseResourceFileMetadata(
2834 function_ref<ParseResult(StringRef, SMLoc)> parseBody) {
2835 if (parseToken(Token::l_brace,
"expected '{'"))
2838 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2840 SMLoc nameLoc = getToken().getLoc();
2842 if (
failed(parseOptionalKeyword(&name)))
2843 return emitError(
"expected identifier key for 'resource' entry");
2845 if (parseToken(Token::colon,
"expected ':'") ||
2846 parseToken(Token::l_brace,
"expected '{'"))
2848 return parseBody(name, nameLoc);
2852ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() {
2853 return parseResourceFileMetadata([&](StringRef name,
2854 SMLoc nameLoc) -> ParseResult {
2856 Dialect *dialect =
getContext()->getOrLoadDialect(name);
2858 return emitError(nameLoc,
"dialect '" + name +
"' is unknown");
2859 const auto *handler = dyn_cast<OpAsmDialectInterface>(dialect);
2861 return emitError() <<
"unexpected 'resource' section for dialect '"
2865 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2867 SMLoc keyLoc = getToken().getLoc();
2869 if (
failed(parseResourceHandle(handler, key)) ||
2870 parseToken(Token::colon,
"expected ':'"))
2872 Token valueTok = getToken();
2875 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2876 return handler->parseResource(entry);
2881ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() {
2882 return parseResourceFileMetadata([&](StringRef name,
2883 SMLoc nameLoc) -> ParseResult {
2889 <<
"ignoring unknown external resources for '" << name <<
"'";
2892 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2894 SMLoc keyLoc = getToken().getLoc();
2896 if (
failed(parseOptionalKeywordOrString(&key)))
2898 "expected identifier key for 'external_resources' entry");
2899 if (parseToken(Token::colon,
"expected ':'"))
2901 Token valueTok = getToken();
2906 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2912ParseResult TopLevelOperationParser::parse(
Block *topLevelBlock,
2913 Location parserLoc) {
2915 OwningOpRef<ModuleOp> topLevelOp(ModuleOp::create(parserLoc));
2916 OperationParser opParser(state, topLevelOp.get());
2918 switch (getToken().getKind()) {
2921 if (opParser.parseOperation())
2927 if (opParser.finalize())
2932 auto &parsedOps = topLevelOp->getBody()->getOperations();
2934 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(),
2946 case Token::hash_identifier:
2947 if (parseAttributeAliasDef())
2952 case Token::exclamation_identifier:
2953 if (parseTypeAliasDef())
2958 case Token::file_metadata_begin:
2959 if (parseFileMetadataDictionary())
2972 const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
2979 ParserState state(sourceMgr, config, aliasState, asmState,
2980 codeCompleteContext);
2981 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.