//===- AffineParser.cpp - MLIR Affine Parser ------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements a parser for Affine structures. // //===----------------------------------------------------------------------===// #include "Parser.h" #include "ParserState.h" #include "mlir/IR/AffineExpr.h" #include "mlir/IR/AffineMap.h" #include "mlir/IR/AsmState.h" #include "mlir/IR/Diagnostics.h" #include "mlir/IR/IntegerSet.h" #include "mlir/IR/OpImplementation.h" #include "mlir/Support/LLVM.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdint> #include <utility> usingnamespacemlir; usingnamespacemlir::detail; namespace { /// Lower precedence ops (all at the same precedence level). LNoOp is false in /// the boolean sense. enum AffineLowPrecOp { … }; /// Higher precedence ops - all at the same precedence level. HNoOp is false /// in the boolean sense. enum AffineHighPrecOp { … }; /// This is a specialized parser for affine structures (affine maps, affine /// expressions, and integer sets), maintaining the state transient to their /// bodies. class AffineParser : public Parser { … }; } // namespace /// Create an affine binary high precedence op expression (mul's, div's, mod). /// opLoc is the location of the op token to be used to report errors /// for non-conforming expressions. AffineExpr AffineParser::getAffineBinaryOpExpr(AffineHighPrecOp op, AffineExpr lhs, AffineExpr rhs, SMLoc opLoc) { … } /// Create an affine binary low precedence op expression (add, sub). AffineExpr AffineParser::getAffineBinaryOpExpr(AffineLowPrecOp op, AffineExpr lhs, AffineExpr rhs) { … } /// Consume this token if it is a lower precedence affine op (there are only /// two precedence levels). AffineLowPrecOp AffineParser::consumeIfLowPrecOp() { … } /// Consume this token if it is a higher precedence affine op (there are only /// two precedence levels) AffineHighPrecOp AffineParser::consumeIfHighPrecOp() { … } /// Parse a high precedence op expression list: mul, div, and mod are high /// precedence binary ops, i.e., parse a /// expr_1 op_1 expr_2 op_2 ... expr_n /// where op_1, op_2 are all a AffineHighPrecOp (mul, div, mod). /// All affine binary ops are left associative. /// Given llhs, returns (llhs llhsOp lhs) op rhs, or (lhs op rhs) if llhs is /// null. If no rhs can be found, returns (llhs llhsOp lhs) or lhs if llhs is /// null. llhsOpLoc is the location of the llhsOp token that will be used to /// report an error for non-conforming expressions. AffineExpr AffineParser::parseAffineHighPrecOpExpr(AffineExpr llhs, AffineHighPrecOp llhsOp, SMLoc llhsOpLoc) { … } /// Parse an affine expression inside parentheses. /// /// affine-expr ::= `(` affine-expr `)` AffineExpr AffineParser::parseParentheticalExpr() { … } /// Parse the negation expression. /// /// affine-expr ::= `-` affine-expr AffineExpr AffineParser::parseNegateExpression(AffineExpr lhs) { … } /// Returns true if the given token can be represented as an identifier. static bool isIdentifier(const Token &token) { … } /// Parse a bare id that may appear in an affine expression. /// /// affine-expr ::= bare-id AffineExpr AffineParser::parseBareIdExpr() { … } /// Parse an SSA id which may appear in an affine expression. AffineExpr AffineParser::parseSSAIdExpr(bool isSymbol) { … } AffineExpr AffineParser::parseSymbolSSAIdExpr() { … } /// Parse a positive integral constant appearing in an affine expression. /// /// affine-expr ::= integer-literal AffineExpr AffineParser::parseIntegerExpr() { … } /// Parses an expression that can be a valid operand of an affine expression. /// lhs: if non-null, lhs is an affine expression that is the lhs of a binary /// operator, the rhs of which is being parsed. This is used to determine /// whether an error should be emitted for a missing right operand. // Eg: for an expression without parentheses (like i + j + k + l), each // of the four identifiers is an operand. For i + j*k + l, j*k is not an // operand expression, it's an op expression and will be parsed via // parseAffineHighPrecOpExpression(). However, for i + (j*k) + -l, (j*k) and // -l are valid operands that will be parsed by this function. AffineExpr AffineParser::parseAffineOperandExpr(AffineExpr lhs) { … } /// Parse affine expressions that are bare-id's, integer constants, /// parenthetical affine expressions, and affine op expressions that are a /// composition of those. /// /// All binary op's associate from left to right. /// /// {add, sub} have lower precedence than {mul, div, and mod}. /// /// Add, sub'are themselves at the same precedence level. Mul, floordiv, /// ceildiv, and mod are at the same higher precedence level. Negation has /// higher precedence than any binary op. /// /// llhs: the affine expression appearing on the left of the one being parsed. /// This function will return ((llhs llhsOp lhs) op rhs) if llhs is non null, /// and lhs op rhs otherwise; if there is no rhs, llhs llhsOp lhs is returned /// if llhs is non-null; otherwise lhs is returned. This is to deal with left /// associativity. /// /// Eg: when the expression is e1 + e2*e3 + e4, with e1 as llhs, this function /// will return the affine expr equivalent of (e1 + (e2*e3)) + e4, where /// (e2*e3) will be parsed using parseAffineHighPrecOpExpr(). AffineExpr AffineParser::parseAffineLowPrecOpExpr(AffineExpr llhs, AffineLowPrecOp llhsOp) { … } /// Parse an affine expression. /// affine-expr ::= `(` affine-expr `)` /// | `-` affine-expr /// | affine-expr `+` affine-expr /// | affine-expr `-` affine-expr /// | affine-expr `*` affine-expr /// | affine-expr `floordiv` affine-expr /// | affine-expr `ceildiv` affine-expr /// | affine-expr `mod` affine-expr /// | bare-id /// | integer-literal /// /// Additional conditions are checked depending on the production. For eg., /// one of the operands for `*` has to be either constant/symbolic; the second /// operand for floordiv, ceildiv, and mod has to be a positive integer. AffineExpr AffineParser::parseAffineExpr() { … } /// Parse a dim or symbol from the lists appearing before the actual /// expressions of the affine map. Update our state to store the /// dimensional/symbolic identifier. ParseResult AffineParser::parseIdentifierDefinition(AffineExpr idExpr) { … } /// Parse the list of dimensional identifiers to an affine map. ParseResult AffineParser::parseDimIdList(unsigned &numDims) { … } /// Parse the list of symbolic identifiers to an affine map. ParseResult AffineParser::parseSymbolIdList(unsigned &numSymbols) { … } /// Parse the list of symbolic identifiers to an affine map. ParseResult AffineParser::parseDimAndOptionalSymbolIdList(unsigned &numDims, unsigned &numSymbols) { … } /// Parses an ambiguous affine map or integer set definition inline. ParseResult AffineParser::parseAffineMapOrIntegerSetInline(AffineMap &map, IntegerSet &set) { … } /// Parse an affine expresion definition inline, with given symbols. ParseResult AffineParser::parseAffineExprInline( ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet, AffineExpr &expr) { … } /// Parse an AffineMap where the dim and symbol identifiers are SSA ids. ParseResult AffineParser::parseAffineMapOfSSAIds(AffineMap &map, OpAsmParser::Delimiter delimiter) { … } /// Parse an AffineExpr where the dim and symbol identifiers are SSA ids. ParseResult AffineParser::parseAffineExprOfSSAIds(AffineExpr &expr) { … } /// Parse the range and sizes affine map definition inline. /// /// affine-map ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr /// /// multi-dim-affine-expr ::= `(` `)` /// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)` ParseResult AffineParser::parseAffineMapRange(unsigned numDims, unsigned numSymbols, AffineMap &result) { … } /// Parse an affine constraint. /// affine-constraint ::= affine-expr `>=` `affine-expr` /// | affine-expr `<=` `affine-expr` /// | affine-expr `==` `affine-expr` /// /// The constraint is normalized to /// affine-constraint ::= affine-expr `>=` `0` /// | affine-expr `==` `0` /// before returning. /// /// isEq is set to true if the parsed constraint is an equality, false if it /// is an inequality (greater than or equal). /// AffineExpr AffineParser::parseAffineConstraint(bool *isEq) { … } /// Parse the constraints that are part of an integer set definition. /// integer-set-inline /// ::= dim-and-symbol-id-lists `:` /// '(' affine-constraint-conjunction? ')' /// affine-constraint-conjunction ::= affine-constraint (`,` /// affine-constraint)* /// ParseResult AffineParser::parseIntegerSetConstraints(unsigned numDims, unsigned numSymbols, IntegerSet &result) { … } //===----------------------------------------------------------------------===// // Parser //===----------------------------------------------------------------------===// /// Parse an ambiguous reference to either and affine map or an integer set. ParseResult Parser::parseAffineMapOrIntegerSetReference(AffineMap &map, IntegerSet &set) { … } ParseResult Parser::parseAffineMapReference(AffineMap &map) { … } ParseResult Parser::parseAffineExprReference( ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet, AffineExpr &expr) { … } ParseResult Parser::parseIntegerSetReference(IntegerSet &set) { … } /// Parse an AffineMap of SSA ids. The callback 'parseElement' is used to /// parse SSA value uses encountered while parsing affine expressions. ParseResult Parser::parseAffineMapOfSSAIds(AffineMap &map, function_ref<ParseResult(bool)> parseElement, OpAsmParser::Delimiter delimiter) { … } /// Parse an AffineExpr of SSA ids. The callback `parseElement` is used to parse /// SSA value uses encountered while parsing. ParseResult Parser::parseAffineExprOfSSAIds(AffineExpr &expr, function_ref<ParseResult(bool)> parseElement) { … } static void parseAffineMapOrIntegerSet(StringRef inputStr, MLIRContext *context, AffineMap &map, IntegerSet &set) { … } AffineMap mlir::parseAffineMap(StringRef inputStr, MLIRContext *context) { … } IntegerSet mlir::parseIntegerSet(StringRef inputStr, MLIRContext *context) { … }