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());
 
  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.
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.
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.