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"
37 enum AffineLowPrecOp {
46 enum AffineHighPrecOp {
58 class 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,
69 parseAffineExprInline(
ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet,
71 ParseResult parseIntegerSetConstraints(
unsigned numDims,
unsigned numSymbols,
73 ParseResult parseAffineMapOfSSAIds(
AffineMap &map,
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);
108 bool allowParsingSSAIds;
110 unsigned numDimOperands = 0;
111 unsigned numSymbolOperands = 0;
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");
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");
176 AffineLowPrecOp 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;
191 AffineHighPrecOp 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);
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);
250 AffineExpr 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 ')'"))
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) ||
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;
308 AffineExpr 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});
331 AffineExpr AffineParser::parseSymbolSSAIdExpr() {
332 if (parseToken(Token::kw_symbol,
"expected symbol keyword") ||
333 parseToken(Token::l_paren,
"expected '(' at start of SSA symbol"))
338 if (parseToken(Token::r_paren,
"expected ')' at end of SSA symbol"))
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);
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");
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);
479 return parseAffineLowPrecOpExpr(
nullptr, AffineLowPrecOp::LNoOp);
485 ParseResult 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});
501 ParseResult AffineParser::parseDimIdList(
unsigned &numDims) {
502 auto parseElt = [&]() -> ParseResult {
504 return parseIdentifierDefinition(dimension);
507 " in dimensional identifier list");
511 ParseResult AffineParser::parseSymbolIdList(
unsigned &numSymbols) {
512 auto parseElt = [&]() -> ParseResult {
514 return parseIdentifierDefinition(symbol);
522 AffineParser::parseDimAndOptionalSymbolIdList(
unsigned &numDims,
523 unsigned &numSymbols) {
524 if (parseDimIdList(numDims)) {
527 if (!getToken().is(Token::l_square)) {
531 return parseSymbolIdList(numSymbols);
535 ParseResult 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);
552 ParseResult AffineParser::parseAffineExprInline(
554 dimsAndSymbols.assign(symbolSet.begin(), symbolSet.end());
555 expr = parseAffineExpr();
556 return success(expr !=
nullptr);
561 AffineParser::parseAffineMapOfSSAIds(
AffineMap &map,
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,
585 ParseResult AffineParser::parseAffineExprOfSSAIds(
AffineExpr &expr) {
586 expr = parseAffineExpr();
587 return success(expr !=
nullptr);
596 ParseResult AffineParser::parseAffineMapRange(
unsigned numDims,
600 auto parseElt = [&]() -> ParseResult {
601 auto elt = parseAffineExpr();
602 ParseResult res = elt ? success() : failure();
603 exprs.push_back(elt);
612 " in affine map range"))
633 AffineExpr AffineParser::parseAffineConstraint(
bool *isEq) {
639 if (consumeIf(Token::greater) && consumeIf(Token::equal)) {
644 return lhsExpr - rhsExpr;
648 if (consumeIf(Token::less) && consumeIf(Token::equal)) {
653 return rhsExpr - lhsExpr;
657 if (consumeIf(Token::equal) && consumeIf(Token::equal)) {
662 return lhsExpr - rhsExpr;
665 return emitError(
"expected '== affine-expr' or '>= affine-expr' at end of "
666 "affine constraint"),
677 ParseResult AffineParser::parseIntegerSetConstraints(
unsigned numDims,
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());
771 ParserState state(sourceMgr, config, symbolState,
nullptr,
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)
static MLIRContext * getContext(OpFoldResult val)
Base type for affine expression.
bool isSymbolicOrConstant() const
Returns true if this expression is made out of only symbols and constants, i.e., it does not involve ...
AffineExpr floorDiv(uint64_t v) const
AffineExpr ceilDiv(uint64_t v) const
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 parseAffineExprReference(ArrayRef< std::pair< StringRef, AffineExpr >> symbolSet, AffineExpr &expr)
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 parseAffineExprOfSSAIds(AffineExpr &expr, function_ref< ParseResult(bool)> parseElement)
Parse an AffineExpr where dim and symbol identifiers are SSA ids.
const Token & getToken() const
Return the current token the parser is inspecting.
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.
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.
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.