38#include "llvm/ADT/APFloat.h"
39#include "llvm/ADT/DenseMap.h"
40#include "llvm/ADT/PointerUnion.h"
41#include "llvm/ADT/STLExtras.h"
42#include "llvm/ADT/ScopeExit.h"
43#include "llvm/ADT/Sequence.h"
44#include "llvm/ADT/StringExtras.h"
45#include "llvm/ADT/StringMap.h"
46#include "llvm/ADT/StringSet.h"
47#include "llvm/Support/Alignment.h"
48#include "llvm/Support/Casting.h"
49#include "llvm/Support/Endian.h"
50#include "llvm/Support/ErrorHandling.h"
51#include "llvm/Support/MathExtras.h"
52#include "llvm/Support/PrettyStackTrace.h"
53#include "llvm/Support/SourceMgr.h"
54#include "llvm/Support/raw_ostream.h"
86 StringRef contextMessage) {
90 case Delimiter::OptionalParen:
91 if (
getToken().isNot(Token::l_paren))
94 case Delimiter::Paren:
95 if (
parseToken(Token::l_paren,
"expected '('" + contextMessage))
101 case Delimiter::OptionalLessGreater:
106 case Delimiter::LessGreater:
107 if (
parseToken(Token::less,
"expected '<'" + contextMessage))
113 case Delimiter::OptionalSquare:
114 if (
getToken().isNot(Token::l_square))
117 case Delimiter::Square:
118 if (
parseToken(Token::l_square,
"expected '['" + contextMessage))
124 case Delimiter::OptionalBraces:
125 if (
getToken().isNot(Token::l_brace))
128 case Delimiter::Braces:
129 if (
parseToken(Token::l_brace,
"expected '{'" + contextMessage))
138 if (parseElementFn())
143 if (parseElementFn())
148 case Delimiter::None:
150 case Delimiter::OptionalParen:
151 case Delimiter::Paren:
152 return parseToken(Token::r_paren,
"expected ')'" + contextMessage);
153 case Delimiter::OptionalLessGreater:
154 case Delimiter::LessGreater:
155 return parseToken(Token::greater,
"expected '>'" + contextMessage);
156 case Delimiter::OptionalSquare:
157 case Delimiter::Square:
158 return parseToken(Token::r_square,
"expected ']'" + contextMessage);
159 case Delimiter::OptionalBraces:
160 case Delimiter::Braces:
161 return parseToken(Token::r_brace,
"expected '}'" + contextMessage);
163 llvm_unreachable(
"Unknown delimiter");
175 bool allowEmptyList) {
193 auto loc =
state.curToken.getLoc();
194 if (
state.curToken.isNot(Token::eof))
198 return emitError(SMLoc::getFromPointer(loc.getPointer() - 1), message);
206 size_t slashPos = line.find(
"//");
207 if (slashPos == StringRef::npos)
208 return StringRef::npos;
213 size_t quotePos = line.find(
'"');
214 if (quotePos == StringRef::npos || quotePos > slashPos)
218 bool inString =
false;
219 for (
size_t i = 0, e = line.size(); i < e; ++i) {
232 }
else if (c ==
'/' && i + 1 < e && line[i + 1] ==
'/') {
237 return StringRef::npos;
255 auto loc =
state.curToken.getLoc();
258 if (
state.curToken.is(Token::eof))
259 loc = SMLoc::getFromPointer(loc.getPointer() - 1);
262 auto originalLoc = loc;
265 const char *bufferStart =
state.lex.getBufferBegin();
266 const char *curPtr = loc.getPointer();
270 StringRef startOfBuffer(bufferStart, curPtr - bufferStart);
275 startOfBuffer = startOfBuffer.rtrim(
" \t");
279 if (startOfBuffer.empty())
283 if (startOfBuffer.back() !=
'\n' && startOfBuffer.back() !=
'\r')
284 return emitError(SMLoc::getFromPointer(startOfBuffer.end()), message);
287 startOfBuffer = startOfBuffer.drop_back();
290 auto prevLine = startOfBuffer;
291 size_t newLineIndex = prevLine.find_last_of(
"\n\r");
292 if (newLineIndex != StringRef::npos)
293 prevLine = prevLine.drop_front(newLineIndex);
298 if (commentStart != StringRef::npos)
299 startOfBuffer = startOfBuffer.drop_back(prevLine.size() - commentStart);
306 const Twine &message) {
336 if (curToken.
isNot(Token::integer, Token::minus))
341 if (
parseToken(Token::integer,
"expected integer value"))
345 bool isHex = spelling.size() > 1 && spelling[1] ==
'x';
346 if (spelling.getAsInteger(isHex ? 0 : 10,
result))
363 if (curToken.
isNot(Token::integer, Token::minus)) {
369 if (
parseToken(Token::integer,
"expected integer value")) {
377 if (spelling[0] ==
'0' && spelling.size() > 1 &&
378 llvm::toLower(spelling[1]) ==
'x') {
380 state.lex.resetPointer(spelling.data() + 1);
385 if (spelling.getAsInteger(10,
result))
400 const Token &tok,
bool isNegative,
401 const llvm::fltSemantics &semantics) {
403 if (tok.
is(Token::floatliteral)) {
408 result.emplace(isNegative ? -*val : *val);
410 result->convert(semantics, APFloat::rmNearestTiesToEven, &unused);
415 if (tok.
is(Token::integer))
424 const Token &tok,
bool isNegative,
425 const llvm::fltSemantics &semantics) {
427 bool isHex = spelling.size() > 1 && spelling[1] ==
'x';
429 return emitError(tok.
getLoc(),
"unexpected decimal integer literal for a "
430 "floating point value")
432 <<
"add a trailing dot to make the literal a float";
436 "hexadecimal float literal should not have a "
441 tok.
getSpelling().getAsInteger(isHex ? 0 : 10, intValue);
442 auto typeSizeInBits = APFloat::semanticsSizeInBits(semantics);
443 if (intValue.getActiveBits() > typeSizeInBits) {
445 "hexadecimal float constant out of range for type");
448 APInt truncatedValue(typeSizeInBits,
449 ArrayRef(intValue.getRawData(), intValue.getNumWords()));
450 result.emplace(semantics, truncatedValue);
478FailureOr<AsmDialectResourceHandle>
481 assert(dialect &&
"expected valid dialect interface");
484 return emitError(
"expected identifier key for 'resource' entry");
490 std::pair<std::string, AsmDialectResourceHandle> &entry =
491 resources[dialect][name];
492 if (entry.first.empty()) {
496 <<
"unknown 'resource' key '" << name <<
"' for dialect '"
507FailureOr<AsmDialectResourceHandle>
512 <<
"' does not expect resource handles";
514 std::string resourceName;
523 state.codeCompleteContext->completeDialectName();
531 if (dialectName.empty() || dialectName.contains(
'.'))
533 state.codeCompleteContext->completeOperationName(dialectName);
542 auto shouldIgnoreOpCompletion = [&]() {
543 const char *bufBegin =
state.lex.getBufferBegin();
544 const char *it = loc.getPointer() - 1;
545 for (; it > bufBegin && *it !=
'\n'; --it)
546 if (!StringRef(
" \t\r").
contains(*it))
550 if (shouldIgnoreOpCompletion())
568 if (name.consume_back(
"."))
574 state.codeCompleteContext->completeExpectedTokens(tokens,
false);
578 state.codeCompleteContext->completeExpectedTokens(tokens,
true);
583 state.codeCompleteContext->completeAttribute(
584 state.symbols.attributeAliasDefinitions);
588 state.codeCompleteContext->completeType(
state.symbols.typeAliasDefinitions);
594 state.codeCompleteContext->completeDialectAttributeOrAlias(aliases);
598 state.codeCompleteContext->completeDialectTypeOrAlias(aliases);
609class OperationParser :
public Parser {
611 OperationParser(
ParserState &state, ModuleOp topLevelOp);
616 ParseResult finalize();
625 struct DeferredLocInfo {
627 StringRef identifier;
631 void pushSSANameScope(
bool isIsolated);
634 ParseResult popSSANameScope();
637 ParseResult addDefinition(UnresolvedOperand useInfo,
Value value);
645 ParseResult parseSSAUse(UnresolvedOperand &
result,
646 bool allowResultNumber =
true);
650 Value resolveSSAUse(UnresolvedOperand useInfo,
Type type);
652 ParseResult parseSSADefOrUseAndType(
659 std::optional<SMLoc> getReferenceLoc(StringRef name,
unsigned number) {
660 auto &values = isolatedNameScopes.back().values;
661 if (!values.count(name) || number >= values[name].size())
663 if (values[name][number].value)
664 return values[name][number].loc;
673 ParseResult parseOperation();
676 ParseResult parseSuccessor(
Block *&dest);
679 ParseResult parseSuccessors(SmallVectorImpl<Block *> &destinations);
682 Operation *parseGenericOperation();
689 ParseResult parseGenericOperationAfterOpName(
691 std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo =
693 std::optional<ArrayRef<Block *>> parsedSuccessors = std::nullopt,
694 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions =
696 std::optional<ArrayRef<NamedAttribute>> parsedAttributes = std::nullopt,
697 std::optional<Attribute> propertiesAttribute = std::nullopt,
698 std::optional<FunctionType> parsedFnType = std::nullopt);
702 Operation *parseGenericOperation(
Block *insertBlock,
708 using OpOrArgument = llvm::PointerUnion<Operation *, BlockArgument>;
715 ParseResult parseTrailingLocationSpecifier(OpOrArgument opOrArgument);
721 ParseResult parseLocationAlias(LocationAttr &loc);
725 using ResultRecord = std::tuple<StringRef, unsigned, SMLoc>;
729 Operation *parseCustomOperation(ArrayRef<ResultRecord> resultIDs);
733 FailureOr<OperationName> parseCustomOperationName();
742 ParseResult parseRegion(Region ®ion, ArrayRef<Argument> entryArguments,
743 bool isIsolatedNameScope =
false);
746 ParseResult parseRegionBody(Region ®ion, SMLoc startLoc,
747 ArrayRef<Argument> entryArguments,
748 bool isIsolatedNameScope);
755 ParseResult parseBlock(
Block *&block);
758 ParseResult parseBlockBody(
Block *block);
761 ParseResult parseOptionalBlockArgList(
Block *owner);
766 Block *getBlockNamed(StringRef name, SMLoc loc);
776 ParseResult codeCompleteSSAUse();
777 ParseResult codeCompleteBlock();
781 struct BlockDefinition {
788 struct ValueDefinition {
796 BlockDefinition &getBlockInfoByName(StringRef name) {
797 return blocksByName.back()[name];
801 void insertForwardRef(
Block *block, SMLoc loc) {
802 forwardRef.back().try_emplace(block, loc);
806 bool eraseForwardRef(
Block *block) {
return forwardRef.back().erase(block); }
809 void recordDefinition(StringRef def);
812 SmallVectorImpl<ValueDefinition> &getSSAValueEntry(StringRef name);
816 Value createForwardRefPlaceholder(SMLoc loc, Type type);
819 bool isForwardRefPlaceholder(Value value) {
820 return forwardRefPlaceholders.count(value);
827 struct IsolatedSSANameScope {
829 void recordDefinition(StringRef def) {
830 definitionsPerScope.back().insert(def);
834 void pushSSANameScope() { definitionsPerScope.push_back({}); }
837 void popSSANameScope() {
838 for (
auto &def : definitionsPerScope.pop_back_val())
839 values.erase(def.getKey());
844 llvm::StringMap<SmallVector<ValueDefinition, 1>> values;
847 SmallVector<llvm::StringSet<>, 2> definitionsPerScope;
851 SmallVector<IsolatedSSANameScope, 2> isolatedNameScopes;
856 SmallVector<DenseMap<StringRef, BlockDefinition>, 2> blocksByName;
857 SmallVector<DenseMap<Block *, SMLoc>, 2> forwardRef;
872 std::vector<DeferredLocInfo> deferredLocsReferences;
878 Operation *topLevelOp;
885OperationParser::OperationParser(
ParserState &state, ModuleOp topLevelOp)
886 :
Parser(state), opBuilder(topLevelOp.getRegion()), topLevelOp(topLevelOp) {
888 pushSSANameScope(
true);
892 state.asmState->initialize(topLevelOp);
895OperationParser::~OperationParser() {
896 for (Operation *op : forwardRefOps) {
902 for (
const auto &scope : forwardRef) {
903 for (
const auto &fwd : scope) {
906 fwd.first->dropAllUses();
914ParseResult OperationParser::finalize() {
917 if (!forwardRefPlaceholders.empty()) {
918 SmallVector<const char *, 4> errors;
920 for (
auto entry : forwardRefPlaceholders)
921 errors.push_back(entry.second.getPointer());
922 llvm::array_pod_sort(errors.begin(), errors.end());
924 for (
const char *entry : errors) {
925 auto loc = SMLoc::getFromPointer(entry);
926 emitError(loc,
"use of undeclared SSA value name");
934 auto resolveLocation = [&,
this](
auto &opOrArgument) -> LogicalResult {
935 auto fwdLoc = dyn_cast<OpaqueLoc>(opOrArgument.getLoc());
936 if (!fwdLoc || fwdLoc.getUnderlyingTypeID() != locID)
938 auto locInfo = deferredLocsReferences[fwdLoc.getUnderlyingLocation()];
939 Attribute attr = attributeAliases.lookup(locInfo.identifier);
942 <<
"operation location alias was never defined";
943 auto locAttr = dyn_cast<LocationAttr>(attr);
946 <<
"expected location, but found '" << attr <<
"'";
947 opOrArgument.setLoc(locAttr);
951 auto walkRes = topLevelOp->walk([&](Operation *op) {
952 if (
failed(resolveLocation(*op)))
955 for (
Block &block : region.getBlocks())
957 if (
failed(resolveLocation(arg)))
961 if (walkRes.wasInterrupted())
965 if (
failed(popSSANameScope()))
982void OperationParser::pushSSANameScope(
bool isIsolated) {
988 isolatedNameScopes.push_back({});
989 isolatedNameScopes.back().pushSSANameScope();
992ParseResult OperationParser::popSSANameScope() {
993 auto forwardRefInCurrentScope = forwardRef.pop_back_val();
996 if (!forwardRefInCurrentScope.empty()) {
997 SmallVector<std::pair<const char *, Block *>, 4> errors;
999 for (
auto entry : forwardRefInCurrentScope) {
1000 errors.push_back({entry.second.getPointer(), entry.first});
1002 topLevelOp->getRegion(0).push_back(entry.first);
1004 llvm::array_pod_sort(errors.begin(), errors.end());
1006 for (
auto entry : errors) {
1007 auto loc = SMLoc::getFromPointer(entry.first);
1008 emitError(loc,
"reference to an undefined block");
1015 auto ¤tNameScope = isolatedNameScopes.back();
1016 if (currentNameScope.definitionsPerScope.size() == 1)
1017 isolatedNameScopes.pop_back();
1019 currentNameScope.popSSANameScope();
1021 blocksByName.pop_back();
1026ParseResult OperationParser::addDefinition(UnresolvedOperand useInfo,
1028 auto &entries = getSSAValueEntry(useInfo.name);
1031 if (entries.size() <= useInfo.number)
1032 entries.resize(useInfo.number + 1);
1036 if (
auto existing = entries[useInfo.number].value) {
1037 if (!isForwardRefPlaceholder(existing)) {
1039 .
append(
"redefinition of SSA value '", useInfo.name,
"'")
1040 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1041 .
append(
"previously defined here");
1044 if (existing.getType() != value.
getType()) {
1046 .
append(
"definition of SSA value '", useInfo.name,
"#",
1047 useInfo.number,
"' has type ", value.
getType())
1048 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1049 .
append(
"previously used here with type ", existing.getType());
1055 existing.replaceAllUsesWith(value);
1056 forwardRefPlaceholders.erase(existing);
1065 entries[useInfo.number] = {value, useInfo.location};
1066 recordDefinition(useInfo.name);
1075ParseResult OperationParser::parseOptionalSSAUseList(
1076 SmallVectorImpl<UnresolvedOperand> &results) {
1077 if (!getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
1080 UnresolvedOperand
result;
1083 results.push_back(
result);
1092ParseResult OperationParser::parseSSAUse(UnresolvedOperand &
result,
1093 bool allowResultNumber) {
1094 if (getToken().isCodeCompletion())
1095 return codeCompleteSSAUse();
1097 result.name = getTokenSpelling();
1099 result.location = getToken().getLoc();
1100 if (parseToken(Token::percent_identifier,
"expected SSA operand"))
1104 if (getToken().is(Token::hash_identifier)) {
1105 if (!allowResultNumber)
1106 return emitError(
"result number not allowed in argument list");
1108 if (
auto value = getToken().getHashIdentifierNumber())
1111 return emitError(
"invalid SSA value result number");
1112 consumeToken(Token::hash_identifier);
1120Value OperationParser::resolveSSAUse(UnresolvedOperand useInfo, Type type) {
1121 auto &entries = getSSAValueEntry(useInfo.name);
1125 auto maybeRecordUse = [&](Value value) {
1132 if (useInfo.number < entries.size() && entries[useInfo.number].value) {
1133 Value
result = entries[useInfo.number].value;
1135 if (
result.getType() == type)
1136 return maybeRecordUse(
result);
1138 emitError(useInfo.location,
"use of value '")
1140 "' expects different type than prior uses: ", type,
" vs ",
1142 .
attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1143 .
append(
"prior use here");
1148 if (entries.size() <= useInfo.number)
1149 entries.resize(useInfo.number + 1);
1153 if (entries[0].value && !isForwardRefPlaceholder(entries[0].value))
1154 return (
emitError(useInfo.location,
"reference to invalid result number"),
1159 Value
result = createForwardRefPlaceholder(useInfo.location, type);
1160 entries[useInfo.number] = {
result, useInfo.location};
1161 return maybeRecordUse(
result);
1167ParseResult OperationParser::parseSSADefOrUseAndType(
1168 function_ref<ParseResult(UnresolvedOperand, Type)> action) {
1169 UnresolvedOperand useInfo;
1170 if (parseSSAUse(useInfo) ||
1171 parseToken(Token::colon,
"expected ':' and type for SSA operand"))
1178 return action(useInfo, type);
1187ParseResult OperationParser::parseOptionalSSAUseAndTypeList(
1188 SmallVectorImpl<Value> &results) {
1189 SmallVector<UnresolvedOperand, 4> valueIDs;
1190 if (parseOptionalSSAUseList(valueIDs))
1194 if (valueIDs.empty())
1197 SmallVector<Type, 4> types;
1198 if (parseToken(Token::colon,
"expected ':' in operand list") ||
1199 parseTypeListNoParens(types))
1202 if (valueIDs.size() != types.size())
1204 << valueIDs.size() <<
" types to match operand list";
1206 results.reserve(valueIDs.size());
1207 for (
unsigned i = 0, e = valueIDs.size(); i != e; ++i) {
1208 if (
auto value = resolveSSAUse(valueIDs[i], types[i]))
1209 results.push_back(value);
1218void OperationParser::recordDefinition(StringRef def) {
1219 isolatedNameScopes.back().recordDefinition(def);
1223auto OperationParser::getSSAValueEntry(StringRef name)
1224 -> SmallVectorImpl<ValueDefinition> & {
1225 return isolatedNameScopes.back().values[name];
1229Value OperationParser::createForwardRefPlaceholder(SMLoc loc, Type type) {
1236 auto name = OperationName(
"builtin.unrealized_conversion_cast",
getContext());
1238 getEncodedSourceLocation(loc), name, type, {},
1239 NamedAttrList(),
nullptr,
1241 forwardRefPlaceholders[op->
getResult(0)] = loc;
1242 forwardRefOps.insert(op);
1262ParseResult OperationParser::parseOperation() {
1263 auto loc = getToken().getLoc();
1264 SmallVector<ResultRecord, 1> resultIDs;
1265 size_t numExpectedResults = 0;
1266 if (getToken().is(Token::percent_identifier)) {
1268 auto parseNextResult = [&]() -> ParseResult {
1270 Token nameTok = getToken();
1271 if (parseToken(Token::percent_identifier,
1272 "expected valid ssa identifier"))
1276 size_t expectedSubResults = 1;
1277 if (consumeIf(Token::colon)) {
1279 if (!getToken().is(Token::integer))
1280 return emitWrongTokenError(
"expected integer number of results");
1283 auto val = getToken().getUInt64IntegerValue();
1284 if (!val || *val < 1)
1286 "expected named operation to have at least 1 result");
1287 consumeToken(Token::integer);
1288 expectedSubResults = *val;
1291 resultIDs.emplace_back(nameTok.
getSpelling(), expectedSubResults,
1293 numExpectedResults += expectedSubResults;
1299 if (parseToken(Token::equal,
"expected '=' after SSA name"))
1304 Token nameTok = getToken();
1305 if (nameTok.
is(Token::bare_identifier) || nameTok.
isKeyword())
1306 op = parseCustomOperation(resultIDs);
1307 else if (nameTok.
is(Token::string))
1308 op = parseGenericOperation();
1310 return codeCompleteStringDialectOrOperationName(nameTok.
getStringValue());
1312 return codeCompleteDialectOrElidedOpName(loc);
1314 return emitWrongTokenError(
"expected operation name in quotes");
1321 if (!resultIDs.empty()) {
1323 return emitError(loc,
"cannot name an operation with no results");
1325 return emitError(loc,
"operation defines ")
1327 << numExpectedResults <<
" to bind";
1331 unsigned resultIt = 0;
1332 SmallVector<std::pair<unsigned, SMLoc>> asmResultGroups;
1333 asmResultGroups.reserve(resultIDs.size());
1334 for (ResultRecord &record : resultIDs) {
1335 asmResultGroups.emplace_back(resultIt, std::get<2>(record));
1336 resultIt += std::get<1>(record);
1339 op, nameTok.
getLocRange(), getLastToken().getEndLoc(),
1344 unsigned opResI = 0;
1345 for (ResultRecord &resIt : resultIDs) {
1346 for (
unsigned subRes : llvm::seq<unsigned>(0, std::get<1>(resIt))) {
1347 if (addDefinition({std::get<2>(resIt), std::get<0>(resIt), subRes},
1357 getLastToken().getEndLoc());
1367ParseResult OperationParser::parseSuccessor(
Block *&dest) {
1368 if (getToken().isCodeCompletion())
1369 return codeCompleteBlock();
1372 if (!getToken().is(Token::caret_identifier))
1373 return emitWrongTokenError(
"expected block name");
1374 dest = getBlockNamed(getTokenSpelling(), getToken().getLoc());
1384OperationParser::parseSuccessors(SmallVectorImpl<Block *> &destinations) {
1385 if (parseToken(Token::l_square,
"expected '['"))
1388 auto parseElt = [
this, &destinations] {
1390 ParseResult res = parseSuccessor(dest);
1391 destinations.push_back(dest);
1394 return parseCommaSeparatedListUntil(Token::r_square, parseElt,
1403struct CleanupOpStateRegions {
1404 ~CleanupOpStateRegions() {
1405 SmallVector<Region *, 4> regionsToClean;
1406 regionsToClean.reserve(state.regions.size());
1407 for (
auto ®ion : state.regions)
1409 for (
auto &block : *region)
1412 OperationState &state;
1416ParseResult OperationParser::parseGenericOperationAfterOpName(
1418 std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo,
1419 std::optional<ArrayRef<Block *>> parsedSuccessors,
1420 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1421 std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1422 std::optional<Attribute> propertiesAttribute,
1423 std::optional<FunctionType> parsedFnType) {
1426 SmallVector<UnresolvedOperand, 8> opInfo;
1427 if (!parsedOperandUseInfo) {
1428 if (parseToken(Token::l_paren,
"expected '(' to start operand list") ||
1429 parseOptionalSSAUseList(opInfo) ||
1430 parseToken(Token::r_paren,
"expected ')' to end operand list")) {
1433 parsedOperandUseInfo = opInfo;
1437 if (!parsedSuccessors) {
1438 if (getToken().is(Token::l_square)) {
1440 if (!
result.name.mightHaveTrait<OpTrait::IsTerminator>())
1441 return emitError(
"successors in non-terminator");
1443 SmallVector<Block *, 2> successors;
1444 if (parseSuccessors(successors))
1446 result.addSuccessors(successors);
1449 result.addSuccessors(*parsedSuccessors);
1453 if (propertiesAttribute) {
1454 result.propertiesAttr = *propertiesAttribute;
1455 }
else if (consumeIf(Token::less)) {
1457 if (!
result.propertiesAttr)
1459 if (parseToken(Token::greater,
"expected '>' to close properties"))
1463 if (!parsedRegions) {
1464 if (consumeIf(Token::l_paren)) {
1467 result.regions.emplace_back(
new Region(topLevelOp));
1468 if (parseRegion(*
result.regions.back(), {}))
1470 }
while (consumeIf(Token::comma));
1471 if (parseToken(Token::r_paren,
"expected ')' to end region list"))
1475 result.addRegions(*parsedRegions);
1479 if (!parsedAttributes) {
1480 if (getToken().is(Token::l_brace)) {
1481 if (parseAttributeDict(
result.attributes))
1485 result.addAttributes(*parsedAttributes);
1489 Location typeLoc =
result.location;
1490 if (!parsedFnType) {
1491 if (parseToken(Token::colon,
"expected ':' followed by operation type"))
1494 typeLoc = getEncodedSourceLocation(getToken().getLoc());
1498 auto fnType = dyn_cast<FunctionType>(type);
1502 parsedFnType = fnType;
1505 result.addTypes(parsedFnType->getResults());
1508 ArrayRef<Type> operandTypes = parsedFnType->getInputs();
1509 if (operandTypes.size() != parsedOperandUseInfo->size()) {
1510 auto plural =
"s"[parsedOperandUseInfo->size() == 1];
1512 << parsedOperandUseInfo->size() <<
" operand type" << plural
1513 <<
" but had " << operandTypes.size();
1517 for (
unsigned i = 0, e = parsedOperandUseInfo->size(); i != e; ++i) {
1518 result.operands.push_back(
1519 resolveSSAUse((*parsedOperandUseInfo)[i], operandTypes[i]));
1520 if (!
result.operands.back())
1527Operation *OperationParser::parseGenericOperation() {
1529 auto srcLocation = getEncodedSourceLocation(getToken().getLoc());
1531 std::string name = getToken().getStringValue();
1533 return (
emitError(
"empty operation name is invalid"),
nullptr);
1534 if (name.find(
'\0') != StringRef::npos)
1535 return (
emitError(
"null character not allowed in operation name"),
nullptr);
1537 consumeToken(Token::string);
1539 OperationState
result(srcLocation, name);
1540 CleanupOpStateRegions guard{
result};
1543 if (!
result.name.isRegistered()) {
1544 StringRef dialectName = StringRef(name).split(
'.').first;
1545 if (!
getContext()->getLoadedDialect(dialectName) &&
1546 !
getContext()->getOrLoadDialect(dialectName)) {
1547 if (!
getContext()->allowsUnregisteredDialects()) {
1550 emitError(
"operation being parsed with an unregistered dialect. If "
1551 "this is intended, please use -allow-unregistered-dialect "
1552 "with the MLIR tool used");
1565 if (parseGenericOperationAfterOpName(
result))
1571 Attribute properties;
1572 std::swap(properties,
result.propertiesAttr);
1588 if (!properties && !
result.getRawProperties()) {
1589 std::optional<RegisteredOperationName> info =
1590 result.name.getRegisteredInfo();
1592 if (
failed(info->verifyInherentAttrs(
result.attributes, [&]() {
1593 return mlir::emitError(srcLocation) <<
"'" << name <<
"' op ";
1601 if (parseTrailingLocationSpecifier(op))
1609 << properties <<
" for op " << name <<
": ";
1618Operation *OperationParser::parseGenericOperation(
Block *insertBlock,
1620 Token nameToken = getToken();
1622 OpBuilder::InsertionGuard restoreInsertionPoint(opBuilder);
1623 opBuilder.setInsertionPoint(insertBlock, insertPt);
1624 Operation *op = parseGenericOperation();
1633 getLastToken().getEndLoc());
1638class CustomOpAsmParser :
public AsmParserImpl<OpAsmParser> {
1641 SMLoc nameLoc, ArrayRef<OperationParser::ResultRecord> resultIDs,
1642 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly,
1643 bool isIsolatedFromAbove, StringRef opName, OperationParser &parser)
1644 : AsmParserImpl<OpAsmParser>(nameLoc, parser), resultIDs(resultIDs),
1645 parseAssembly(parseAssembly), isIsolatedFromAbove(isIsolatedFromAbove),
1646 opName(opName), parser(parser) {
1647 (void)isIsolatedFromAbove;
1652 ParseResult parseOperation(OperationState &opState) {
1653 if (parseAssembly(*
this, opState))
1659 std::optional<NamedAttribute> duplicate =
1662 return emitError(getNameLoc(),
"attribute '")
1663 << duplicate->getName().getValue()
1664 <<
"' occurs more than once in the attribute list";
1668 Operation *parseGenericOperation(
Block *insertBlock,
1670 return parser.parseGenericOperation(insertBlock, insertPt);
1673 FailureOr<OperationName> parseCustomOperationName() final {
1674 return parser.parseCustomOperationName();
1677 ParseResult parseGenericOperationAfterOpName(
1679 std::optional<ArrayRef<UnresolvedOperand>> parsedUnresolvedOperands,
1680 std::optional<ArrayRef<Block *>> parsedSuccessors,
1681 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1682 std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1683 std::optional<Attribute> parsedPropertiesAttribute,
1684 std::optional<FunctionType> parsedFnType)
final {
1685 return parser.parseGenericOperationAfterOpName(
1686 result, parsedUnresolvedOperands, parsedSuccessors, parsedRegions,
1687 parsedAttributes, parsedPropertiesAttribute, parsedFnType);
1702 std::pair<StringRef, unsigned>
1703 getResultName(
unsigned resultNo)
const override {
1705 for (
const auto &entry : resultIDs) {
1706 if (resultNo < std::get<1>(entry)) {
1708 StringRef name = std::get<0>(entry).drop_front();
1709 return {name, resultNo};
1711 resultNo -= std::get<1>(entry);
1720 size_t getNumResults()
const override {
1722 for (
auto &entry : resultIDs)
1723 count += std::get<1>(entry);
1728 InFlightDiagnostic
emitError(SMLoc loc,
const Twine &message)
override {
1738 ParseResult parseOperand(UnresolvedOperand &
result,
1739 bool allowResultNumber =
true)
override {
1740 OperationParser::UnresolvedOperand useInfo;
1741 if (parser.parseSSAUse(useInfo, allowResultNumber))
1750 parseOptionalOperand(UnresolvedOperand &
result,
1751 bool allowResultNumber =
true)
override {
1752 if (parser.getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
1753 return parseOperand(
result, allowResultNumber);
1754 return std::nullopt;
1759 ParseResult parseOperandList(SmallVectorImpl<UnresolvedOperand> &
result,
1760 Delimiter delimiter = Delimiter::None,
1761 bool allowResultNumber =
true,
1762 int requiredOperandCount = -1)
override {
1764 if (delimiter == Delimiter::None) {
1767 Token tok = parser.getToken();
1771 if (requiredOperandCount == -1 || requiredOperandCount == 0)
1775 if (tok.
isAny(Token::l_paren, Token::l_square))
1776 return parser.emitError(
"unexpected delimiter");
1777 return parser.emitWrongTokenError(
"expected operand");
1781 auto parseOneOperand = [&]() -> ParseResult {
1782 return parseOperand(
result.emplace_back(), allowResultNumber);
1785 auto startLoc = parser.getToken().getLoc();
1790 if (requiredOperandCount != -1 &&
1791 result.size() !=
static_cast<size_t>(requiredOperandCount))
1793 << requiredOperandCount <<
" operands";
1798 ParseResult resolveOperand(
const UnresolvedOperand &operand, Type type,
1799 SmallVectorImpl<Value> &
result)
override {
1800 if (
auto value = parser.resolveSSAUse(operand, type)) {
1809 parseAffineMapOfSSAIds(SmallVectorImpl<UnresolvedOperand> &operands,
1810 Attribute &mapAttr, StringRef attrName,
1811 NamedAttrList &attrs, Delimiter delimiter)
override {
1812 SmallVector<UnresolvedOperand, 2> dimOperands;
1813 SmallVector<UnresolvedOperand, 1> symOperands;
1815 auto parseElement = [&](
bool isSymbol) -> ParseResult {
1816 UnresolvedOperand operand;
1817 if (parseOperand(operand))
1820 symOperands.push_back(operand);
1822 dimOperands.push_back(operand);
1827 if (parser.parseAffineMapOfSSAIds(map, parseElement, delimiter))
1831 mapAttr = AffineMapAttr::get(map);
1832 attrs.
push_back(parser.builder.getNamedAttr(attrName, mapAttr));
1836 operands.assign(dimOperands.begin(), dimOperands.end());
1837 operands.append(symOperands.begin(), symOperands.end());
1843 parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands,
1844 SmallVectorImpl<UnresolvedOperand> &symbOperands,
1845 AffineExpr &expr)
override {
1846 auto parseElement = [&](
bool isSymbol) -> ParseResult {
1847 UnresolvedOperand operand;
1848 if (parseOperand(operand))
1851 symbOperands.push_back(operand);
1853 dimOperands.push_back(operand);
1857 return parser.parseAffineExprOfSSAIds(expr, parseElement);
1870 ParseResult parseArgument(Argument &
result,
bool allowType =
false,
1871 bool allowAttrs =
false)
override {
1872 NamedAttrList attrs;
1873 if (parseOperand(
result.ssaName,
false) ||
1874 (allowType && parseColonType(
result.type)) ||
1875 (allowAttrs && parseOptionalAttrDict(attrs)) ||
1876 parseOptionalLocationSpecifier(
result.sourceLoc))
1883 OptionalParseResult parseOptionalArgument(Argument &
result,
bool allowType,
1884 bool allowAttrs)
override {
1885 if (parser.getToken().is(Token::percent_identifier))
1886 return parseArgument(
result, allowType, allowAttrs);
1887 return std::nullopt;
1890 ParseResult parseArgumentList(SmallVectorImpl<Argument> &
result,
1891 Delimiter delimiter,
bool allowType,
1892 bool allowAttrs)
override {
1894 if (delimiter == Delimiter::None &&
1895 parser.getToken().isNot(Token::percent_identifier))
1898 auto parseOneArgument = [&]() -> ParseResult {
1899 return parseArgument(
result.emplace_back(), allowType, allowAttrs);
1902 " in argument list");
1911 ParseResult parseRegion(Region ®ion, ArrayRef<Argument> arguments,
1912 bool enableNameShadowing)
override {
1914 (void)isIsolatedFromAbove;
1915 assert((!enableNameShadowing || isIsolatedFromAbove) &&
1916 "name shadowing is only allowed on isolated regions");
1917 if (parser.parseRegion(region, arguments, enableNameShadowing))
1923 OptionalParseResult parseOptionalRegion(Region ®ion,
1924 ArrayRef<Argument> arguments,
1925 bool enableNameShadowing)
override {
1926 if (parser.getToken().isNot(Token::l_brace))
1927 return std::nullopt;
1928 return parseRegion(region, arguments, enableNameShadowing);
1935 parseOptionalRegion(std::unique_ptr<Region> ®ion,
1936 ArrayRef<Argument> arguments,
1937 bool enableNameShadowing =
false)
override {
1938 if (parser.getToken().isNot(Token::l_brace))
1939 return std::nullopt;
1940 std::unique_ptr<Region> newRegion = std::make_unique<Region>();
1941 if (parseRegion(*newRegion, arguments, enableNameShadowing))
1944 region = std::move(newRegion);
1953 ParseResult parseSuccessor(
Block *&dest)
override {
1954 return parser.parseSuccessor(dest);
1958 OptionalParseResult parseOptionalSuccessor(
Block *&dest)
override {
1959 if (!parser.getToken().isOrIsCodeCompletionFor(Token::caret_identifier))
1960 return std::nullopt;
1961 return parseSuccessor(dest);
1966 parseSuccessorAndUseList(
Block *&dest,
1967 SmallVectorImpl<Value> &operands)
override {
1968 if (parseSuccessor(dest))
1972 if (succeeded(parseOptionalLParen()) &&
1973 (parser.parseOptionalSSAUseAndTypeList(operands) || parseRParen())) {
1985 OptionalParseResult parseOptionalAssignmentList(
1986 SmallVectorImpl<Argument> &
lhs,
1987 SmallVectorImpl<UnresolvedOperand> &
rhs)
override {
1988 if (
failed(parseOptionalLParen()))
1989 return std::nullopt;
1991 auto parseElt = [&]() -> ParseResult {
1992 if (parseArgument(
lhs.emplace_back()) || parseEqual() ||
1993 parseOperand(
rhs.emplace_back()))
1997 return parser.parseCommaSeparatedListUntil(Token::r_paren, parseElt);
2002 parseOptionalLocationSpecifier(std::optional<Location> &
result)
override {
2004 if (!parser.consumeIf(Token::kw_loc))
2006 LocationAttr directLoc;
2007 if (parser.parseToken(Token::l_paren,
"expected '(' in location"))
2010 Token tok = parser.getToken();
2016 if (tok.
is(Token::hash_identifier) && !tok.
getSpelling().contains(
'.')) {
2017 if (parser.parseLocationAlias(directLoc))
2019 }
else if (parser.parseLocationInstance(directLoc)) {
2023 if (parser.parseToken(Token::r_paren,
"expected ')' in location"))
2032 ArrayRef<OperationParser::ResultRecord> resultIDs;
2035 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly;
2036 bool isIsolatedFromAbove;
2040 OperationParser &parser;
2044FailureOr<OperationName> OperationParser::parseCustomOperationName() {
2045 Token nameTok = getToken();
2050 return emitError(
"expected bare identifier or keyword");
2053 return (
emitError(
"empty operation name is invalid"), failure());
2057 std::optional<RegisteredOperationName> opInfo =
2064 auto opNameSplit = opName.split(
'.');
2065 StringRef dialectName = opNameSplit.first;
2066 std::string opNameStorage;
2067 if (opNameSplit.second.empty()) {
2069 if (getToken().isCodeCompletion() && opName.back() ==
'.')
2070 return codeCompleteOperationName(dialectName);
2072 dialectName = getState().defaultDialectStack.back();
2073 opNameStorage = (dialectName +
"." + opName).str();
2074 opName = opNameStorage;
2084OperationParser::parseCustomOperation(ArrayRef<ResultRecord> resultIDs) {
2085 SMLoc opLoc = getToken().getLoc();
2086 StringRef originalOpName = getTokenSpelling();
2088 FailureOr<OperationName> opNameInfo = parseCustomOperationName();
2091 StringRef opName = opNameInfo->getStringRef();
2097 bool isIsolatedFromAbove =
false;
2099 StringRef defaultDialect =
"";
2100 if (
auto opInfo = opNameInfo->getRegisteredInfo()) {
2101 parseAssemblyFn = opInfo->getParseAssemblyFn();
2102 isIsolatedFromAbove = opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>();
2103 auto *iface = opInfo->getInterface<OpAsmOpInterface>();
2104 if (iface && !iface->getDefaultDialect().empty())
2105 defaultDialect = iface->getDefaultDialect();
2107 std::optional<Dialect::ParseOpHook> dialectHook;
2108 Dialect *dialect = opNameInfo->getDialect();
2110 InFlightDiagnostic
diag =
2111 emitError(opLoc) <<
"Dialect `" << opNameInfo->getDialectNamespace()
2112 <<
"' not found for custom op '" << originalOpName
2114 if (originalOpName != opName)
2115 diag <<
" (tried '" << opName <<
"' as well)";
2116 auto ¬e =
diag.attachNote();
2117 note <<
"Available dialects: ";
2118 std::vector<StringRef> registered =
getContext()->getAvailableDialects();
2119 auto loaded =
getContext()->getLoadedDialects();
2122 SmallVector<std::pair<StringRef, bool>> mergedDialects;
2123 auto regIt = registered.begin(), regEnd = registered.end();
2124 auto loadIt = loaded.rbegin(), loadEnd = loaded.rend();
2125 bool isRegistered =
false;
2126 bool isOnlyLoaded =
true;
2127 while (regIt != regEnd && loadIt != loadEnd) {
2128 StringRef reg = *regIt;
2129 StringRef
load = (*loadIt)->getNamespace();
2131 mergedDialects.emplace_back(
load, isOnlyLoaded);
2134 mergedDialects.emplace_back(reg, isRegistered);
2140 for (; regIt != regEnd; ++regIt)
2141 mergedDialects.emplace_back(*regIt, isRegistered);
2142 for (; loadIt != loadEnd; ++loadIt)
2143 mergedDialects.emplace_back((*loadIt)->getNamespace(), isOnlyLoaded);
2145 bool loadedUnregistered =
false;
2146 llvm::interleaveComma(mergedDialects, note, [&](
auto &pair) {
2149 loadedUnregistered =
true;
2154 if (loadedUnregistered)
2155 note <<
"(* corresponding to loaded but unregistered dialects)";
2156 note <<
"; for more info on dialect registration see "
2157 "https://mlir.llvm.org/getting_started/Faq/"
2158 "#registered-loaded-dependent-whats-up-with-dialects-management";
2163 InFlightDiagnostic
diag =
2164 emitError(opLoc) <<
"custom op '" << originalOpName <<
"' is unknown";
2165 if (originalOpName != opName)
2166 diag <<
" (tried '" << opName <<
"' as well)";
2169 parseAssemblyFn = *dialectHook;
2171 getState().defaultDialectStack.push_back(defaultDialect);
2172 llvm::scope_exit restoreDefaultDialect(
2173 [&]() { getState().defaultDialectStack.pop_back(); });
2177 llvm::PrettyStackTraceFormat fmt(
"MLIR Parser: custom op parser '%s'",
2178 opNameInfo->getIdentifier().data());
2181 auto srcLocation = getEncodedSourceLocation(opLoc);
2182 OperationState opState(srcLocation, *opNameInfo);
2189 CleanupOpStateRegions guard{opState};
2190 CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn,
2191 isIsolatedFromAbove, opName, *
this);
2192 if (opAsmParser.parseOperation(opState))
2196 if (opAsmParser.didEmitError())
2203 Operation *op = opBuilder.
create(opState);
2204 if (parseTrailingLocationSpecifier(op))
2220ParseResult OperationParser::parseLocationAlias(LocationAttr &loc) {
2221 Token tok = getToken();
2222 consumeToken(Token::hash_identifier);
2223 StringRef identifier = tok.
getSpelling().drop_front();
2224 assert(!identifier.contains(
'.') &&
2225 "unexpected dialect attribute token, expected alias");
2233 if (!(loc = dyn_cast<LocationAttr>(attr)))
2235 <<
"expected location, but found '" << attr <<
"'";
2239 loc = OpaqueLoc::get(deferredLocsReferences.size(),
2242 deferredLocsReferences.push_back(DeferredLocInfo{tok.
getLoc(), identifier});
2248OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) {
2250 if (!consumeIf(Token::kw_loc))
2252 if (parseToken(Token::l_paren,
"expected '(' in location"))
2254 Token tok = getToken();
2259 LocationAttr directLoc;
2260 if (tok.
is(Token::hash_identifier) && !tok.
getSpelling().contains(
'.')) {
2261 if (parseLocationAlias(directLoc))
2263 }
else if (parseLocationInstance(directLoc)) {
2267 if (parseToken(Token::r_paren,
"expected ')' in location"))
2270 if (
auto *op = llvm::dyn_cast_if_present<Operation *>(opOrArgument))
2273 cast<BlockArgument>(opOrArgument).setLoc(directLoc);
2281ParseResult OperationParser::parseRegion(Region ®ion,
2282 ArrayRef<Argument> entryArguments,
2283 bool isIsolatedNameScope) {
2285 Token lBraceTok = getToken();
2286 if (parseToken(Token::l_brace,
"expected '{' to begin a region"))
2294 if ((!entryArguments.empty() || getToken().isNot(Token::r_brace)) &&
2295 parseRegionBody(region, lBraceTok.
getLoc(), entryArguments,
2296 isIsolatedNameScope)) {
2299 consumeToken(Token::r_brace);
2308ParseResult OperationParser::parseRegionBody(Region ®ion, SMLoc startLoc,
2309 ArrayRef<Argument> entryArguments,
2310 bool isIsolatedNameScope) {
2311 auto currentPt = opBuilder.saveInsertionPoint();
2314 pushSSANameScope(isIsolatedNameScope);
2317 auto owningBlock = std::make_unique<Block>();
2318 llvm::scope_exit failureCleanup([&] {
2323 owningBlock->dropAllDefinedValueUses();
2326 Block *block = owningBlock.get();
2331 if (state.
asmState && getToken().isNot(Token::caret_identifier))
2335 if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) {
2337 if (getToken().is(Token::caret_identifier))
2338 return emitError(
"invalid block name in region with named arguments");
2340 for (
auto &entryArg : entryArguments) {
2341 auto &argInfo = entryArg.ssaName;
2344 if (
auto defLoc = getReferenceLoc(argInfo.name, argInfo.number)) {
2345 return emitError(argInfo.location,
"region entry argument '" +
2347 "' is already in use")
2348 .
attachNote(getEncodedSourceLocation(*defLoc))
2349 <<
"previously referenced here";
2351 Location loc = entryArg.sourceLoc.has_value()
2352 ? *entryArg.sourceLoc
2353 : getEncodedSourceLocation(argInfo.location);
2354 BlockArgument arg = block->addArgument(entryArg.type, loc);
2361 if (addDefinition(argInfo, arg))
2366 if (parseBlock(block))
2370 if (!entryArguments.empty() &&
2371 block->getNumArguments() > entryArguments.size()) {
2372 return emitError(
"entry block arguments were already defined");
2376 region.
push_back(owningBlock.release());
2377 while (getToken().isNot(Token::r_brace)) {
2378 Block *newBlock =
nullptr;
2379 if (parseBlock(newBlock))
2385 if (popSSANameScope())
2389 opBuilder.restoreInsertionPoint(currentPt);
2404ParseResult OperationParser::parseBlock(
Block *&block) {
2407 if (block && getToken().isNot(Token::caret_identifier))
2408 return parseBlockBody(block);
2410 SMLoc nameLoc = getToken().getLoc();
2411 auto name = getTokenSpelling();
2412 if (parseToken(Token::caret_identifier,
"expected block name"))
2416 auto &blockAndLoc = getBlockInfoByName(name);
2417 blockAndLoc.loc = nameLoc;
2422 std::unique_ptr<Block> inflightBlock;
2423 llvm::scope_exit cleanupOnFailure([&] {
2425 inflightBlock->dropAllDefinedValueUses();
2430 if (!blockAndLoc.block) {
2432 blockAndLoc.block = block;
2434 inflightBlock = std::make_unique<Block>();
2435 blockAndLoc.block = inflightBlock.get();
2442 }
else if (!eraseForwardRef(blockAndLoc.block)) {
2443 return emitError(nameLoc,
"redefinition of block '") << name <<
"'";
2447 inflightBlock.reset(blockAndLoc.block);
2453 block = blockAndLoc.block;
2456 if (getToken().is(Token::l_paren))
2457 if (parseOptionalBlockArgList(block))
2459 if (parseToken(Token::colon,
"expected ':' after block name"))
2463 ParseResult res = parseBlockBody(block);
2468 (void)inflightBlock.release();
2472ParseResult OperationParser::parseBlockBody(
Block *block) {
2474 opBuilder.setInsertionPointToEnd(block);
2477 while (getToken().isNot(Token::caret_identifier, Token::r_brace))
2478 if (parseOperation())
2487Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
2488 BlockDefinition &blockDef = getBlockInfoByName(name);
2489 if (!blockDef.block) {
2490 blockDef = {
new Block(), loc};
2491 insertForwardRef(blockDef.block, blockDef.loc);
2498 return blockDef.block;
2507ParseResult OperationParser::parseOptionalBlockArgList(
Block *owner) {
2508 if (getToken().is(Token::r_brace))
2514 unsigned nextArgument = 0;
2517 return parseSSADefOrUseAndType(
2518 [&](UnresolvedOperand useInfo, Type type) -> ParseResult {
2523 if (definingExistingArgs) {
2526 return emitError(
"too many arguments specified in argument list");
2531 return emitError(
"argument and block argument type mismatch");
2533 auto loc = getEncodedSourceLocation(useInfo.location);
2539 if (parseTrailingLocationSpecifier(arg))
2547 return addDefinition(useInfo, arg);
2556ParseResult OperationParser::codeCompleteSSAUse() {
2557 for (IsolatedSSANameScope &scope : isolatedNameScopes) {
2558 for (
auto &it : scope.values) {
2559 if (it.second.empty())
2561 Value frontValue = it.second.front().value;
2563 std::string detailData;
2564 llvm::raw_string_ostream detailOS(detailData);
2568 if (
auto result = dyn_cast<OpResult>(frontValue)) {
2569 if (!forwardRefPlaceholders.count(
result))
2570 detailOS <<
result.getOwner()->getName() <<
": ";
2572 detailOS <<
"arg #" << cast<BlockArgument>(frontValue).getArgNumber()
2577 detailOS << frontValue.
getType();
2582 if (it.second.size() > 1)
2583 detailOS <<
", ...";
2586 it.getKey(), std::move(detailData));
2593ParseResult OperationParser::codeCompleteBlock() {
2596 StringRef spelling = getTokenSpelling();
2597 if (!(spelling.empty() || spelling ==
"^"))
2600 for (
const auto &it : blocksByName.back())
2612class TopLevelOperationParser :
public Parser {
2614 explicit TopLevelOperationParser(ParserState &state) : Parser(state) {}
2617 ParseResult
parse(
Block *topLevelBlock, Location parserLoc);
2624 ParseResult parseAttributeAliasDef();
2630 ParseResult parseTypeAliasDef();
2636 ParseResult parseFileMetadataDictionary();
2639 ParseResult parseResourceFileMetadata(
2640 function_ref<ParseResult(StringRef, SMLoc)> parseBody);
2641 ParseResult parseDialectResourceFileMetadata();
2642 ParseResult parseExternalResourceFileMetadata();
2647class ParsedResourceEntry :
public AsmParsedResourceEntry {
2649 ParsedResourceEntry(std::string key, SMLoc keyLoc, Token value, Parser &p)
2650 : key(std::move(key)), keyLoc(keyLoc), value(value), p(p) {}
2651 ~ParsedResourceEntry()
override =
default;
2653 StringRef getKey() const final {
return key; }
2655 InFlightDiagnostic
emitError() const final {
return p.emitError(keyLoc); }
2658 if (value.isAny(Token::kw_true, Token::kw_false))
2659 return AsmResourceEntryKind::Bool;
2660 return value.getSpelling().starts_with(
"\"0x")
2661 ? AsmResourceEntryKind::Blob
2662 : AsmResourceEntryKind::String;
2665 FailureOr<bool> parseAsBool() const final {
2666 if (value.is(Token::kw_true))
2668 if (value.is(Token::kw_false))
2670 return p.emitError(value.getLoc(),
2671 "expected 'true' or 'false' value for key '" + key +
2675 FailureOr<std::string> parseAsString() const final {
2676 if (value.isNot(Token::string))
2677 return p.emitError(value.getLoc(),
2678 "expected string value for key '" + key +
"'");
2679 return value.getStringValue();
2682 FailureOr<AsmResourceBlob>
2683 parseAsBlob(BlobAllocatorFn allocator)
const final {
2687 std::optional<std::string> blobData =
2688 value.is(Token::string) ? value.getHexStringValue() : std::nullopt;
2690 return p.emitError(value.getLoc(),
2691 "expected hex string blob for key '" + key +
"'");
2695 if (blobData->size() <
sizeof(uint32_t)) {
2696 return p.emitError(value.getLoc(),
2697 "expected hex string blob for key '" + key +
2698 "' to encode alignment in first 4 bytes");
2700 llvm::support::ulittle32_t align;
2701 memcpy(&align, blobData->data(),
sizeof(uint32_t));
2702 if (align && !llvm::isPowerOf2_32(align)) {
2703 return p.emitError(value.getLoc(),
2704 "expected hex string blob for key '" + key +
2705 "' to encode alignment in first 4 bytes, but got "
2706 "non-power-of-2 value: " +
2711 StringRef data = StringRef(*blobData).drop_front(
sizeof(uint32_t));
2713 return AsmResourceBlob();
2717 AsmResourceBlob blob = allocator(data.size(), align);
2718 assert(llvm::isAddrAligned(llvm::Align(align), blob.
getData().data()) &&
2720 "blob allocator did not return a properly aligned address");
2733ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
2734 assert(getToken().is(Token::hash_identifier));
2735 StringRef aliasName = getTokenSpelling().drop_front();
2739 return emitError(
"redefinition of attribute alias id '" + aliasName +
"'");
2742 if (aliasName.contains(
'.'))
2743 return emitError(
"attribute names with a '.' are reserved for "
2744 "dialect-defined names");
2746 SMRange location = getToken().getLocRange();
2747 consumeToken(Token::hash_identifier);
2750 if (parseToken(Token::equal,
"expected '=' in attribute alias definition"))
2765ParseResult TopLevelOperationParser::parseTypeAliasDef() {
2766 assert(getToken().is(Token::exclamation_identifier));
2767 StringRef aliasName = getTokenSpelling().drop_front();
2771 return emitError(
"redefinition of type alias id '" + aliasName +
"'");
2774 if (aliasName.contains(
'.'))
2775 return emitError(
"type names with a '.' are reserved for "
2776 "dialect-defined names");
2778 SMRange location = getToken().getLocRange();
2779 consumeToken(Token::exclamation_identifier);
2782 if (parseToken(Token::equal,
"expected '=' in type alias definition"))
2797ParseResult TopLevelOperationParser::parseFileMetadataDictionary() {
2798 consumeToken(Token::file_metadata_begin);
2799 return parseCommaSeparatedListUntil(
2800 Token::file_metadata_end, [&]() -> ParseResult {
2802 SMLoc keyLoc = getToken().getLoc();
2804 if (
failed(parseOptionalKeyword(&key)))
2805 return emitError(
"expected identifier key in file "
2806 "metadata dictionary");
2807 if (parseToken(Token::colon,
"expected ':'"))
2811 if (key ==
"dialect_resources")
2812 return parseDialectResourceFileMetadata();
2813 if (key ==
"external_resources")
2814 return parseExternalResourceFileMetadata();
2815 return emitError(keyLoc,
"unknown key '" + key +
2816 "' in file metadata dictionary");
2820ParseResult TopLevelOperationParser::parseResourceFileMetadata(
2821 function_ref<ParseResult(StringRef, SMLoc)> parseBody) {
2822 if (parseToken(Token::l_brace,
"expected '{'"))
2825 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2827 SMLoc nameLoc = getToken().getLoc();
2829 if (
failed(parseOptionalKeyword(&name)))
2830 return emitError(
"expected identifier key for 'resource' entry");
2832 if (parseToken(Token::colon,
"expected ':'") ||
2833 parseToken(Token::l_brace,
"expected '{'"))
2835 return parseBody(name, nameLoc);
2839ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() {
2840 return parseResourceFileMetadata([&](StringRef name,
2841 SMLoc nameLoc) -> ParseResult {
2843 Dialect *dialect =
getContext()->getOrLoadDialect(name);
2845 return emitError(nameLoc,
"dialect '" + name +
"' is unknown");
2846 const auto *handler = dyn_cast<OpAsmDialectInterface>(dialect);
2848 return emitError() <<
"unexpected 'resource' section for dialect '"
2852 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2854 SMLoc keyLoc = getToken().getLoc();
2856 if (
failed(parseResourceHandle(handler, key)) ||
2857 parseToken(Token::colon,
"expected ':'"))
2859 Token valueTok = getToken();
2862 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2863 return handler->parseResource(entry);
2868ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() {
2869 return parseResourceFileMetadata([&](StringRef name,
2870 SMLoc nameLoc) -> ParseResult {
2876 <<
"ignoring unknown external resources for '" << name <<
"'";
2879 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2881 SMLoc keyLoc = getToken().getLoc();
2883 if (
failed(parseOptionalKeywordOrString(&key)))
2885 "expected identifier key for 'external_resources' entry");
2886 if (parseToken(Token::colon,
"expected ':'"))
2888 Token valueTok = getToken();
2893 ParsedResourceEntry entry(key, keyLoc, valueTok, *
this);
2899ParseResult TopLevelOperationParser::parse(
Block *topLevelBlock,
2900 Location parserLoc) {
2902 OwningOpRef<ModuleOp> topLevelOp(ModuleOp::create(parserLoc));
2903 OperationParser opParser(state, topLevelOp.get());
2905 switch (getToken().getKind()) {
2908 if (opParser.parseOperation())
2914 if (opParser.finalize())
2919 auto &parsedOps = topLevelOp->getBody()->getOperations();
2921 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(),
2933 case Token::hash_identifier:
2934 if (parseAttributeAliasDef())
2939 case Token::exclamation_identifier:
2940 if (parseTypeAliasDef())
2945 case Token::file_metadata_begin:
2946 if (parseFileMetadataDictionary())
2959 const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
2967 codeCompleteContext);
2968 return TopLevelOperationParser(state).parse(block, parserLoc);
static size_t findCommentStart(StringRef line)
Find the start of a line comment (//) in the given string, ignoring occurrences inside string literal...
static bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
static std::string diag(const llvm::Value &value)
#define MLIR_DECLARE_EXPLICIT_SELF_OWNING_TYPE_ID(CLASS_NAME)
#define MLIR_DEFINE_EXPLICIT_SELF_OWNING_TYPE_ID(CLASS_NAME)
This class provides an abstract interface into the parser for hooking in code completion events.
virtual void appendBlockCompletion(StringRef name)=0
Append the given block as a code completion result for block name completions.
virtual void appendSSAValueCompletion(StringRef name, std::string typeData)=0
Append the given SSA value as a code completion result for SSA value completions.
virtual ~AsmParserCodeCompleteContext()
This class represents state from a parsed MLIR textual format string.
void startRegionDefinition()
Start a definition for a region nested under the current operation.
void startOperationDefinition(const OperationName &opName)
Start a definition for an operation with the given name.
void finalizeOperationDefinition(Operation *op, SMRange nameLoc, SMLoc endLoc, ArrayRef< std::pair< unsigned, SMLoc > > resultGroups={})
Finalize the most recently started operation definition.
void addAttrAliasUses(StringRef name, SMRange locations)
void addAttrAliasDefinition(StringRef name, SMRange location, Attribute value)
void finalize(Operation *topLevelOp)
Finalize any in-progress parser state under the given top-level operation.
void addUses(Value value, ArrayRef< SMLoc > locations)
Add a source uses of the given value.
void refineDefinition(Value oldValue, Value newValue)
Refine the oldValue to the newValue.
void finalizeRegionDefinition()
Finalize the most recently started region definition.
void addTypeAliasDefinition(StringRef name, SMRange location, Type value)
void addDefinition(Block *block, SMLoc location)
Add a definition of the given entity.
MutableArrayRef< char > getMutableData()
Return a mutable reference to the raw underlying data of this blob.
ArrayRef< char > getData() const
Return the raw underlying data of this blob.
bool isMutable() const
Return if the data of this blob is mutable.
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry)=0
Parse the given resource entry.
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
OpListType::iterator iterator
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
OpListType & getOperations()
void dropAllDefinedValueUses()
This drops all uses of values defined in this block or in the blocks of nested regions wherever the u...
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
BlockArgListType getArguments()
Diagnostic & append(Arg1 &&arg1, Arg2 &&arg2, Args &&...args)
Append arguments to the diagnostic.
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.