22#include "llvm/Support/ErrorHandling.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include "llvm/Support/SourceMgr.h"
25#include "llvm/Support/raw_ostream.h"
46enum AffineHighPrecOp {
58class AffineParser :
public Parser {
60 AffineParser(ParserState &state,
bool allowParsingSSAIds =
false,
62 : Parser(state), allowParsingSSAIds(allowParsingSSAIds),
63 parseElement(parseElement) {}
65 ParseResult parseAffineMapRange(
unsigned numDims,
unsigned numSymbols,
67 ParseResult parseAffineMapOrIntegerSetInline(AffineMap &map, IntegerSet &set);
69 parseAffineExprInline(ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet,
71 ParseResult parseIntegerSetConstraints(
unsigned numDims,
unsigned numSymbols,
73 ParseResult parseAffineMapOfSSAIds(AffineMap &map,
74 OpAsmParser::Delimiter delimiter);
75 ParseResult parseAffineExprOfSSAIds(AffineExpr &expr);
79 AffineLowPrecOp consumeIfLowPrecOp();
80 AffineHighPrecOp consumeIfHighPrecOp();
83 ParseResult parseDimIdList(
unsigned &numDims);
84 ParseResult parseSymbolIdList(
unsigned &numSymbols);
85 ParseResult parseDimAndOptionalSymbolIdList(
unsigned &numDims,
86 unsigned &numSymbols);
87 ParseResult parseIdentifierDefinition(AffineExpr idExpr);
89 AffineExpr parseAffineExpr();
90 AffineExpr parseParentheticalExpr();
91 AffineExpr parseNegateExpression(AffineExpr
lhs);
92 AffineExpr parseIntegerExpr();
93 AffineExpr parseBareIdExpr();
94 AffineExpr parseSSAIdExpr(
bool isSymbol);
95 AffineExpr parseSymbolSSAIdExpr();
98 AffineExpr
rhs, SMLoc opLoc);
101 AffineExpr parseAffineOperandExpr(AffineExpr
lhs);
102 AffineExpr parseAffineLowPrecOpExpr(AffineExpr llhs, AffineLowPrecOp llhsOp);
103 AffineExpr parseAffineHighPrecOpExpr(AffineExpr llhs, AffineHighPrecOp llhsOp,
105 AffineExpr parseAffineConstraint(
bool *isEq);
108 bool allowParsingSSAIds;
110 unsigned numDimOperands = 0;
111 unsigned numSymbolOperands = 0;
112 SmallVector<std::pair<StringRef, AffineExpr>, 4> dimsAndSymbols;
119AffineExpr AffineParser::getAffineBinaryOpExpr(AffineHighPrecOp op,
125 if (!
lhs.isSymbolicOrConstant() && !
rhs.isSymbolicOrConstant()) {
126 emitError(opLoc,
"non-affine expression: at least one of the multiply "
127 "operands has to be either a constant or symbolic");
132 if (!
rhs.isSymbolicOrConstant()) {
133 emitError(opLoc,
"non-affine expression: right operand of floordiv "
134 "has to be either a constant or symbolic");
139 if (!
rhs.isSymbolicOrConstant()) {
140 emitError(opLoc,
"non-affine expression: right operand of ceildiv "
141 "has to be either a constant or symbolic");
146 if (!
rhs.isSymbolicOrConstant()) {
147 emitError(opLoc,
"non-affine expression: right operand of mod "
148 "has to be either a constant or symbolic");
153 llvm_unreachable(
"can't create affine expression for null high prec op");
156 llvm_unreachable(
"Unknown AffineHighPrecOp");
160AffineExpr AffineParser::getAffineBinaryOpExpr(AffineLowPrecOp op,
161 AffineExpr
lhs, AffineExpr
rhs) {
163 case AffineLowPrecOp::Add:
165 case AffineLowPrecOp::Sub:
167 case AffineLowPrecOp::LNoOp:
168 llvm_unreachable(
"can't create affine expression for null low prec op");
171 llvm_unreachable(
"Unknown AffineLowPrecOp");
176AffineLowPrecOp AffineParser::consumeIfLowPrecOp() {
177 switch (getToken().getKind()) {
179 consumeToken(Token::plus);
180 return AffineLowPrecOp::Add;
182 consumeToken(Token::minus);
183 return AffineLowPrecOp::Sub;
185 return AffineLowPrecOp::LNoOp;
191AffineHighPrecOp AffineParser::consumeIfHighPrecOp() {
192 switch (getToken().getKind()) {
194 consumeToken(Token::star);
196 case Token::kw_floordiv:
197 consumeToken(Token::kw_floordiv);
199 case Token::kw_ceildiv:
200 consumeToken(Token::kw_ceildiv);
203 consumeToken(Token::kw_mod);
219AffineExpr AffineParser::parseAffineHighPrecOpExpr(AffineExpr llhs,
220 AffineHighPrecOp llhsOp,
222 AffineExpr
lhs = parseAffineOperandExpr(llhs);
227 auto opLoc = getToken().getLoc();
228 if (AffineHighPrecOp op = consumeIfHighPrecOp()) {
233 return parseAffineHighPrecOpExpr(expr, op, opLoc);
236 return parseAffineHighPrecOpExpr(
lhs, op, opLoc);
250AffineExpr AffineParser::parseParentheticalExpr() {
251 if (parseToken(Token::l_paren,
"expected '('"))
253 if (getToken().is(Token::r_paren))
254 return emitError(
"no expression inside parentheses"),
nullptr;
256 auto expr = parseAffineExpr();
257 if (!expr || parseToken(Token::r_paren,
"expected ')'"))
266AffineExpr AffineParser::parseNegateExpression(AffineExpr
lhs) {
267 if (parseToken(Token::minus,
"expected '-'"))
270 AffineExpr operand = parseAffineOperandExpr(
lhs);
277 return emitError(
"missing operand of negation"),
nullptr;
278 return (-1) * operand;
285 return token.
isAny(Token::bare_identifier, Token::inttype) ||
292AffineExpr AffineParser::parseBareIdExpr() {
294 return emitWrongTokenError(
"expected bare identifier"),
nullptr;
296 StringRef sRef = getTokenSpelling();
297 for (
auto entry : dimsAndSymbols) {
298 if (entry.first == sRef) {
304 return emitWrongTokenError(
"use of undeclared identifier"),
nullptr;
308AffineExpr AffineParser::parseSSAIdExpr(
bool isSymbol) {
309 if (!allowParsingSSAIds)
310 return emitWrongTokenError(
"unexpected ssa identifier"),
nullptr;
311 if (getToken().isNot(Token::percent_identifier))
312 return emitWrongTokenError(
"expected ssa identifier"),
nullptr;
313 auto name = getTokenSpelling();
315 for (
auto entry : dimsAndSymbols) {
316 if (entry.first == name) {
317 consumeToken(Token::percent_identifier);
322 if (parseElement(isSymbol))
324 auto idExpr = isSymbol
327 dimsAndSymbols.push_back({name, idExpr});
331AffineExpr AffineParser::parseSymbolSSAIdExpr() {
332 if (parseToken(Token::kw_symbol,
"expected symbol keyword") ||
333 parseToken(Token::l_paren,
"expected '(' at start of SSA symbol"))
335 AffineExpr symbolExpr = parseSSAIdExpr(
true);
338 if (parseToken(Token::r_paren,
"expected ')' at end of SSA symbol"))
346AffineExpr AffineParser::parseIntegerExpr() {
347 auto val = getToken().getUInt64IntegerValue();
348 if (!val.has_value() || (int64_t)*val < 0)
349 return emitError(
"constant too large for index"),
nullptr;
351 consumeToken(Token::integer);
352 return builder.getAffineConstantExpr((int64_t)*val);
364AffineExpr AffineParser::parseAffineOperandExpr(AffineExpr
lhs) {
365 switch (getToken().getKind()) {
366 case Token::kw_symbol:
367 return parseSymbolSSAIdExpr();
368 case Token::percent_identifier:
369 return parseSSAIdExpr(
false);
371 return parseIntegerExpr();
373 return parseParentheticalExpr();
375 return parseNegateExpression(
lhs);
376 case Token::kw_ceildiv:
377 case Token::kw_floordiv:
380 return parseBareIdExpr();
384 emitError(
"missing right operand of binary operator");
386 emitError(
"missing left operand of binary operator");
391 return parseBareIdExpr();
394 emitError(
"missing right operand of binary operator");
422AffineExpr AffineParser::parseAffineLowPrecOpExpr(AffineExpr llhs,
423 AffineLowPrecOp llhsOp) {
425 if (!(
lhs = parseAffineOperandExpr(llhs)))
429 if (AffineLowPrecOp lOp = consumeIfLowPrecOp()) {
432 return parseAffineLowPrecOpExpr(sum, lOp);
435 return parseAffineLowPrecOpExpr(
lhs, lOp);
437 auto opLoc = getToken().getLoc();
438 if (AffineHighPrecOp hOp = consumeIfHighPrecOp()) {
441 AffineExpr highRes = parseAffineHighPrecOpExpr(
lhs, hOp, opLoc);
452 if (AffineLowPrecOp nextOp = consumeIfLowPrecOp())
453 return parseAffineLowPrecOpExpr(expr, nextOp);
478AffineExpr AffineParser::parseAffineExpr() {
479 return parseAffineLowPrecOpExpr(
nullptr, AffineLowPrecOp::LNoOp);
485ParseResult AffineParser::parseIdentifierDefinition(AffineExpr idExpr) {
487 return emitWrongTokenError(
"expected bare identifier");
489 auto name = getTokenSpelling();
490 for (
auto entry : dimsAndSymbols) {
491 if (entry.first == name)
492 return emitError(
"redefinition of identifier '" + name +
"'");
496 dimsAndSymbols.push_back({name, idExpr});
501ParseResult AffineParser::parseDimIdList(
unsigned &numDims) {
502 auto parseElt = [&]() -> ParseResult {
504 return parseIdentifierDefinition(dimension);
507 " in dimensional identifier list");
511ParseResult AffineParser::parseSymbolIdList(
unsigned &numSymbols) {
512 auto parseElt = [&]() -> ParseResult {
514 return parseIdentifierDefinition(symbol);
522AffineParser::parseDimAndOptionalSymbolIdList(
unsigned &numDims,
523 unsigned &numSymbols) {
524 if (parseDimIdList(numDims)) {
527 if (!getToken().is(Token::l_square)) {
531 return parseSymbolIdList(numSymbols);
535ParseResult AffineParser::parseAffineMapOrIntegerSetInline(AffineMap &map,
537 unsigned numDims = 0, numSymbols = 0;
540 if (parseDimAndOptionalSymbolIdList(numDims, numSymbols))
543 if (consumeIf(Token::arrow))
544 return parseAffineMapRange(numDims, numSymbols, map);
546 if (parseToken(Token::colon,
"expected '->' or ':'"))
548 return parseIntegerSetConstraints(numDims, numSymbols, set);
552ParseResult AffineParser::parseAffineExprInline(
553 ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet, AffineExpr &expr) {
554 dimsAndSymbols.assign(symbolSet.begin(), symbolSet.end());
555 expr = parseAffineExpr();
556 return success(expr !=
nullptr);
561AffineParser::parseAffineMapOfSSAIds(AffineMap &map,
562 OpAsmParser::Delimiter delimiter) {
564 SmallVector<AffineExpr, 4> exprs;
565 auto parseElt = [&]() -> ParseResult {
566 auto elt = parseAffineExpr();
567 exprs.push_back(elt);
568 return elt ?
success() : failure();
579 map =
AffineMap::get(numDimOperands, dimsAndSymbols.size() - numDimOperands,
585ParseResult AffineParser::parseAffineExprOfSSAIds(AffineExpr &expr) {
586 expr = parseAffineExpr();
587 return success(expr !=
nullptr);
596ParseResult AffineParser::parseAffineMapRange(
unsigned numDims,
599 SmallVector<AffineExpr, 4> exprs;
600 auto parseElt = [&]() -> ParseResult {
601 auto elt = parseAffineExpr();
602 ParseResult res = elt ?
success() : failure();
603 exprs.push_back(elt);
612 " in affine map range"))
633AffineExpr AffineParser::parseAffineConstraint(
bool *isEq) {
634 AffineExpr lhsExpr = parseAffineExpr();
639 if (consumeIf(Token::greater) && consumeIf(Token::equal)) {
640 AffineExpr rhsExpr = parseAffineExpr();
644 return lhsExpr - rhsExpr;
648 if (consumeIf(Token::less) && consumeIf(Token::equal)) {
649 AffineExpr rhsExpr = parseAffineExpr();
653 return rhsExpr - lhsExpr;
657 if (consumeIf(Token::equal) && consumeIf(Token::equal)) {
658 AffineExpr rhsExpr = parseAffineExpr();
662 return lhsExpr - rhsExpr;
665 return emitError(
"expected '== affine-expr' or '>= affine-expr' at end of "
666 "affine constraint"),
677ParseResult AffineParser::parseIntegerSetConstraints(
unsigned numDims,
680 SmallVector<AffineExpr, 4> constraints;
681 SmallVector<bool, 4> isEqs;
682 auto parseElt = [&]() -> ParseResult {
684 auto elt = parseAffineConstraint(&isEq);
685 ParseResult res = elt ?
success() : failure();
687 constraints.push_back(elt);
688 isEqs.push_back(isEq);
695 " in integer set constraint list"))
699 if (constraints.empty()) {
718 return AffineParser(
state).parseAffineMapOrIntegerSetInline(map, set);
726 return emitError(curLoc,
"expected AffineMap, but got IntegerSet");
731 return AffineParser(
state).parseAffineExprInline(symbolSet, expr);
739 return emitError(curLoc,
"expected IntegerSet, but got AffineMap");
749 return AffineParser(
state,
true, parseElement)
750 .parseAffineMapOfSSAIds(map, delimiter);
758 return AffineParser(
state,
true, parseElement)
759 .parseAffineExprOfSSAIds(expr);
764 llvm::SourceMgr sourceMgr;
765 auto memBuffer = llvm::MemoryBuffer::getMemBuffer(
766 inputStr,
"<mlir_parser_buffer>",
768 sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc());
780 if (endTok.
isNot(Token::eof)) {
791 "expected string to represent AffineMap, but got IntegerSet instead");
800 "expected string to represent IntegerSet, but got AffineMap instead");
static bool isIdentifier(const Token &token)
Returns true if the given token can be represented as an identifier.
static void parseAffineMapOrIntegerSet(StringRef inputStr, MLIRContext *context, AffineMap &map, IntegerSet &set)
Base type for affine expression.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
Delimiter
These are the supported delimiters around operand lists and region argument lists,...
An integer set representing a conjunction of one or more affine equalities and inequalities.
static IntegerSet get(unsigned dimCount, unsigned symbolCount, ArrayRef< AffineExpr > constraints, ArrayRef< bool > eqFlags)
MLIRContext is the top-level object for a collection of MLIR operations.
This class represents a configuration for the MLIR assembly parser.
This class is a utility diagnostic handler for use with llvm::SourceMgr.
This represents a token in the MLIR syntax.
bool isKeyword() const
Return true if this is one of the keyword token kinds (e.g. kw_if).
bool isAny(Kind k1, Kind k2) const
This class implement support for parsing global entities like attributes and types.
ParseResult parseAffineMapReference(AffineMap &map)
InFlightDiagnostic emitError(const Twine &message={})
Emit an error and return failure.
ParserState & state
The Parser is subclassed and reinstantiated.
ParseResult parseAffineMapOrIntegerSetReference(AffineMap &map, IntegerSet &set)
Parse a reference to either an affine map, expr, or an integer set.
ParseResult parseAffineMapOfSSAIds(AffineMap &map, function_ref< ParseResult(bool)> parseElement, Delimiter delimiter)
Parse an AffineMap where the dim and symbol identifiers are SSA ids.
ParseResult parseIntegerSetReference(IntegerSet &set)
ParseResult parseAffineExprReference(ArrayRef< std::pair< StringRef, AffineExpr > > symbolSet, AffineExpr &expr)
const Token & getToken() const
Return the current token the parser is inspecting.
ParseResult parseAffineExprOfSSAIds(AffineExpr &expr, function_ref< ParseResult(bool)> parseElement)
Parse an AffineExpr where dim and symbol identifiers are SSA ids.
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-...
Include the generated interface declarations.
AffineMap parseAffineMap(llvm::StringRef str, MLIRContext *context)
This parses a single IntegerSet/AffineMap to an MLIR context if it was valid.
const FrozenRewritePatternSet GreedyRewriteConfig config
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
@ Mul
RHS of mul is always a constant or a symbolic expression.
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
AffineExpr getAffineBinaryOpExpr(AffineExprKind kind, AffineExpr lhs, AffineExpr rhs)
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
IntegerSet parseIntegerSet(llvm::StringRef str, MLIRContext *context)
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
llvm::function_ref< Fn > function_ref
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
This class refers to all of the state maintained globally by the parser, such as the current lexer po...
This class contains record of any parsed top-level symbols.