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) {
91 if (
getToken().isNot(Token::l_paren))
95 if (
parseToken(Token::l_paren,
"expected '('" + contextMessage))
107 if (
parseToken(Token::less,
"expected '<'" + contextMessage))
114 if (
getToken().isNot(Token::l_square))
118 if (
parseToken(Token::l_square,
"expected '['" + contextMessage))
125 if (
getToken().isNot(Token::l_brace))
129 if (
parseToken(Token::l_brace,
"expected '{'" + contextMessage))
138 if (parseElementFn())
143 if (parseElementFn())
152 return parseToken(Token::r_paren,
"expected ')'" + contextMessage);
155 return parseToken(Token::greater,
"expected '>'" + contextMessage);
158 return parseToken(Token::r_square,
"expected ']'" + contextMessage);
161 return parseToken(Token::r_brace,
"expected '}'" + contextMessage);
163 llvm_unreachable(
"Unknown delimiter");
175 bool allowEmptyList) {
198 return emitError(SMLoc::getFromPointer(loc.getPointer() - 1), message);
220 loc = SMLoc::getFromPointer(loc.getPointer() - 1);
223 auto originalLoc = loc;
227 const char *curPtr = loc.getPointer();
231 StringRef startOfBuffer(bufferStart, curPtr - bufferStart);
236 startOfBuffer = startOfBuffer.rtrim(
" \t");
240 if (startOfBuffer.empty())
244 if (startOfBuffer.back() !=
'\n' && startOfBuffer.back() !=
'\r')
245 return emitError(SMLoc::getFromPointer(startOfBuffer.end()), message);
248 startOfBuffer = startOfBuffer.drop_back();
253 auto prevLine = startOfBuffer;
254 size_t newLineIndex = prevLine.find_last_of(
"\n\r");
255 if (newLineIndex != StringRef::npos)
256 prevLine = prevLine.drop_front(newLineIndex);
259 size_t commentStart = prevLine.find(
"//");
260 if (commentStart != StringRef::npos)
261 startOfBuffer = startOfBuffer.drop_back(prevLine.size() - commentStart);
268 const Twine &message) {
298 if (curToken.
isNot(Token::integer, Token::minus))
303 if (
parseToken(Token::integer,
"expected integer value"))
307 bool isHex = spelling.size() > 1 && spelling[1] ==
'x';
308 if (spelling.getAsInteger(isHex ? 0 : 10, result))
312 if (result.isNegative())
313 result = result.zext(result.getBitWidth() + 1);
325 if (curToken.
isNot(Token::integer, Token::minus)) {
331 if (
parseToken(Token::integer,
"expected integer value")) {
339 if (spelling[0] ==
'0' && spelling.size() > 1 &&
347 if (spelling.getAsInteger(10, result))
351 if (result.isNegative())
352 result = result.zext(result.getBitWidth() + 1);
362 const Token &tok,
bool isNegative,
363 const llvm::fltSemantics &semantics) {
365 if (tok.
is(Token::floatliteral)) {
370 result.emplace(isNegative ? -*val : *val);
372 result->convert(semantics, APFloat::rmNearestTiesToEven, &unused);
377 if (tok.
is(Token::integer))
386 const Token &tok,
bool isNegative,
387 const llvm::fltSemantics &semantics) {
389 bool isHex = spelling.size() > 1 && spelling[1] ==
'x';
391 return emitError(tok.
getLoc(),
"unexpected decimal integer literal for a "
392 "floating point value")
394 <<
"add a trailing dot to make the literal a float";
398 "hexadecimal float literal should not have a "
403 tok.
getSpelling().getAsInteger(isHex ? 0 : 10, intValue);
404 auto typeSizeInBits = APFloat::semanticsSizeInBits(semantics);
405 if (intValue.getActiveBits() > typeSizeInBits) {
407 "hexadecimal float constant out of range for type");
410 APInt truncatedValue(typeSizeInBits, intValue.getNumWords(),
411 intValue.getRawData());
412 result.emplace(semantics, truncatedValue);
429 *result = keyword.str();
440 FailureOr<AsmDialectResourceHandle>
443 assert(dialect &&
"expected valid dialect interface");
446 return emitError(
"expected identifier key for 'resource' entry");
452 std::pair<std::string, AsmDialectResourceHandle> &entry =
453 resources[dialect][name];
454 if (entry.first.empty()) {
455 FailureOr<AsmDialectResourceHandle> result = dialect->
declareResource(name);
456 if (failed(result)) {
458 <<
"unknown 'resource' key '" << name <<
"' for dialect '"
459 << dialect->getDialect()->getNamespace() <<
"'";
462 entry.second = *result;
469 FailureOr<AsmDialectResourceHandle>
474 <<
"' does not expect resource handles";
476 std::string resourceName;
493 if (dialectName.empty() || dialectName.contains(
'.'))
504 auto shouldIgnoreOpCompletion = [&]() {
506 const char *it = loc.getPointer() - 1;
507 for (; it > bufBegin && *it !=
'\n'; --it)
508 if (!StringRef(
" \t\r").contains(*it))
512 if (shouldIgnoreOpCompletion())
530 if (name.consume_back(
"."))
571 class OperationParser :
public Parser {
573 OperationParser(
ParserState &state, ModuleOp topLevelOp);
578 ParseResult finalize();
587 struct DeferredLocInfo {
589 StringRef identifier;
593 void pushSSANameScope(
bool isIsolated);
596 ParseResult popSSANameScope();
599 ParseResult addDefinition(UnresolvedOperand useInfo,
Value value);
607 ParseResult parseSSAUse(UnresolvedOperand &result,
608 bool allowResultNumber =
true);
612 Value resolveSSAUse(UnresolvedOperand useInfo,
Type type);
614 ParseResult parseSSADefOrUseAndType(
621 std::optional<SMLoc> getReferenceLoc(StringRef name,
unsigned number) {
622 auto &values = isolatedNameScopes.back().values;
623 if (!values.count(name) || number >= values[name].size())
625 if (values[name][number].value)
626 return values[name][number].loc;
635 ParseResult parseOperation();
638 ParseResult parseSuccessor(
Block *&dest);
651 ParseResult parseGenericOperationAfterOpName(
656 std::optional<
MutableArrayRef<std::unique_ptr<Region>>> parsedRegions =
659 std::optional<Attribute> propertiesAttribute = std::nullopt,
660 std::optional<FunctionType> parsedFnType = std::nullopt);
677 ParseResult parseTrailingLocationSpecifier(OpOrArgument opOrArgument);
687 using ResultRecord = std::tuple<StringRef, unsigned, SMLoc>;
695 FailureOr<OperationName> parseCustomOperationName();
705 bool isIsolatedNameScope =
false);
708 ParseResult parseRegionBody(
Region ®ion, SMLoc startLoc,
710 bool isIsolatedNameScope);
717 ParseResult parseBlock(
Block *&block);
720 ParseResult parseBlockBody(
Block *block);
723 ParseResult parseOptionalBlockArgList(
Block *owner);
728 Block *getBlockNamed(StringRef name, SMLoc loc);
738 ParseResult codeCompleteSSAUse();
739 ParseResult codeCompleteBlock();
743 struct BlockDefinition {
750 struct ValueDefinition {
758 BlockDefinition &getBlockInfoByName(StringRef name) {
759 return blocksByName.back()[name];
763 void insertForwardRef(
Block *block, SMLoc loc) {
764 forwardRef.back().try_emplace(block, loc);
768 bool eraseForwardRef(
Block *block) {
return forwardRef.back().erase(block); }
771 void recordDefinition(StringRef def);
778 Value createForwardRefPlaceholder(SMLoc loc,
Type type);
781 bool isForwardRefPlaceholder(
Value value) {
782 return forwardRefPlaceholders.count(value);
789 struct IsolatedSSANameScope {
791 void recordDefinition(StringRef def) {
792 definitionsPerScope.back().insert(def);
796 void pushSSANameScope() { definitionsPerScope.push_back({}); }
799 void popSSANameScope() {
800 for (
auto &def : definitionsPerScope.pop_back_val())
801 values.erase(def.getKey());
806 llvm::StringMap<SmallVector<ValueDefinition, 1>> values;
834 std::vector<DeferredLocInfo> deferredLocsReferences;
847 OperationParser::OperationParser(
ParserState &state, ModuleOp topLevelOp)
848 :
Parser(state), opBuilder(topLevelOp.getRegion()), topLevelOp(topLevelOp) {
850 pushSSANameScope(
true);
857 OperationParser::~OperationParser() {
864 for (
const auto &scope : forwardRef) {
865 for (
const auto &fwd : scope) {
868 fwd.first->dropAllUses();
876 ParseResult OperationParser::finalize() {
879 if (!forwardRefPlaceholders.empty()) {
882 for (
auto entry : forwardRefPlaceholders)
883 errors.push_back(entry.second.getPointer());
884 llvm::array_pod_sort(errors.begin(), errors.end());
886 for (
const char *entry : errors) {
887 auto loc = SMLoc::getFromPointer(entry);
888 emitError(loc,
"use of undeclared SSA value name");
894 auto &attributeAliases = state.symbols.attributeAliasDefinitions;
895 auto locID = TypeID::get<DeferredLocInfo *>();
896 auto resolveLocation = [&,
this](
auto &opOrArgument) -> LogicalResult {
897 auto fwdLoc = dyn_cast<OpaqueLoc>(opOrArgument.getLoc());
898 if (!fwdLoc || fwdLoc.getUnderlyingTypeID() != locID)
900 auto locInfo = deferredLocsReferences[fwdLoc.getUnderlyingLocation()];
901 Attribute attr = attributeAliases.lookup(locInfo.identifier);
904 <<
"operation location alias was never defined";
905 auto locAttr = dyn_cast<LocationAttr>(attr);
908 <<
"expected location, but found '" << attr <<
"'";
909 opOrArgument.setLoc(locAttr);
913 auto walkRes = topLevelOp->walk([&](
Operation *op) {
914 if (failed(resolveLocation(*op)))
917 for (
Block &block : region.getBlocks())
919 if (failed(resolveLocation(arg)))
923 if (walkRes.wasInterrupted())
927 if (failed(popSSANameScope()))
931 if (state.config.shouldVerifyAfterParse() && failed(
verify(topLevelOp)))
936 state.asmState->finalize(topLevelOp);
944 void OperationParser::pushSSANameScope(
bool isIsolated) {
950 isolatedNameScopes.push_back({});
951 isolatedNameScopes.back().pushSSANameScope();
954 ParseResult OperationParser::popSSANameScope() {
955 auto forwardRefInCurrentScope = forwardRef.pop_back_val();
958 if (!forwardRefInCurrentScope.empty()) {
961 for (
auto entry : forwardRefInCurrentScope) {
962 errors.push_back({entry.second.getPointer(), entry.first});
964 topLevelOp->getRegion(0).push_back(entry.first);
966 llvm::array_pod_sort(errors.begin(), errors.end());
968 for (
auto entry : errors) {
969 auto loc = SMLoc::getFromPointer(entry.first);
970 emitError(loc,
"reference to an undefined block");
977 auto ¤tNameScope = isolatedNameScopes.back();
978 if (currentNameScope.definitionsPerScope.size() == 1)
979 isolatedNameScopes.pop_back();
981 currentNameScope.popSSANameScope();
983 blocksByName.pop_back();
988 ParseResult OperationParser::addDefinition(UnresolvedOperand useInfo,
990 auto &entries = getSSAValueEntry(useInfo.name);
993 if (entries.size() <= useInfo.number)
994 entries.resize(useInfo.number + 1);
998 if (
auto existing = entries[useInfo.number].value) {
999 if (!isForwardRefPlaceholder(existing)) {
1001 .
append(
"redefinition of SSA value '", useInfo.name,
"'")
1002 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1003 .
append(
"previously defined here");
1006 if (existing.getType() != value.
getType()) {
1008 .
append(
"definition of SSA value '", useInfo.name,
"#",
1009 useInfo.number,
"' has type ", value.
getType())
1010 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1011 .
append(
"previously used here with type ", existing.getType());
1017 existing.replaceAllUsesWith(value);
1018 forwardRefPlaceholders.erase(existing);
1023 state.asmState->refineDefinition(existing, value);
1027 entries[useInfo.number] = {value, useInfo.location};
1028 recordDefinition(useInfo.name);
1037 ParseResult OperationParser::parseOptionalSSAUseList(
1039 if (!getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
1042 UnresolvedOperand result;
1043 if (parseSSAUse(result))
1045 results.push_back(result);
1054 ParseResult OperationParser::parseSSAUse(UnresolvedOperand &result,
1055 bool allowResultNumber) {
1056 if (getToken().isCodeCompletion())
1057 return codeCompleteSSAUse();
1059 result.name = getTokenSpelling();
1061 result.location = getToken().getLoc();
1062 if (parseToken(Token::percent_identifier,
"expected SSA operand"))
1066 if (getToken().is(Token::hash_identifier)) {
1067 if (!allowResultNumber)
1068 return emitError(
"result number not allowed in argument list");
1070 if (
auto value = getToken().getHashIdentifierNumber())
1071 result.number = *value;
1073 return emitError(
"invalid SSA value result number");
1074 consumeToken(Token::hash_identifier);
1082 Value OperationParser::resolveSSAUse(UnresolvedOperand useInfo,
Type type) {
1083 auto &entries = getSSAValueEntry(useInfo.name);
1087 auto maybeRecordUse = [&](
Value value) {
1089 state.asmState->addUses(value, useInfo.location);
1094 if (useInfo.number < entries.size() && entries[useInfo.number].value) {
1095 Value result = entries[useInfo.number].value;
1098 return maybeRecordUse(result);
1100 emitError(useInfo.location,
"use of value '")
1102 "' expects different type than prior uses: ", type,
" vs ",
1104 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1105 .
append(
"prior use here");
1110 if (entries.size() <= useInfo.number)
1111 entries.resize(useInfo.number + 1);
1115 if (entries[0].value && !isForwardRefPlaceholder(entries[0].value))
1116 return (
emitError(useInfo.location,
"reference to invalid result number"),
1121 Value result = createForwardRefPlaceholder(useInfo.location, type);
1122 entries[useInfo.number] = {result, useInfo.location};
1123 return maybeRecordUse(result);
1129 ParseResult OperationParser::parseSSADefOrUseAndType(
1131 UnresolvedOperand useInfo;
1132 if (parseSSAUse(useInfo) ||
1133 parseToken(Token::colon,
"expected ':' and type for SSA operand"))
1140 return action(useInfo, type);
1149 ParseResult OperationParser::parseOptionalSSAUseAndTypeList(
1152 if (parseOptionalSSAUseList(valueIDs))
1156 if (valueIDs.empty())
1160 if (parseToken(Token::colon,
"expected ':' in operand list") ||
1161 parseTypeListNoParens(types))
1164 if (valueIDs.size() != types.size())
1166 << valueIDs.size() <<
" types to match operand list";
1168 results.reserve(valueIDs.size());
1169 for (
unsigned i = 0, e = valueIDs.size(); i != e; ++i) {
1170 if (
auto value = resolveSSAUse(valueIDs[i], types[i]))
1171 results.push_back(value);
1180 void OperationParser::recordDefinition(StringRef def) {
1181 isolatedNameScopes.back().recordDefinition(def);
1185 auto OperationParser::getSSAValueEntry(StringRef name)
1187 return isolatedNameScopes.back().values[name];
1191 Value OperationParser::createForwardRefPlaceholder(SMLoc loc,
Type type) {
1200 getEncodedSourceLocation(loc), name, type, {},
1201 std::nullopt,
nullptr, {},
1203 forwardRefPlaceholders[op->
getResult(0)] = loc;
1204 forwardRefOps.insert(op);
1224 ParseResult OperationParser::parseOperation() {
1225 auto loc = getToken().
getLoc();
1227 size_t numExpectedResults = 0;
1228 if (getToken().is(Token::percent_identifier)) {
1230 auto parseNextResult = [&]() -> ParseResult {
1232 Token nameTok = getToken();
1233 if (parseToken(Token::percent_identifier,
1234 "expected valid ssa identifier"))
1238 size_t expectedSubResults = 1;
1239 if (consumeIf(Token::colon)) {
1241 if (!getToken().is(Token::integer))
1242 return emitWrongTokenError(
"expected integer number of results");
1245 auto val = getToken().getUInt64IntegerValue();
1246 if (!val || *val < 1)
1248 "expected named operation to have at least 1 result");
1249 consumeToken(Token::integer);
1250 expectedSubResults = *val;
1253 resultIDs.emplace_back(nameTok.
getSpelling(), expectedSubResults,
1255 numExpectedResults += expectedSubResults;
1261 if (parseToken(Token::equal,
"expected '=' after SSA name"))
1266 Token nameTok = getToken();
1267 if (nameTok.
is(Token::bare_identifier) || nameTok.
isKeyword())
1268 op = parseCustomOperation(resultIDs);
1269 else if (nameTok.
is(Token::string))
1270 op = parseGenericOperation();
1272 return codeCompleteStringDialectOrOperationName(nameTok.
getStringValue());
1274 return codeCompleteDialectOrElidedOpName(loc);
1276 return emitWrongTokenError(
"expected operation name in quotes");
1283 if (!resultIDs.empty()) {
1285 return emitError(loc,
"cannot name an operation with no results");
1287 return emitError(loc,
"operation defines ")
1289 << numExpectedResults <<
" to bind";
1292 if (state.asmState) {
1293 unsigned resultIt = 0;
1295 asmResultGroups.reserve(resultIDs.size());
1296 for (ResultRecord &record : resultIDs) {
1297 asmResultGroups.emplace_back(resultIt, std::get<2>(record));
1298 resultIt += std::get<1>(record);
1300 state.asmState->finalizeOperationDefinition(
1301 op, nameTok.
getLocRange(), getLastToken().getEndLoc(),
1306 unsigned opResI = 0;
1307 for (ResultRecord &resIt : resultIDs) {
1308 for (
unsigned subRes : llvm::seq<unsigned>(0, std::get<1>(resIt))) {
1309 if (addDefinition({std::get<2>(resIt), std::get<0>(resIt), subRes},
1316 }
else if (state.asmState) {
1317 state.asmState->finalizeOperationDefinition(
1319 getLastToken().getEndLoc());
1329 ParseResult OperationParser::parseSuccessor(
Block *&dest) {
1330 if (getToken().isCodeCompletion())
1331 return codeCompleteBlock();
1334 if (!getToken().is(Token::caret_identifier))
1335 return emitWrongTokenError(
"expected block name");
1336 dest = getBlockNamed(getTokenSpelling(), getToken().getLoc());
1347 if (parseToken(Token::l_square,
"expected '['"))
1350 auto parseElt = [
this, &destinations] {
1352 ParseResult res = parseSuccessor(dest);
1353 destinations.push_back(dest);
1356 return parseCommaSeparatedListUntil(Token::r_square, parseElt,
1365 struct CleanupOpStateRegions {
1366 ~CleanupOpStateRegions() {
1368 regionsToClean.reserve(state.regions.size());
1369 for (
auto ®ion : state.regions)
1371 for (
auto &block : *region)
1378 ParseResult OperationParser::parseGenericOperationAfterOpName(
1382 std::optional<
MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1384 std::optional<Attribute> propertiesAttribute,
1385 std::optional<FunctionType> parsedFnType) {
1389 if (!parsedOperandUseInfo) {
1390 if (parseToken(Token::l_paren,
"expected '(' to start operand list") ||
1391 parseOptionalSSAUseList(opInfo) ||
1392 parseToken(Token::r_paren,
"expected ')' to end operand list")) {
1395 parsedOperandUseInfo = opInfo;
1399 if (!parsedSuccessors) {
1400 if (getToken().is(Token::l_square)) {
1403 return emitError(
"successors in non-terminator");
1406 if (parseSuccessors(successors))
1415 if (propertiesAttribute) {
1417 }
else if (consumeIf(Token::less)) {
1421 if (parseToken(Token::greater,
"expected '>' to close properties"))
1425 if (!parsedRegions) {
1426 if (consumeIf(Token::l_paren)) {
1430 if (parseRegion(*result.
regions.back(), {}))
1432 }
while (consumeIf(Token::comma));
1433 if (parseToken(Token::r_paren,
"expected ')' to end region list"))
1441 if (!parsedAttributes) {
1442 if (getToken().is(Token::l_brace)) {
1452 if (!parsedFnType) {
1453 if (parseToken(Token::colon,
"expected ':' followed by operation type"))
1456 typeLoc = getEncodedSourceLocation(getToken().getLoc());
1460 auto fnType = dyn_cast<FunctionType>(type);
1464 parsedFnType = fnType;
1467 result.
addTypes(parsedFnType->getResults());
1471 if (operandTypes.size() != parsedOperandUseInfo->size()) {
1472 auto plural =
"s"[parsedOperandUseInfo->size() == 1];
1474 << parsedOperandUseInfo->size() <<
" operand type" << plural
1475 <<
" but had " << operandTypes.size();
1479 for (
unsigned i = 0, e = parsedOperandUseInfo->size(); i != e; ++i) {
1481 resolveSSAUse((*parsedOperandUseInfo)[i], operandTypes[i]));
1489 Operation *OperationParser::parseGenericOperation() {
1491 auto srcLocation = getEncodedSourceLocation(getToken().getLoc());
1493 std::string name = getToken().getStringValue();
1495 return (
emitError(
"empty operation name is invalid"),
nullptr);
1496 if (name.find(
'\0') != StringRef::npos)
1497 return (
emitError(
"null character not allowed in operation name"),
nullptr);
1499 consumeToken(Token::string);
1502 CleanupOpStateRegions guard{result};
1506 StringRef dialectName = StringRef(name).split(
'.').first;
1507 if (!
getContext()->getLoadedDialect(dialectName) &&
1508 !
getContext()->getOrLoadDialect(dialectName)) {
1509 if (!
getContext()->allowsUnregisteredDialects()) {
1512 emitError(
"operation being parsed with an unregistered dialect. If "
1513 "this is intended, please use -allow-unregistered-dialect "
1514 "with the MLIR tool used");
1525 state.asmState->startOperationDefinition(result.
name);
1527 if (parseGenericOperationAfterOpName(result))
1551 std::optional<RegisteredOperationName> info =
1554 if (failed(info->verifyInherentAttrs(result.
attributes, [&]() {
1555 return mlir::emitError(srcLocation) <<
"'" << name <<
"' op ";
1563 if (parseTrailingLocationSpecifier(op))
1571 << properties <<
" for op " << name <<
": ";
1580 Operation *OperationParser::parseGenericOperation(
Block *insertBlock,
1582 Token nameToken = getToken();
1585 opBuilder.setInsertionPoint(insertBlock, insertPt);
1586 Operation *op = parseGenericOperation();
1593 state.asmState->finalizeOperationDefinition(
1595 getLastToken().getEndLoc());
1600 class CustomOpAsmParser :
public AsmParserImpl<OpAsmParser> {
1605 bool isIsolatedFromAbove, StringRef opName, OperationParser &parser)
1607 parseAssembly(parseAssembly), isIsolatedFromAbove(isIsolatedFromAbove),
1608 opName(opName), parser(parser) {
1609 (void)isIsolatedFromAbove;
1615 if (parseAssembly(*
this, opState))
1621 std::optional<NamedAttribute> duplicate =
1624 return emitError(getNameLoc(),
"attribute '")
1625 << duplicate->getName().getValue()
1626 <<
"' occurs more than once in the attribute list";
1632 return parser.parseGenericOperation(insertBlock, insertPt);
1635 FailureOr<OperationName> parseCustomOperationName() final {
1636 return parser.parseCustomOperationName();
1639 ParseResult parseGenericOperationAfterOpName(
1643 std::optional<
MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1645 std::optional<Attribute> parsedPropertiesAttribute,
1646 std::optional<FunctionType> parsedFnType)
final {
1647 return parser.parseGenericOperationAfterOpName(
1648 result, parsedUnresolvedOperands, parsedSuccessors, parsedRegions,
1649 parsedAttributes, parsedPropertiesAttribute, parsedFnType);
1664 std::pair<StringRef, unsigned>
1665 getResultName(
unsigned resultNo)
const override {
1667 for (
const auto &entry : resultIDs) {
1668 if (resultNo < std::get<1>(entry)) {
1670 StringRef name = std::get<0>(entry).drop_front();
1671 return {name, resultNo};
1673 resultNo -= std::get<1>(entry);
1682 size_t getNumResults()
const override {
1684 for (
auto &entry : resultIDs)
1685 count += std::get<1>(entry);
1700 ParseResult parseOperand(UnresolvedOperand &result,
1701 bool allowResultNumber =
true)
override {
1703 if (parser.parseSSAUse(useInfo, allowResultNumber))
1712 parseOptionalOperand(UnresolvedOperand &result,
1713 bool allowResultNumber =
true)
override {
1714 if (parser.getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
1715 return parseOperand(result, allowResultNumber);
1716 return std::nullopt;
1723 bool allowResultNumber =
true,
1724 int requiredOperandCount = -1)
override {
1729 Token tok = parser.getToken();
1733 if (requiredOperandCount == -1 || requiredOperandCount == 0)
1737 if (tok.
isAny(Token::l_paren, Token::l_square))
1738 return parser.emitError(
"unexpected delimiter");
1739 return parser.emitWrongTokenError(
"expected operand");
1743 auto parseOneOperand = [&]() -> ParseResult {
1744 return parseOperand(result.emplace_back(), allowResultNumber);
1747 auto startLoc = parser.getToken().getLoc();
1752 if (requiredOperandCount != -1 &&
1753 result.size() !=
static_cast<size_t>(requiredOperandCount))
1755 << requiredOperandCount <<
" operands";
1760 ParseResult resolveOperand(
const UnresolvedOperand &operand,
Type type,
1762 if (
auto value = parser.resolveSSAUse(operand, type)) {
1763 result.push_back(value);
1777 auto parseElement = [&](
bool isSymbol) -> ParseResult {
1778 UnresolvedOperand operand;
1779 if (parseOperand(operand))
1782 symOperands.push_back(operand);
1784 dimOperands.push_back(operand);
1789 if (parser.parseAffineMapOfSSAIds(map, parseElement, delimiter))
1794 attrs.
push_back(parser.builder.getNamedAttr(attrName, mapAttr));
1798 operands.assign(dimOperands.begin(), dimOperands.end());
1799 operands.append(symOperands.begin(), symOperands.end());
1808 auto parseElement = [&](
bool isSymbol) -> ParseResult {
1809 UnresolvedOperand operand;
1810 if (parseOperand(operand))
1813 symbOperands.push_back(operand);
1815 dimOperands.push_back(operand);
1819 return parser.parseAffineExprOfSSAIds(expr, parseElement);
1832 ParseResult parseArgument(
Argument &result,
bool allowType =
false,
1833 bool allowAttrs =
false)
override {
1835 if (parseOperand(result.ssaName,
false) ||
1836 (allowType && parseColonType(result.type)) ||
1837 (allowAttrs && parseOptionalAttrDict(attrs)) ||
1838 parseOptionalLocationSpecifier(result.sourceLoc))
1846 bool allowAttrs)
override {
1847 if (parser.getToken().is(Token::percent_identifier))
1848 return parseArgument(result, allowType, allowAttrs);
1849 return std::nullopt;
1853 Delimiter delimiter,
bool allowType,
1854 bool allowAttrs)
override {
1857 parser.getToken().isNot(Token::percent_identifier))
1860 auto parseOneArgument = [&]() -> ParseResult {
1861 return parseArgument(result.emplace_back(), allowType, allowAttrs);
1864 " in argument list");
1874 bool enableNameShadowing)
override {
1876 (void)isIsolatedFromAbove;
1877 assert((!enableNameShadowing || isIsolatedFromAbove) &&
1878 "name shadowing is only allowed on isolated regions");
1879 if (parser.parseRegion(region, arguments, enableNameShadowing))
1887 bool enableNameShadowing)
override {
1888 if (parser.getToken().isNot(Token::l_brace))
1889 return std::nullopt;
1890 return parseRegion(region, arguments, enableNameShadowing);
1897 parseOptionalRegion(std::unique_ptr<Region> ®ion,
1899 bool enableNameShadowing =
false)
override {
1900 if (parser.getToken().isNot(Token::l_brace))
1901 return std::nullopt;
1902 std::unique_ptr<Region> newRegion = std::make_unique<Region>();
1903 if (parseRegion(*newRegion, arguments, enableNameShadowing))
1906 region = std::move(newRegion);
1915 ParseResult parseSuccessor(
Block *&dest)
override {
1916 return parser.parseSuccessor(dest);
1921 if (!parser.getToken().isOrIsCodeCompletionFor(Token::caret_identifier))
1922 return std::nullopt;
1923 return parseSuccessor(dest);
1928 parseSuccessorAndUseList(
Block *&dest,
1930 if (parseSuccessor(dest))
1934 if (succeeded(parseOptionalLParen()) &&
1935 (parser.parseOptionalSSAUseAndTypeList(operands) || parseRParen())) {
1950 if (failed(parseOptionalLParen()))
1951 return std::nullopt;
1953 auto parseElt = [&]() -> ParseResult {
1954 if (parseArgument(lhs.emplace_back()) || parseEqual() ||
1955 parseOperand(rhs.emplace_back()))
1959 return parser.parseCommaSeparatedListUntil(Token::r_paren, parseElt);
1964 parseOptionalLocationSpecifier(std::optional<Location> &result)
override {
1966 if (!parser.consumeIf(Token::kw_loc))
1969 if (parser.parseToken(Token::l_paren,
"expected '(' in location"))
1972 Token tok = parser.getToken();
1978 if (tok.
is(Token::hash_identifier) && !tok.
getSpelling().contains(
'.')) {
1979 if (parser.parseLocationAlias(directLoc))
1981 }
else if (parser.parseLocationInstance(directLoc)) {
1985 if (parser.parseToken(Token::r_paren,
"expected ')' in location"))
1998 bool isIsolatedFromAbove;
2002 OperationParser &parser;
2006 FailureOr<OperationName> OperationParser::parseCustomOperationName() {
2007 Token nameTok = getToken();
2010 return (
emitError(
"empty operation name is invalid"), failure());
2014 std::optional<RegisteredOperationName> opInfo =
2021 auto opNameSplit = opName.split(
'.');
2022 StringRef dialectName = opNameSplit.first;
2023 std::string opNameStorage;
2024 if (opNameSplit.second.empty()) {
2026 if (getToken().isCodeCompletion() && opName.back() ==
'.')
2027 return codeCompleteOperationName(dialectName);
2029 dialectName = getState().defaultDialectStack.back();
2030 opNameStorage = (dialectName +
"." + opName).str();
2031 opName = opNameStorage;
2042 SMLoc opLoc = getToken().
getLoc();
2043 StringRef originalOpName = getTokenSpelling();
2045 FailureOr<OperationName> opNameInfo = parseCustomOperationName();
2046 if (failed(opNameInfo))
2048 StringRef opName = opNameInfo->getStringRef();
2054 bool isIsolatedFromAbove =
false;
2056 StringRef defaultDialect =
"";
2057 if (
auto opInfo = opNameInfo->getRegisteredInfo()) {
2058 parseAssemblyFn = opInfo->getParseAssemblyFn();
2060 auto *iface = opInfo->getInterface<OpAsmOpInterface>();
2061 if (iface && !iface->getDefaultDialect().empty())
2062 defaultDialect = iface->getDefaultDialect();
2064 std::optional<Dialect::ParseOpHook> dialectHook;
2065 Dialect *dialect = opNameInfo->getDialect();
2068 emitError(opLoc) <<
"Dialect `" << opNameInfo->getDialectNamespace()
2069 <<
"' not found for custom op '" << originalOpName
2071 if (originalOpName != opName)
2072 diag <<
" (tried '" << opName <<
"' as well)";
2073 auto ¬e =
diag.attachNote();
2074 note <<
"Registered dialects: ";
2075 llvm::interleaveComma(
getContext()->getAvailableDialects(), note,
2076 [&](StringRef dialect) { note << dialect; });
2077 note <<
" ; for more info on dialect registration see "
2078 "https://mlir.llvm.org/getting_started/Faq/"
2079 "#registered-loaded-dependent-whats-up-with-dialects-management";
2085 emitError(opLoc) <<
"custom op '" << originalOpName <<
"' is unknown";
2086 if (originalOpName != opName)
2087 diag <<
" (tried '" << opName <<
"' as well)";
2090 parseAssemblyFn = *dialectHook;
2092 getState().defaultDialectStack.push_back(defaultDialect);
2093 auto restoreDefaultDialect = llvm::make_scope_exit(
2094 [&]() { getState().defaultDialectStack.pop_back(); });
2098 llvm::PrettyStackTraceFormat fmt(
"MLIR Parser: custom op parser '%s'",
2099 opNameInfo->getIdentifier().data());
2102 auto srcLocation = getEncodedSourceLocation(opLoc);
2107 state.asmState->startOperationDefinition(opState.
name);
2110 CleanupOpStateRegions guard{opState};
2111 CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn,
2112 isIsolatedFromAbove, opName, *
this);
2113 if (opAsmParser.parseOperation(opState))
2117 if (opAsmParser.didEmitError())
2125 if (parseTrailingLocationSpecifier(op))
2141 ParseResult OperationParser::parseLocationAlias(
LocationAttr &loc) {
2142 Token tok = getToken();
2143 consumeToken(Token::hash_identifier);
2144 StringRef identifier = tok.
getSpelling().drop_front();
2145 assert(!identifier.contains(
'.') &&
2146 "unexpected dialect attribute token, expected alias");
2149 state.asmState->addAttrAliasUses(identifier, tok.
getLocRange());
2152 Attribute attr = state.symbols.attributeAliasDefinitions.lookup(identifier);
2154 if (!(loc = dyn_cast<LocationAttr>(attr)))
2156 <<
"expected location, but found '" << attr <<
"'";
2161 TypeID::get<DeferredLocInfo *>(),
2163 deferredLocsReferences.push_back(DeferredLocInfo{tok.
getLoc(), identifier});
2169 OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) {
2171 if (!consumeIf(Token::kw_loc))
2173 if (parseToken(Token::l_paren,
"expected '(' in location"))
2175 Token tok = getToken();
2181 if (tok.
is(Token::hash_identifier) && !tok.
getSpelling().contains(
'.')) {
2182 if (parseLocationAlias(directLoc))
2184 }
else if (parseLocationInstance(directLoc)) {
2188 if (parseToken(Token::r_paren,
"expected ')' in location"))
2191 if (
auto *op = llvm::dyn_cast_if_present<Operation *>(opOrArgument))
2194 cast<BlockArgument>(opOrArgument).setLoc(directLoc);
2202 ParseResult OperationParser::parseRegion(
Region ®ion,
2204 bool isIsolatedNameScope) {
2206 Token lBraceTok = getToken();
2207 if (parseToken(Token::l_brace,
"expected '{' to begin a region"))
2212 state.asmState->startRegionDefinition();
2215 if ((!entryArguments.empty() || getToken().isNot(Token::r_brace)) &&
2216 parseRegionBody(region, lBraceTok.
getLoc(), entryArguments,
2217 isIsolatedNameScope)) {
2220 consumeToken(Token::r_brace);
2224 state.asmState->finalizeRegionDefinition();
2229 ParseResult OperationParser::parseRegionBody(
Region ®ion, SMLoc startLoc,
2231 bool isIsolatedNameScope) {
2232 auto currentPt = opBuilder.saveInsertionPoint();
2235 pushSSANameScope(isIsolatedNameScope);
2238 auto owningBlock = std::make_unique<Block>();
2239 auto failureCleanup = llvm::make_scope_exit([&] {
2244 owningBlock->dropAllDefinedValueUses();
2247 Block *block = owningBlock.get();
2252 if (state.asmState && getToken().isNot(Token::caret_identifier))
2253 state.asmState->addDefinition(block, startLoc);
2256 if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) {
2258 if (getToken().is(Token::caret_identifier))
2259 return emitError(
"invalid block name in region with named arguments");
2261 for (
auto &entryArg : entryArguments) {
2262 auto &argInfo = entryArg.ssaName;
2265 if (
auto defLoc = getReferenceLoc(argInfo.name, argInfo.number)) {
2266 return emitError(argInfo.location,
"region entry argument '" +
2268 "' is already in use")
2269 .
attachNote(getEncodedSourceLocation(*defLoc))
2270 <<
"previously referenced here";
2272 Location loc = entryArg.sourceLoc.has_value()
2273 ? *entryArg.sourceLoc
2274 : getEncodedSourceLocation(argInfo.location);
2279 state.asmState->addDefinition(arg, argInfo.location);
2282 if (addDefinition(argInfo, arg))
2287 if (parseBlock(block))
2291 if (!entryArguments.empty() &&
2292 block->getNumArguments() > entryArguments.size()) {
2293 return emitError(
"entry block arguments were already defined");
2297 region.
push_back(owningBlock.release());
2298 while (getToken().isNot(Token::r_brace)) {
2299 Block *newBlock =
nullptr;
2300 if (parseBlock(newBlock))
2306 if (popSSANameScope())
2310 opBuilder.restoreInsertionPoint(currentPt);
2325 ParseResult OperationParser::parseBlock(
Block *&block) {
2328 if (block && getToken().isNot(Token::caret_identifier))
2329 return parseBlockBody(block);
2331 SMLoc nameLoc = getToken().getLoc();
2332 auto name = getTokenSpelling();
2333 if (parseToken(Token::caret_identifier,
"expected block name"))
2337 auto &blockAndLoc = getBlockInfoByName(name);
2338 blockAndLoc.loc = nameLoc;
2343 std::unique_ptr<Block> inflightBlock;
2344 auto cleanupOnFailure = llvm::make_scope_exit([&] {
2346 inflightBlock->dropAllDefinedValueUses();
2351 if (!blockAndLoc.block) {
2353 blockAndLoc.block = block;
2355 inflightBlock = std::make_unique<Block>();
2356 blockAndLoc.block = inflightBlock.get();
2363 }
else if (!eraseForwardRef(blockAndLoc.block)) {
2364 return emitError(nameLoc,
"redefinition of block '") << name <<
"'";
2368 inflightBlock.reset(blockAndLoc.block);
2373 state.asmState->addDefinition(blockAndLoc.block, nameLoc);
2374 block = blockAndLoc.block;
2377 if (getToken().is(Token::l_paren))
2378 if (parseOptionalBlockArgList(block))
2380 if (parseToken(Token::colon,
"expected ':' after block name"))
2384 ParseResult res = parseBlockBody(block);
2389 (void)inflightBlock.release();
2393 ParseResult OperationParser::parseBlockBody(
Block *block) {
2395 opBuilder.setInsertionPointToEnd(block);
2398 while (getToken().isNot(Token::caret_identifier, Token::r_brace))
2399 if (parseOperation())
2408 Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
2409 BlockDefinition &blockDef = getBlockInfoByName(name);
2410 if (!blockDef.block) {
2411 blockDef = {
new Block(), loc};
2412 insertForwardRef(blockDef.block, blockDef.loc);
2417 state.asmState->addUses(blockDef.block, loc);
2419 return blockDef.block;
2428 ParseResult OperationParser::parseOptionalBlockArgList(
Block *owner) {
2429 if (getToken().is(Token::r_brace))
2435 unsigned nextArgument = 0;
2438 return parseSSADefOrUseAndType(
2439 [&](UnresolvedOperand useInfo,
Type type) -> ParseResult {
2444 if (definingExistingArgs) {
2447 return emitError(
"too many arguments specified in argument list");
2452 return emitError(
"argument and block argument type mismatch");
2454 auto loc = getEncodedSourceLocation(useInfo.location);
2460 if (parseTrailingLocationSpecifier(arg))
2466 state.asmState->addDefinition(arg, useInfo.location);
2468 return addDefinition(useInfo, arg);
2477 ParseResult OperationParser::codeCompleteSSAUse() {
2478 for (IsolatedSSANameScope &scope : isolatedNameScopes) {
2479 for (
auto &it : scope.values) {
2480 if (it.second.empty())
2482 Value frontValue = it.second.front().value;
2484 std::string detailData;
2485 llvm::raw_string_ostream detailOS(detailData);
2489 if (
auto result = dyn_cast<OpResult>(frontValue)) {
2490 if (!forwardRefPlaceholders.count(result))
2491 detailOS << result.getOwner()->getName() <<
": ";
2493 detailOS <<
"arg #" << cast<BlockArgument>(frontValue).getArgNumber()
2498 detailOS << frontValue.
getType();
2503 if (it.second.size() > 1)
2504 detailOS <<
", ...";
2506 state.codeCompleteContext->appendSSAValueCompletion(
2507 it.getKey(), std::move(detailData));
2514 ParseResult OperationParser::codeCompleteBlock() {
2517 StringRef spelling = getTokenSpelling();
2518 if (!(spelling.empty() || spelling ==
"^"))
2521 for (
const auto &it : blocksByName.back())
2522 state.codeCompleteContext->appendBlockCompletion(it.getFirst());
2533 class TopLevelOperationParser :
public Parser {
2545 ParseResult parseAttributeAliasDef();
2551 ParseResult parseTypeAliasDef();
2557 ParseResult parseFileMetadataDictionary();
2560 ParseResult parseResourceFileMetadata(
2561 function_ref<ParseResult(StringRef, SMLoc)> parseBody);
2562 ParseResult parseDialectResourceFileMetadata();
2563 ParseResult parseExternalResourceFileMetadata();
2570 ParsedResourceEntry(std::string key, SMLoc keyLoc,
Token value,
Parser &p)
2571 : key(std::move(key)), keyLoc(keyLoc), value(value), p(p) {}
2572 ~ParsedResourceEntry()
override =
default;
2574 StringRef getKey() const final {
return key; }
2579 if (value.isAny(Token::kw_true, Token::kw_false))
2581 return value.getSpelling().starts_with(
"\"0x")
2586 FailureOr<bool> parseAsBool() const final {
2587 if (value.is(Token::kw_true))
2589 if (value.is(Token::kw_false))
2591 return p.emitError(value.getLoc(),
2592 "expected 'true' or 'false' value for key '" + key +
2596 FailureOr<std::string> parseAsString() const final {
2597 if (value.isNot(Token::string))
2598 return p.emitError(value.getLoc(),
2599 "expected string value for key '" + key +
"'");
2600 return value.getStringValue();
2603 FailureOr<AsmResourceBlob>
2604 parseAsBlob(BlobAllocatorFn allocator)
const final {
2608 std::optional<std::string> blobData =
2609 value.is(Token::string) ? value.getHexStringValue() : std::nullopt;
2611 return p.emitError(value.getLoc(),
2612 "expected hex string blob for key '" + key +
"'");
2616 if (blobData->size() <
sizeof(uint32_t)) {
2617 return p.emitError(value.getLoc(),
2618 "expected hex string blob for key '" + key +
2619 "' to encode alignment in first 4 bytes");
2621 llvm::support::ulittle32_t align;
2622 memcpy(&align, blobData->data(),
sizeof(uint32_t));
2623 if (align && !llvm::isPowerOf2_32(align)) {
2624 return p.emitError(value.getLoc(),
2625 "expected hex string blob for key '" + key +
2626 "' to encode alignment in first 4 bytes, but got "
2627 "non-power-of-2 value: " +
2632 StringRef data = StringRef(*blobData).drop_front(
sizeof(uint32_t));
2639 assert(llvm::isAddrAligned(llvm::Align(align), blob.
getData().data()) &&
2641 "blob allocator did not return a properly aligned address");
2654 ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
2655 assert(getToken().is(Token::hash_identifier));
2656 StringRef aliasName = getTokenSpelling().drop_front();
2659 if (state.symbols.attributeAliasDefinitions.count(aliasName) > 0)
2660 return emitError(
"redefinition of attribute alias id '" + aliasName +
"'");
2663 if (aliasName.contains(
'.'))
2664 return emitError(
"attribute names with a '.' are reserved for "
2665 "dialect-defined names");
2667 SMRange location = getToken().getLocRange();
2668 consumeToken(Token::hash_identifier);
2671 if (parseToken(Token::equal,
"expected '=' in attribute alias definition"))
2681 state.asmState->addAttrAliasDefinition(aliasName, location, attr);
2682 state.symbols.attributeAliasDefinitions[aliasName] = attr;
2686 ParseResult TopLevelOperationParser::parseTypeAliasDef() {
2687 assert(getToken().is(Token::exclamation_identifier));
2688 StringRef aliasName = getTokenSpelling().drop_front();
2691 if (state.symbols.typeAliasDefinitions.count(aliasName) > 0)
2692 return emitError(
"redefinition of type alias id '" + aliasName +
"'");
2695 if (aliasName.contains(
'.'))
2696 return emitError(
"type names with a '.' are reserved for "
2697 "dialect-defined names");
2699 SMRange location = getToken().getLocRange();
2700 consumeToken(Token::exclamation_identifier);
2703 if (parseToken(Token::equal,
"expected '=' in type alias definition"))
2713 state.asmState->addTypeAliasDefinition(aliasName, location, aliasedType);
2714 state.symbols.typeAliasDefinitions.try_emplace(aliasName, aliasedType);
2718 ParseResult TopLevelOperationParser::parseFileMetadataDictionary() {
2719 consumeToken(Token::file_metadata_begin);
2720 return parseCommaSeparatedListUntil(
2721 Token::file_metadata_end, [&]() -> ParseResult {
2723 SMLoc keyLoc = getToken().getLoc();
2725 if (failed(parseOptionalKeyword(&key)))
2726 return emitError(
"expected identifier key in file "
2727 "metadata dictionary");
2728 if (parseToken(Token::colon,
"expected ':'"))
2732 if (key ==
"dialect_resources")
2733 return parseDialectResourceFileMetadata();
2734 if (key ==
"external_resources")
2735 return parseExternalResourceFileMetadata();
2736 return emitError(keyLoc,
"unknown key '" + key +
2737 "' in file metadata dictionary");
2741 ParseResult TopLevelOperationParser::parseResourceFileMetadata(
2742 function_ref<ParseResult(StringRef, SMLoc)> parseBody) {
2743 if (parseToken(Token::l_brace,
"expected '{'"))
2746 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2748 SMLoc nameLoc = getToken().getLoc();
2750 if (failed(parseOptionalKeyword(&name)))
2751 return emitError(
"expected identifier key for 'resource' entry");
2753 if (parseToken(Token::colon,
"expected ':'") ||
2754 parseToken(Token::l_brace,
"expected '{'"))
2756 return parseBody(name, nameLoc);
2760 ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() {
2761 return parseResourceFileMetadata([&](StringRef name,
2762 SMLoc nameLoc) -> ParseResult {
2766 return emitError(nameLoc,
"dialect '" + name +
"' is unknown");
2767 const auto *handler = dyn_cast<OpAsmDialectInterface>(dialect);
2769 return emitError() <<
"unexpected 'resource' section for dialect '"
2773 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2775 SMLoc keyLoc = getToken().getLoc();
2777 if (failed(parseResourceHandle(handler, key)) ||
2778 parseToken(Token::colon,
"expected ':'"))
2780 Token valueTok = getToken();
2783 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2784 return handler->parseResource(entry);
2789 ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() {
2790 return parseResourceFileMetadata([&](StringRef name,
2791 SMLoc nameLoc) -> ParseResult {
2797 <<
"ignoring unknown external resources for '" << name <<
"'";
2800 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2802 SMLoc keyLoc = getToken().getLoc();
2804 if (failed(parseOptionalKeywordOrString(&key)))
2806 "expected identifier key for 'external_resources' entry");
2807 if (parseToken(Token::colon,
"expected ':'"))
2809 Token valueTok = getToken();
2814 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2824 OperationParser opParser(state, topLevelOp.get());
2826 switch (getToken().getKind()) {
2829 if (opParser.parseOperation())
2835 if (opParser.finalize())
2840 auto &parsedOps = topLevelOp->getBody()->getOperations();
2842 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(),
2854 case Token::hash_identifier:
2855 if (parseAttributeAliasDef())
2860 case Token::exclamation_identifier:
2861 if (parseTypeAliasDef())
2866 case Token::file_metadata_begin:
2867 if (parseFileMetadataDictionary())
2880 const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
2888 codeCompleteContext);
2889 return TopLevelOperationParser(state).parse(block, parserLoc);
static void toLower(char *token)
Helper to convert C-style strings (i.e., '\0' terminated) to lower case.
static MLIRContext * getContext(OpFoldResult val)
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)
Base type for affine expression.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
This class represents a single parsed resource entry.
This class provides an abstract interface into the parser for hooking in code completion events.
virtual void completeExpectedTokens(ArrayRef< StringRef > tokens, bool optional)=0
Signal a completion for the given expected tokens, which are optional if optional is set.
virtual void completeAttribute(const llvm::StringMap< Attribute > &aliases)=0
Signal a completion for an attribute.
virtual void completeDialectAttributeOrAlias(const llvm::StringMap< Attribute > &aliases)=0
virtual void completeType(const llvm::StringMap< Type > &aliases)=0
Signal a completion for a type.
virtual void completeOperationName(StringRef dialectName)=0
Signal code completion for an operation name within the given dialect.
virtual void completeDialectName(StringRef prefix)=0
Signal code completion for a dialect name, with an optional prefix.
virtual void completeDialectTypeOrAlias(const llvm::StringMap< Type > &aliases)=0
virtual ~AsmParserCodeCompleteContext()
This class represents state from a parsed MLIR textual format string.
void initialize(Operation *topLevelOp)
Initialize the state in preparation for populating more parser state under the given top-level operat...
Delimiter
These are the supported delimiters around operand lists and region argument lists,...
@ Paren
Parens surrounding zero or more operands.
@ None
Zero or more operands with no delimiters.
@ OptionalLessGreater
<> brackets supporting zero or more ops, or nothing.
@ Braces
{} brackets surrounding zero or more operands.
@ OptionalBraces
{} brackets surrounding zero or more operands, or nothing.
@ OptionalParen
Parens supporting zero or more operands, or nothing.
@ Square
Square brackets surrounding zero or more operands.
@ LessGreater
<> brackets surrounding zero or more operands.
@ OptionalSquare
Square brackets supporting zero or more ops, or nothing.
This class represents a processed binary blob of data.
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.
This class represents an instance of a resource parser.
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry)=0
Parse the given resource entry.
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
OpListType::iterator iterator
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
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.
OpListType & getOperations()
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.
Diagnostic & attachNote(std::optional< Location > noteLoc=std::nullopt)
Attaches a note to this diagnostic.
InFlightDiagnostic & append(Args &&...args) &
Append arguments to the diagnostic.
void resetPointer(const char *newPointer)
Change the position of the lexer cursor.
const char * getBufferBegin()
Returns the start of the buffer.
Location objects represent source locations information in MLIR.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
void push_back(NamedAttribute newAttribute)
Add an attribute with the specified name.
std::optional< NamedAttribute > findDuplicate() const
Returns an entry with a duplicate name the list, if it exists, else returns std::nullopt.
virtual std::string getResourceKey(const AsmDialectResourceHandle &handle) const
Return a key to use for the given resource.
virtual FailureOr< AsmDialectResourceHandle > declareResource(StringRef key) const
Declare a resource with the given key, returning a handle to use for any references of this resource ...
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
This class provides the API for ops that are known to be isolated from above.
This class provides the API for ops that are known to be terminators.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
llvm::unique_function< ParseResult(OpAsmParser &, OperationState &)> ParseAssemblyFn
std::optional< RegisteredOperationName > getRegisteredInfo() const
If this operation is registered, returns the registered information, std::nullopt otherwise.
bool mightHaveTrait() const
Returns true if the operation might have the provided trait.
bool isRegistered() const
Return if this operation is registered.
Operation is the basic unit of execution within MLIR.
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.
Location getLoc()
The source location the operation was defined or derived from.
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, OpaqueProperties properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
MutableArrayRef< Region > getRegions()
Returns the regions held by 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.
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.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
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.
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.
Location getLoc() const
Return the location 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'.
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.
ParserState & getState() const
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.
StringRef getTokenSpelling() 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)
llvm::PointerUnion< NamedAttribute *, NamedProperty *, NamedTypeConstraint * > Argument
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 ...
const FrozenRewritePatternSet GreedyRewriteConfig config
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.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
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.
AsmResourceEntryKind
This enum represents the different kinds of resource values.
@ Blob
A blob of data with an accompanying alignment.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
This is the representation of an operand reference.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
void addRegions(MutableArrayRef< std::unique_ptr< Region >> regions)
Take ownership of a set of regions that should be attached to the Operation.
OpaqueProperties getRawProperties()
SmallVector< Value, 4 > operands
void addAttributes(ArrayRef< NamedAttribute > newAttributes)
Add an array of named attributes.
void addSuccessors(Block *successor)
Adds a successor to the operation sate. successor must not be null.
void addTypes(ArrayRef< Type > newTypes)
SmallVector< std::unique_ptr< Region >, 1 > regions
Regions that the op will hold.
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.
Lexer lex
The lexer for the source file we're parsing.
Token curToken
This is the next token that hasn't been consumed yet.
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.
SmallVector< StringRef > defaultDialectStack
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.