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);
216 auto loc =
state.curToken.getLoc();
219 if (
state.curToken.is(Token::eof))
220 loc = SMLoc::getFromPointer(loc.getPointer() - 1);
223 auto originalLoc = loc;
226 const char *bufferStart =
state.lex.getBufferBegin();
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))
325 if (curToken.
isNot(Token::integer, Token::minus)) {
331 if (
parseToken(Token::integer,
"expected integer value")) {
339 if (spelling[0] ==
'0' && spelling.size() > 1 &&
340 llvm::toLower(spelling[1]) ==
'x') {
342 state.lex.resetPointer(spelling.data() + 1);
347 if (spelling.getAsInteger(10,
result))
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,
411 ArrayRef(intValue.getRawData(), intValue.getNumWords()));
412 result.emplace(semantics, truncatedValue);
440FailureOr<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()) {
458 <<
"unknown 'resource' key '" << name <<
"' for dialect '"
469FailureOr<AsmDialectResourceHandle>
474 <<
"' does not expect resource handles";
476 std::string resourceName;
485 state.codeCompleteContext->completeDialectName();
493 if (dialectName.empty() || dialectName.contains(
'.'))
495 state.codeCompleteContext->completeOperationName(dialectName);
504 auto shouldIgnoreOpCompletion = [&]() {
505 const char *bufBegin =
state.lex.getBufferBegin();
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(
"."))
536 state.codeCompleteContext->completeExpectedTokens(tokens,
false);
540 state.codeCompleteContext->completeExpectedTokens(tokens,
true);
545 state.codeCompleteContext->completeAttribute(
546 state.symbols.attributeAliasDefinitions);
550 state.codeCompleteContext->completeType(
state.symbols.typeAliasDefinitions);
556 state.codeCompleteContext->completeDialectAttributeOrAlias(aliases);
560 state.codeCompleteContext->completeDialectTypeOrAlias(aliases);
571class 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);
641 ParseResult parseSuccessors(SmallVectorImpl<Block *> &destinations);
644 Operation *parseGenericOperation();
651 ParseResult parseGenericOperationAfterOpName(
653 std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo =
655 std::optional<ArrayRef<Block *>> parsedSuccessors = std::nullopt,
656 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions =
658 std::optional<ArrayRef<NamedAttribute>> parsedAttributes = std::nullopt,
659 std::optional<Attribute> propertiesAttribute = std::nullopt,
660 std::optional<FunctionType> parsedFnType = std::nullopt);
664 Operation *parseGenericOperation(
Block *insertBlock,
670 using OpOrArgument = llvm::PointerUnion<Operation *, BlockArgument>;
677 ParseResult parseTrailingLocationSpecifier(OpOrArgument opOrArgument);
683 ParseResult parseLocationAlias(LocationAttr &loc);
687 using ResultRecord = std::tuple<StringRef, unsigned, SMLoc>;
691 Operation *parseCustomOperation(ArrayRef<ResultRecord> resultIDs);
695 FailureOr<OperationName> parseCustomOperationName();
704 ParseResult parseRegion(Region ®ion, ArrayRef<Argument> entryArguments,
705 bool isIsolatedNameScope =
false);
708 ParseResult parseRegionBody(Region ®ion, SMLoc startLoc,
709 ArrayRef<Argument> entryArguments,
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);
774 SmallVectorImpl<ValueDefinition> &getSSAValueEntry(StringRef name);
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;
809 SmallVector<llvm::StringSet<>, 2> definitionsPerScope;
813 SmallVector<IsolatedSSANameScope, 2> isolatedNameScopes;
818 SmallVector<DenseMap<StringRef, BlockDefinition>, 2> blocksByName;
819 SmallVector<DenseMap<Block *, SMLoc>, 2> forwardRef;
834 std::vector<DeferredLocInfo> deferredLocsReferences;
840 Operation *topLevelOp;
847OperationParser::OperationParser(
ParserState &state, ModuleOp topLevelOp)
848 :
Parser(state), opBuilder(topLevelOp.getRegion()), topLevelOp(topLevelOp) {
850 pushSSANameScope(
true);
854 state.asmState->initialize(topLevelOp);
857OperationParser::~OperationParser() {
858 for (Operation *op : forwardRefOps) {
864 for (
const auto &scope : forwardRef) {
865 for (
const auto &fwd : scope) {
868 fwd.first->dropAllUses();
876ParseResult OperationParser::finalize() {
879 if (!forwardRefPlaceholders.empty()) {
880 SmallVector<const char *, 4> errors;
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");
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()))
944void OperationParser::pushSSANameScope(
bool isIsolated) {
950 isolatedNameScopes.push_back({});
951 isolatedNameScopes.back().pushSSANameScope();
954ParseResult OperationParser::popSSANameScope() {
955 auto forwardRefInCurrentScope = forwardRef.pop_back_val();
958 if (!forwardRefInCurrentScope.empty()) {
959 SmallVector<std::pair<const char *, Block *>, 4> errors;
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();
988ParseResult 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);
1027 entries[useInfo.number] = {value, useInfo.location};
1028 recordDefinition(useInfo.name);
1037ParseResult OperationParser::parseOptionalSSAUseList(
1038 SmallVectorImpl<UnresolvedOperand> &results) {
1039 if (!getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
1042 UnresolvedOperand
result;
1045 results.push_back(
result);
1054ParseResult 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())
1073 return emitError(
"invalid SSA value result number");
1074 consumeToken(Token::hash_identifier);
1082Value OperationParser::resolveSSAUse(UnresolvedOperand useInfo, Type type) {
1083 auto &entries = getSSAValueEntry(useInfo.name);
1087 auto maybeRecordUse = [&](Value value) {
1094 if (useInfo.number < entries.size() && entries[useInfo.number].value) {
1095 Value
result = entries[useInfo.number].value;
1097 if (
result.getType() == type)
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);
1129ParseResult OperationParser::parseSSADefOrUseAndType(
1130 function_ref<ParseResult(UnresolvedOperand, Type)> action) {
1131 UnresolvedOperand useInfo;
1132 if (parseSSAUse(useInfo) ||
1133 parseToken(Token::colon,
"expected ':' and type for SSA operand"))
1140 return action(useInfo, type);
1149ParseResult OperationParser::parseOptionalSSAUseAndTypeList(
1150 SmallVectorImpl<Value> &results) {
1151 SmallVector<UnresolvedOperand, 4> valueIDs;
1152 if (parseOptionalSSAUseList(valueIDs))
1156 if (valueIDs.empty())
1159 SmallVector<Type, 4> types;
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);
1180void OperationParser::recordDefinition(StringRef def) {
1181 isolatedNameScopes.back().recordDefinition(def);
1185auto OperationParser::getSSAValueEntry(StringRef name)
1186 -> SmallVectorImpl<ValueDefinition> & {
1187 return isolatedNameScopes.back().values[name];
1191Value OperationParser::createForwardRefPlaceholder(SMLoc loc, Type type) {
1198 auto name = OperationName(
"builtin.unrealized_conversion_cast",
getContext());
1200 getEncodedSourceLocation(loc), name, type, {},
1201 NamedAttrList(),
nullptr,
1203 forwardRefPlaceholders[op->
getResult(0)] = loc;
1204 forwardRefOps.insert(op);
1224ParseResult OperationParser::parseOperation() {
1225 auto loc = getToken().getLoc();
1226 SmallVector<ResultRecord, 1> resultIDs;
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";
1293 unsigned resultIt = 0;
1294 SmallVector<std::pair<unsigned, SMLoc>> asmResultGroups;
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);
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},
1319 getLastToken().getEndLoc());
1329ParseResult 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());
1346OperationParser::parseSuccessors(SmallVectorImpl<Block *> &destinations) {
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,
1365struct CleanupOpStateRegions {
1366 ~CleanupOpStateRegions() {
1367 SmallVector<Region *, 4> regionsToClean;
1368 regionsToClean.reserve(state.regions.size());
1369 for (
auto ®ion : state.regions)
1371 for (
auto &block : *region)
1374 OperationState &state;
1378ParseResult OperationParser::parseGenericOperationAfterOpName(
1380 std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo,
1381 std::optional<ArrayRef<Block *>> parsedSuccessors,
1382 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1383 std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1384 std::optional<Attribute> propertiesAttribute,
1385 std::optional<FunctionType> parsedFnType) {
1388 SmallVector<UnresolvedOperand, 8> opInfo;
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)) {
1402 if (!
result.name.mightHaveTrait<OpTrait::IsTerminator>())
1403 return emitError(
"successors in non-terminator");
1405 SmallVector<Block *, 2> successors;
1406 if (parseSuccessors(successors))
1408 result.addSuccessors(successors);
1411 result.addSuccessors(*parsedSuccessors);
1415 if (propertiesAttribute) {
1416 result.propertiesAttr = *propertiesAttribute;
1417 }
else if (consumeIf(Token::less)) {
1419 if (!
result.propertiesAttr)
1421 if (parseToken(Token::greater,
"expected '>' to close properties"))
1425 if (!parsedRegions) {
1426 if (consumeIf(Token::l_paren)) {
1429 result.regions.emplace_back(
new Region(topLevelOp));
1430 if (parseRegion(*
result.regions.back(), {}))
1432 }
while (consumeIf(Token::comma));
1433 if (parseToken(Token::r_paren,
"expected ')' to end region list"))
1437 result.addRegions(*parsedRegions);
1441 if (!parsedAttributes) {
1442 if (getToken().is(Token::l_brace)) {
1443 if (parseAttributeDict(
result.attributes))
1447 result.addAttributes(*parsedAttributes);
1451 Location typeLoc =
result.location;
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());
1470 ArrayRef<Type> operandTypes = parsedFnType->getInputs();
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) {
1480 result.operands.push_back(
1481 resolveSSAUse((*parsedOperandUseInfo)[i], operandTypes[i]));
1482 if (!
result.operands.back())
1489Operation *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);
1501 OperationState
result(srcLocation, name);
1502 CleanupOpStateRegions guard{
result};
1505 if (!
result.name.isRegistered()) {
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");
1527 if (parseGenericOperationAfterOpName(
result))
1533 Attribute properties;
1534 std::swap(properties,
result.propertiesAttr);
1550 if (!properties && !
result.getRawProperties()) {
1551 std::optional<RegisteredOperationName> info =
1552 result.name.getRegisteredInfo();
1554 if (
failed(info->verifyInherentAttrs(
result.attributes, [&]() {
1555 return mlir::emitError(srcLocation) <<
"'" << name <<
"' op ";
1563 if (parseTrailingLocationSpecifier(op))
1571 << properties <<
" for op " << name <<
": ";
1580Operation *OperationParser::parseGenericOperation(
Block *insertBlock,
1582 Token nameToken = getToken();
1584 OpBuilder::InsertionGuard restoreInsertionPoint(opBuilder);
1585 opBuilder.setInsertionPoint(insertBlock, insertPt);
1586 Operation *op = parseGenericOperation();
1595 getLastToken().getEndLoc());
1600class CustomOpAsmParser :
public AsmParserImpl<OpAsmParser> {
1603 SMLoc nameLoc, ArrayRef<OperationParser::ResultRecord> resultIDs,
1604 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly,
1605 bool isIsolatedFromAbove, StringRef opName, OperationParser &parser)
1606 : AsmParserImpl<OpAsmParser>(nameLoc, parser), resultIDs(resultIDs),
1607 parseAssembly(parseAssembly), isIsolatedFromAbove(isIsolatedFromAbove),
1608 opName(opName), parser(parser) {
1609 (void)isIsolatedFromAbove;
1614 ParseResult parseOperation(OperationState &opState) {
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";
1630 Operation *parseGenericOperation(
Block *insertBlock,
1632 return parser.parseGenericOperation(insertBlock, insertPt);
1635 FailureOr<OperationName> parseCustomOperationName() final {
1636 return parser.parseCustomOperationName();
1639 ParseResult parseGenericOperationAfterOpName(
1641 std::optional<ArrayRef<UnresolvedOperand>> parsedUnresolvedOperands,
1642 std::optional<ArrayRef<Block *>> parsedSuccessors,
1643 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1644 std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
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);
1690 InFlightDiagnostic
emitError(SMLoc loc,
const Twine &message)
override {
1700 ParseResult parseOperand(UnresolvedOperand &
result,
1701 bool allowResultNumber =
true)
override {
1702 OperationParser::UnresolvedOperand useInfo;
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;
1721 ParseResult parseOperandList(SmallVectorImpl<UnresolvedOperand> &
result,
1722 Delimiter delimiter = Delimiter::None,
1723 bool allowResultNumber =
true,
1724 int requiredOperandCount = -1)
override {
1726 if (delimiter == Delimiter::None) {
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,
1761 SmallVectorImpl<Value> &
result)
override {
1762 if (
auto value = parser.resolveSSAUse(operand, type)) {
1771 parseAffineMapOfSSAIds(SmallVectorImpl<UnresolvedOperand> &operands,
1772 Attribute &mapAttr, StringRef attrName,
1773 NamedAttrList &attrs, Delimiter delimiter)
override {
1774 SmallVector<UnresolvedOperand, 2> dimOperands;
1775 SmallVector<UnresolvedOperand, 1> symOperands;
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))
1793 mapAttr = AffineMapAttr::get(map);
1794 attrs.
push_back(parser.builder.getNamedAttr(attrName, mapAttr));
1798 operands.assign(dimOperands.begin(), dimOperands.end());
1799 operands.append(symOperands.begin(), symOperands.end());
1805 parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands,
1806 SmallVectorImpl<UnresolvedOperand> &symbOperands,
1807 AffineExpr &expr)
override {
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 {
1834 NamedAttrList attrs;
1835 if (parseOperand(
result.ssaName,
false) ||
1836 (allowType && parseColonType(
result.type)) ||
1837 (allowAttrs && parseOptionalAttrDict(attrs)) ||
1838 parseOptionalLocationSpecifier(
result.sourceLoc))
1845 OptionalParseResult parseOptionalArgument(Argument &
result,
bool allowType,
1846 bool allowAttrs)
override {
1847 if (parser.getToken().is(Token::percent_identifier))
1848 return parseArgument(
result, allowType, allowAttrs);
1849 return std::nullopt;
1852 ParseResult parseArgumentList(SmallVectorImpl<Argument> &
result,
1853 Delimiter delimiter,
bool allowType,
1854 bool allowAttrs)
override {
1856 if (delimiter == Delimiter::None &&
1857 parser.getToken().isNot(Token::percent_identifier))
1860 auto parseOneArgument = [&]() -> ParseResult {
1861 return parseArgument(
result.emplace_back(), allowType, allowAttrs);
1864 " in argument list");
1873 ParseResult parseRegion(Region ®ion, ArrayRef<Argument> arguments,
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))
1885 OptionalParseResult parseOptionalRegion(Region ®ion,
1886 ArrayRef<Argument> arguments,
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,
1898 ArrayRef<Argument> arguments,
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);
1920 OptionalParseResult parseOptionalSuccessor(
Block *&dest)
override {
1921 if (!parser.getToken().isOrIsCodeCompletionFor(Token::caret_identifier))
1922 return std::nullopt;
1923 return parseSuccessor(dest);
1928 parseSuccessorAndUseList(
Block *&dest,
1929 SmallVectorImpl<Value> &operands)
override {
1930 if (parseSuccessor(dest))
1934 if (succeeded(parseOptionalLParen()) &&
1935 (parser.parseOptionalSSAUseAndTypeList(operands) || parseRParen())) {
1947 OptionalParseResult parseOptionalAssignmentList(
1948 SmallVectorImpl<Argument> &
lhs,
1949 SmallVectorImpl<UnresolvedOperand> &
rhs)
override {
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))
1968 LocationAttr directLoc;
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"))
1994 ArrayRef<OperationParser::ResultRecord> resultIDs;
1997 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly;
1998 bool isIsolatedFromAbove;
2002 OperationParser &parser;
2006FailureOr<OperationName> OperationParser::parseCustomOperationName() {
2007 Token nameTok = getToken();
2012 return emitError(
"expected bare identifier or keyword");
2015 return (
emitError(
"empty operation name is invalid"), failure());
2019 std::optional<RegisteredOperationName> opInfo =
2026 auto opNameSplit = opName.split(
'.');
2027 StringRef dialectName = opNameSplit.first;
2028 std::string opNameStorage;
2029 if (opNameSplit.second.empty()) {
2031 if (getToken().isCodeCompletion() && opName.back() ==
'.')
2032 return codeCompleteOperationName(dialectName);
2034 dialectName = getState().defaultDialectStack.back();
2035 opNameStorage = (dialectName +
"." + opName).str();
2036 opName = opNameStorage;
2046OperationParser::parseCustomOperation(ArrayRef<ResultRecord> resultIDs) {
2047 SMLoc opLoc = getToken().getLoc();
2048 StringRef originalOpName = getTokenSpelling();
2050 FailureOr<OperationName> opNameInfo = parseCustomOperationName();
2053 StringRef opName = opNameInfo->getStringRef();
2059 bool isIsolatedFromAbove =
false;
2061 StringRef defaultDialect =
"";
2062 if (
auto opInfo = opNameInfo->getRegisteredInfo()) {
2063 parseAssemblyFn = opInfo->getParseAssemblyFn();
2064 isIsolatedFromAbove = opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>();
2065 auto *iface = opInfo->getInterface<OpAsmOpInterface>();
2066 if (iface && !iface->getDefaultDialect().empty())
2067 defaultDialect = iface->getDefaultDialect();
2069 std::optional<Dialect::ParseOpHook> dialectHook;
2070 Dialect *dialect = opNameInfo->getDialect();
2072 InFlightDiagnostic
diag =
2073 emitError(opLoc) <<
"Dialect `" << opNameInfo->getDialectNamespace()
2074 <<
"' not found for custom op '" << originalOpName
2076 if (originalOpName != opName)
2077 diag <<
" (tried '" << opName <<
"' as well)";
2078 auto ¬e =
diag.attachNote();
2079 note <<
"Available dialects: ";
2080 std::vector<StringRef> registered =
getContext()->getAvailableDialects();
2081 auto loaded =
getContext()->getLoadedDialects();
2084 SmallVector<std::pair<StringRef, bool>> mergedDialects;
2085 auto regIt = registered.begin(), regEnd = registered.end();
2086 auto loadIt = loaded.rbegin(), loadEnd = loaded.rend();
2087 bool isRegistered =
false;
2088 bool isOnlyLoaded =
true;
2089 while (regIt != regEnd && loadIt != loadEnd) {
2090 StringRef reg = *regIt;
2091 StringRef
load = (*loadIt)->getNamespace();
2093 mergedDialects.emplace_back(
load, isOnlyLoaded);
2096 mergedDialects.emplace_back(reg, isRegistered);
2102 for (; regIt != regEnd; ++regIt)
2103 mergedDialects.emplace_back(*regIt, isRegistered);
2104 for (; loadIt != loadEnd; ++loadIt)
2105 mergedDialects.emplace_back((*loadIt)->getNamespace(), isOnlyLoaded);
2107 bool loadedUnregistered =
false;
2108 llvm::interleaveComma(mergedDialects, note, [&](
auto &pair) {
2111 loadedUnregistered =
true;
2116 if (loadedUnregistered)
2117 note <<
"(* corresponding to loaded but unregistered dialects)";
2118 note <<
"; for more info on dialect registration see "
2119 "https://mlir.llvm.org/getting_started/Faq/"
2120 "#registered-loaded-dependent-whats-up-with-dialects-management";
2125 InFlightDiagnostic
diag =
2126 emitError(opLoc) <<
"custom op '" << originalOpName <<
"' is unknown";
2127 if (originalOpName != opName)
2128 diag <<
" (tried '" << opName <<
"' as well)";
2131 parseAssemblyFn = *dialectHook;
2133 getState().defaultDialectStack.push_back(defaultDialect);
2134 auto restoreDefaultDialect = llvm::make_scope_exit(
2135 [&]() { getState().defaultDialectStack.pop_back(); });
2139 llvm::PrettyStackTraceFormat fmt(
"MLIR Parser: custom op parser '%s'",
2140 opNameInfo->getIdentifier().data());
2143 auto srcLocation = getEncodedSourceLocation(opLoc);
2144 OperationState opState(srcLocation, *opNameInfo);
2151 CleanupOpStateRegions guard{opState};
2152 CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn,
2153 isIsolatedFromAbove, opName, *
this);
2154 if (opAsmParser.parseOperation(opState))
2158 if (opAsmParser.didEmitError())
2165 Operation *op = opBuilder.
create(opState);
2166 if (parseTrailingLocationSpecifier(op))
2182ParseResult OperationParser::parseLocationAlias(LocationAttr &loc) {
2183 Token tok = getToken();
2184 consumeToken(Token::hash_identifier);
2185 StringRef identifier = tok.
getSpelling().drop_front();
2186 assert(!identifier.contains(
'.') &&
2187 "unexpected dialect attribute token, expected alias");
2195 if (!(loc = dyn_cast<LocationAttr>(attr)))
2197 <<
"expected location, but found '" << attr <<
"'";
2201 loc = OpaqueLoc::get(deferredLocsReferences.size(),
2204 deferredLocsReferences.push_back(DeferredLocInfo{tok.
getLoc(), identifier});
2210OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) {
2212 if (!consumeIf(Token::kw_loc))
2214 if (parseToken(Token::l_paren,
"expected '(' in location"))
2216 Token tok = getToken();
2221 LocationAttr directLoc;
2222 if (tok.
is(Token::hash_identifier) && !tok.
getSpelling().contains(
'.')) {
2223 if (parseLocationAlias(directLoc))
2225 }
else if (parseLocationInstance(directLoc)) {
2229 if (parseToken(Token::r_paren,
"expected ')' in location"))
2232 if (
auto *op = llvm::dyn_cast_if_present<Operation *>(opOrArgument))
2235 cast<BlockArgument>(opOrArgument).setLoc(directLoc);
2243ParseResult OperationParser::parseRegion(Region ®ion,
2244 ArrayRef<Argument> entryArguments,
2245 bool isIsolatedNameScope) {
2247 Token lBraceTok = getToken();
2248 if (parseToken(Token::l_brace,
"expected '{' to begin a region"))
2256 if ((!entryArguments.empty() || getToken().isNot(Token::r_brace)) &&
2257 parseRegionBody(region, lBraceTok.
getLoc(), entryArguments,
2258 isIsolatedNameScope)) {
2261 consumeToken(Token::r_brace);
2270ParseResult OperationParser::parseRegionBody(Region ®ion, SMLoc startLoc,
2271 ArrayRef<Argument> entryArguments,
2272 bool isIsolatedNameScope) {
2273 auto currentPt = opBuilder.saveInsertionPoint();
2276 pushSSANameScope(isIsolatedNameScope);
2279 auto owningBlock = std::make_unique<Block>();
2280 auto failureCleanup = llvm::make_scope_exit([&] {
2285 owningBlock->dropAllDefinedValueUses();
2288 Block *block = owningBlock.get();
2293 if (state.
asmState && getToken().isNot(Token::caret_identifier))
2297 if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) {
2299 if (getToken().is(Token::caret_identifier))
2300 return emitError(
"invalid block name in region with named arguments");
2302 for (
auto &entryArg : entryArguments) {
2303 auto &argInfo = entryArg.ssaName;
2306 if (
auto defLoc = getReferenceLoc(argInfo.name, argInfo.number)) {
2307 return emitError(argInfo.location,
"region entry argument '" +
2309 "' is already in use")
2310 .
attachNote(getEncodedSourceLocation(*defLoc))
2311 <<
"previously referenced here";
2313 Location loc = entryArg.sourceLoc.has_value()
2314 ? *entryArg.sourceLoc
2315 : getEncodedSourceLocation(argInfo.location);
2316 BlockArgument arg = block->addArgument(entryArg.type, loc);
2323 if (addDefinition(argInfo, arg))
2328 if (parseBlock(block))
2332 if (!entryArguments.empty() &&
2333 block->getNumArguments() > entryArguments.size()) {
2334 return emitError(
"entry block arguments were already defined");
2338 region.
push_back(owningBlock.release());
2339 while (getToken().isNot(Token::r_brace)) {
2340 Block *newBlock =
nullptr;
2341 if (parseBlock(newBlock))
2347 if (popSSANameScope())
2351 opBuilder.restoreInsertionPoint(currentPt);
2366ParseResult OperationParser::parseBlock(
Block *&block) {
2369 if (block && getToken().isNot(Token::caret_identifier))
2370 return parseBlockBody(block);
2372 SMLoc nameLoc = getToken().getLoc();
2373 auto name = getTokenSpelling();
2374 if (parseToken(Token::caret_identifier,
"expected block name"))
2378 auto &blockAndLoc = getBlockInfoByName(name);
2379 blockAndLoc.loc = nameLoc;
2384 std::unique_ptr<Block> inflightBlock;
2385 auto cleanupOnFailure = llvm::make_scope_exit([&] {
2387 inflightBlock->dropAllDefinedValueUses();
2392 if (!blockAndLoc.block) {
2394 blockAndLoc.block = block;
2396 inflightBlock = std::make_unique<Block>();
2397 blockAndLoc.block = inflightBlock.get();
2404 }
else if (!eraseForwardRef(blockAndLoc.block)) {
2405 return emitError(nameLoc,
"redefinition of block '") << name <<
"'";
2409 inflightBlock.reset(blockAndLoc.block);
2415 block = blockAndLoc.block;
2418 if (getToken().is(Token::l_paren))
2419 if (parseOptionalBlockArgList(block))
2421 if (parseToken(Token::colon,
"expected ':' after block name"))
2425 ParseResult res = parseBlockBody(block);
2430 (void)inflightBlock.release();
2434ParseResult OperationParser::parseBlockBody(
Block *block) {
2436 opBuilder.setInsertionPointToEnd(block);
2439 while (getToken().isNot(Token::caret_identifier, Token::r_brace))
2440 if (parseOperation())
2449Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
2450 BlockDefinition &blockDef = getBlockInfoByName(name);
2451 if (!blockDef.block) {
2452 blockDef = {
new Block(), loc};
2453 insertForwardRef(blockDef.block, blockDef.loc);
2460 return blockDef.block;
2469ParseResult OperationParser::parseOptionalBlockArgList(
Block *owner) {
2470 if (getToken().is(Token::r_brace))
2476 unsigned nextArgument = 0;
2479 return parseSSADefOrUseAndType(
2480 [&](UnresolvedOperand useInfo, Type type) -> ParseResult {
2485 if (definingExistingArgs) {
2488 return emitError(
"too many arguments specified in argument list");
2493 return emitError(
"argument and block argument type mismatch");
2495 auto loc = getEncodedSourceLocation(useInfo.location);
2501 if (parseTrailingLocationSpecifier(arg))
2509 return addDefinition(useInfo, arg);
2518ParseResult OperationParser::codeCompleteSSAUse() {
2519 for (IsolatedSSANameScope &scope : isolatedNameScopes) {
2520 for (
auto &it : scope.values) {
2521 if (it.second.empty())
2523 Value frontValue = it.second.front().value;
2525 std::string detailData;
2526 llvm::raw_string_ostream detailOS(detailData);
2530 if (
auto result = dyn_cast<OpResult>(frontValue)) {
2531 if (!forwardRefPlaceholders.count(
result))
2532 detailOS <<
result.getOwner()->getName() <<
": ";
2534 detailOS <<
"arg #" << cast<BlockArgument>(frontValue).getArgNumber()
2539 detailOS << frontValue.
getType();
2544 if (it.second.size() > 1)
2545 detailOS <<
", ...";
2548 it.getKey(), std::move(detailData));
2555ParseResult OperationParser::codeCompleteBlock() {
2558 StringRef spelling = getTokenSpelling();
2559 if (!(spelling.empty() || spelling ==
"^"))
2562 for (
const auto &it : blocksByName.back())
2574class TopLevelOperationParser :
public Parser {
2576 explicit TopLevelOperationParser(ParserState &state) : Parser(state) {}
2579 ParseResult
parse(
Block *topLevelBlock, Location parserLoc);
2586 ParseResult parseAttributeAliasDef();
2592 ParseResult parseTypeAliasDef();
2598 ParseResult parseFileMetadataDictionary();
2601 ParseResult parseResourceFileMetadata(
2602 function_ref<ParseResult(StringRef, SMLoc)> parseBody);
2603 ParseResult parseDialectResourceFileMetadata();
2604 ParseResult parseExternalResourceFileMetadata();
2609class ParsedResourceEntry :
public AsmParsedResourceEntry {
2611 ParsedResourceEntry(std::string key, SMLoc keyLoc, Token value, Parser &p)
2612 : key(std::move(key)), keyLoc(keyLoc), value(value), p(p) {}
2613 ~ParsedResourceEntry()
override =
default;
2615 StringRef getKey() const final {
return key; }
2617 InFlightDiagnostic
emitError() const final {
return p.emitError(keyLoc); }
2620 if (value.isAny(Token::kw_true, Token::kw_false))
2621 return AsmResourceEntryKind::Bool;
2622 return value.getSpelling().starts_with(
"\"0x")
2623 ? AsmResourceEntryKind::Blob
2624 : AsmResourceEntryKind::String;
2627 FailureOr<bool> parseAsBool() const final {
2628 if (value.is(Token::kw_true))
2630 if (value.is(Token::kw_false))
2632 return p.emitError(value.getLoc(),
2633 "expected 'true' or 'false' value for key '" + key +
2637 FailureOr<std::string> parseAsString() const final {
2638 if (value.isNot(Token::string))
2639 return p.emitError(value.getLoc(),
2640 "expected string value for key '" + key +
"'");
2641 return value.getStringValue();
2644 FailureOr<AsmResourceBlob>
2645 parseAsBlob(BlobAllocatorFn allocator)
const final {
2649 std::optional<std::string> blobData =
2650 value.is(Token::string) ? value.getHexStringValue() : std::nullopt;
2652 return p.emitError(value.getLoc(),
2653 "expected hex string blob for key '" + key +
"'");
2657 if (blobData->size() <
sizeof(uint32_t)) {
2658 return p.emitError(value.getLoc(),
2659 "expected hex string blob for key '" + key +
2660 "' to encode alignment in first 4 bytes");
2662 llvm::support::ulittle32_t align;
2663 memcpy(&align, blobData->data(),
sizeof(uint32_t));
2664 if (align && !llvm::isPowerOf2_32(align)) {
2665 return p.emitError(value.getLoc(),
2666 "expected hex string blob for key '" + key +
2667 "' to encode alignment in first 4 bytes, but got "
2668 "non-power-of-2 value: " +
2673 StringRef data = StringRef(*blobData).drop_front(
sizeof(uint32_t));
2675 return AsmResourceBlob();
2679 AsmResourceBlob blob = allocator(data.size(), align);
2680 assert(llvm::isAddrAligned(llvm::Align(align), blob.
getData().data()) &&
2682 "blob allocator did not return a properly aligned address");
2695ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
2696 assert(getToken().is(Token::hash_identifier));
2697 StringRef aliasName = getTokenSpelling().drop_front();
2701 return emitError(
"redefinition of attribute alias id '" + aliasName +
"'");
2704 if (aliasName.contains(
'.'))
2705 return emitError(
"attribute names with a '.' are reserved for "
2706 "dialect-defined names");
2708 SMRange location = getToken().getLocRange();
2709 consumeToken(Token::hash_identifier);
2712 if (parseToken(Token::equal,
"expected '=' in attribute alias definition"))
2727ParseResult TopLevelOperationParser::parseTypeAliasDef() {
2728 assert(getToken().is(Token::exclamation_identifier));
2729 StringRef aliasName = getTokenSpelling().drop_front();
2733 return emitError(
"redefinition of type alias id '" + aliasName +
"'");
2736 if (aliasName.contains(
'.'))
2737 return emitError(
"type names with a '.' are reserved for "
2738 "dialect-defined names");
2740 SMRange location = getToken().getLocRange();
2741 consumeToken(Token::exclamation_identifier);
2744 if (parseToken(Token::equal,
"expected '=' in type alias definition"))
2759ParseResult TopLevelOperationParser::parseFileMetadataDictionary() {
2760 consumeToken(Token::file_metadata_begin);
2761 return parseCommaSeparatedListUntil(
2762 Token::file_metadata_end, [&]() -> ParseResult {
2764 SMLoc keyLoc = getToken().getLoc();
2766 if (
failed(parseOptionalKeyword(&key)))
2767 return emitError(
"expected identifier key in file "
2768 "metadata dictionary");
2769 if (parseToken(Token::colon,
"expected ':'"))
2773 if (key ==
"dialect_resources")
2774 return parseDialectResourceFileMetadata();
2775 if (key ==
"external_resources")
2776 return parseExternalResourceFileMetadata();
2777 return emitError(keyLoc,
"unknown key '" + key +
2778 "' in file metadata dictionary");
2782ParseResult TopLevelOperationParser::parseResourceFileMetadata(
2783 function_ref<ParseResult(StringRef, SMLoc)> parseBody) {
2784 if (parseToken(Token::l_brace,
"expected '{'"))
2787 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2789 SMLoc nameLoc = getToken().getLoc();
2791 if (
failed(parseOptionalKeyword(&name)))
2792 return emitError(
"expected identifier key for 'resource' entry");
2794 if (parseToken(Token::colon,
"expected ':'") ||
2795 parseToken(Token::l_brace,
"expected '{'"))
2797 return parseBody(name, nameLoc);
2801ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() {
2802 return parseResourceFileMetadata([&](StringRef name,
2803 SMLoc nameLoc) -> ParseResult {
2805 Dialect *dialect =
getContext()->getOrLoadDialect(name);
2807 return emitError(nameLoc,
"dialect '" + name +
"' is unknown");
2808 const auto *handler = dyn_cast<OpAsmDialectInterface>(dialect);
2810 return emitError() <<
"unexpected 'resource' section for dialect '"
2814 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2816 SMLoc keyLoc = getToken().getLoc();
2818 if (
failed(parseResourceHandle(handler, key)) ||
2819 parseToken(Token::colon,
"expected ':'"))
2821 Token valueTok = getToken();
2824 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2825 return handler->parseResource(entry);
2830ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() {
2831 return parseResourceFileMetadata([&](StringRef name,
2832 SMLoc nameLoc) -> ParseResult {
2838 <<
"ignoring unknown external resources for '" << name <<
"'";
2841 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2843 SMLoc keyLoc = getToken().getLoc();
2845 if (
failed(parseOptionalKeywordOrString(&key)))
2847 "expected identifier key for 'external_resources' entry");
2848 if (parseToken(Token::colon,
"expected ':'"))
2850 Token valueTok = getToken();
2855 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2861ParseResult TopLevelOperationParser::parse(
Block *topLevelBlock,
2862 Location parserLoc) {
2864 OwningOpRef<ModuleOp> topLevelOp(ModuleOp::create(parserLoc));
2865 OperationParser opParser(state, topLevelOp.get());
2867 switch (getToken().getKind()) {
2870 if (opParser.parseOperation())
2876 if (opParser.finalize())
2881 auto &parsedOps = topLevelOp->getBody()->getOperations();
2883 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(),
2895 case Token::hash_identifier:
2896 if (parseAttributeAliasDef())
2901 case Token::exclamation_identifier:
2902 if (parseTypeAliasDef())
2907 case Token::file_metadata_begin:
2908 if (parseFileMetadataDictionary())
2921 const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
2929 codeCompleteContext);
2930 return TopLevelOperationParser(state).parse(block, parserLoc);
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.
Dialect * getDialect() const
Return the dialect that this interface represents.
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.
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 ...
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.
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.
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.
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.
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 ...
const FrozenRewritePatternSet GreedyRewriteConfig config
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.