23 #include "llvm/Support/ErrorHandling.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "llvm/Support/SourceMgr.h"
26 #include "llvm/Support/raw_ostream.h"
38 enum AffineLowPrecOp {
47 enum AffineHighPrecOp {
59 class AffineParser :
public Parser {
61 AffineParser(
ParserState &state,
bool allowParsingSSAIds =
false,
63 :
Parser(state), allowParsingSSAIds(allowParsingSSAIds),
64 parseElement(parseElement) {}
66 ParseResult parseAffineMapRange(
unsigned numDims,
unsigned numSymbols,
70 parseAffineExprInline(
ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet,
72 ParseResult parseIntegerSetConstraints(
unsigned numDims,
unsigned numSymbols,
80 AffineLowPrecOp consumeIfLowPrecOp();
81 AffineHighPrecOp consumeIfHighPrecOp();
85 ParseResult parseSymbolIdList(
unsigned &numSymbols);
86 ParseResult parseDimAndOptionalSymbolIdList(
unsigned &numDims,
87 unsigned &numSymbols);
109 bool allowParsingSSAIds;
111 unsigned numDimOperands = 0;
112 unsigned numSymbolOperands = 0;
127 emitError(opLoc,
"non-affine expression: at least one of the multiply "
128 "operands has to be either a constant or symbolic");
133 if (!rhs.isSymbolicOrConstant()) {
134 emitError(opLoc,
"non-affine expression: right operand of floordiv "
135 "has to be either a constant or symbolic");
140 if (!rhs.isSymbolicOrConstant()) {
141 emitError(opLoc,
"non-affine expression: right operand of ceildiv "
142 "has to be either a constant or symbolic");
147 if (!rhs.isSymbolicOrConstant()) {
148 emitError(opLoc,
"non-affine expression: right operand of mod "
149 "has to be either a constant or symbolic");
154 llvm_unreachable(
"can't create affine expression for null high prec op");
157 llvm_unreachable(
"Unknown AffineHighPrecOp");
164 case AffineLowPrecOp::Add:
166 case AffineLowPrecOp::Sub:
168 case AffineLowPrecOp::LNoOp:
169 llvm_unreachable(
"can't create affine expression for null low prec op");
172 llvm_unreachable(
"Unknown AffineLowPrecOp");
177 AffineLowPrecOp AffineParser::consumeIfLowPrecOp() {
178 switch (getToken().getKind()) {
180 consumeToken(Token::plus);
181 return AffineLowPrecOp::Add;
183 consumeToken(Token::minus);
184 return AffineLowPrecOp::Sub;
186 return AffineLowPrecOp::LNoOp;
192 AffineHighPrecOp AffineParser::consumeIfHighPrecOp() {
193 switch (getToken().getKind()) {
195 consumeToken(Token::star);
197 case Token::kw_floordiv:
198 consumeToken(Token::kw_floordiv);
200 case Token::kw_ceildiv:
201 consumeToken(Token::kw_ceildiv);
204 consumeToken(Token::kw_mod);
221 AffineHighPrecOp llhsOp,
223 AffineExpr lhs = parseAffineOperandExpr(llhs);
228 auto opLoc = getToken().getLoc();
229 if (AffineHighPrecOp op = consumeIfHighPrecOp()) {
234 return parseAffineHighPrecOpExpr(expr, op, opLoc);
237 return parseAffineHighPrecOpExpr(lhs, op, opLoc);
251 AffineExpr AffineParser::parseParentheticalExpr() {
252 if (parseToken(Token::l_paren,
"expected '('"))
254 if (getToken().is(Token::r_paren))
255 return emitError(
"no expression inside parentheses"),
nullptr;
257 auto expr = parseAffineExpr();
258 if (!expr || parseToken(Token::r_paren,
"expected ')'"))
268 if (parseToken(Token::minus,
"expected '-'"))
271 AffineExpr operand = parseAffineOperandExpr(lhs);
278 return emitError(
"missing operand of negation"),
nullptr;
279 return (-1) * operand;
286 return token.
isAny(Token::bare_identifier, Token::inttype) ||
295 return emitWrongTokenError(
"expected bare identifier"),
nullptr;
297 StringRef sRef = getTokenSpelling();
298 for (
auto entry : dimsAndSymbols) {
299 if (entry.first == sRef) {
305 return emitWrongTokenError(
"use of undeclared identifier"),
nullptr;
309 AffineExpr AffineParser::parseSSAIdExpr(
bool isSymbol) {
310 if (!allowParsingSSAIds)
311 return emitWrongTokenError(
"unexpected ssa identifier"),
nullptr;
312 if (getToken().isNot(Token::percent_identifier))
313 return emitWrongTokenError(
"expected ssa identifier"),
nullptr;
314 auto name = getTokenSpelling();
316 for (
auto entry : dimsAndSymbols) {
317 if (entry.first == name) {
318 consumeToken(Token::percent_identifier);
323 if (parseElement(isSymbol))
325 auto idExpr = isSymbol
328 dimsAndSymbols.push_back({name, idExpr});
332 AffineExpr AffineParser::parseSymbolSSAIdExpr() {
333 if (parseToken(Token::kw_symbol,
"expected symbol keyword") ||
334 parseToken(Token::l_paren,
"expected '(' at start of SSA symbol"))
339 if (parseToken(Token::r_paren,
"expected ')' at end of SSA symbol"))
348 auto val = getToken().getUInt64IntegerValue();
349 if (!val.has_value() || (int64_t)*val < 0)
350 return emitError(
"constant too large for index"),
nullptr;
352 consumeToken(Token::integer);
353 return builder.getAffineConstantExpr((int64_t)*val);
366 switch (getToken().getKind()) {
367 case Token::kw_symbol:
368 return parseSymbolSSAIdExpr();
369 case Token::percent_identifier:
370 return parseSSAIdExpr(
false);
372 return parseIntegerExpr();
374 return parseParentheticalExpr();
376 return parseNegateExpression(lhs);
377 case Token::kw_ceildiv:
378 case Token::kw_floordiv:
381 return parseBareIdExpr();
385 emitError(
"missing right operand of binary operator");
387 emitError(
"missing left operand of binary operator");
392 return parseBareIdExpr();
395 emitError(
"missing right operand of binary operator");
424 AffineLowPrecOp llhsOp) {
426 if (!(lhs = parseAffineOperandExpr(llhs)))
430 if (AffineLowPrecOp lOp = consumeIfLowPrecOp()) {
433 return parseAffineLowPrecOpExpr(sum, lOp);
436 return parseAffineLowPrecOpExpr(lhs, lOp);
438 auto opLoc = getToken().getLoc();
439 if (AffineHighPrecOp hOp = consumeIfHighPrecOp()) {
442 AffineExpr highRes = parseAffineHighPrecOpExpr(lhs, hOp, opLoc);
453 if (AffineLowPrecOp nextOp = consumeIfLowPrecOp())
454 return parseAffineLowPrecOpExpr(expr, nextOp);
480 return parseAffineLowPrecOpExpr(
nullptr, AffineLowPrecOp::LNoOp);
488 return emitWrongTokenError(
"expected bare identifier");
490 auto name = getTokenSpelling();
491 for (
auto entry : dimsAndSymbols) {
492 if (entry.first == name)
493 return emitError(
"redefinition of identifier '" + name +
"'");
497 dimsAndSymbols.push_back({name, idExpr});
502 ParseResult AffineParser::parseDimIdList(
unsigned &numDims) {
505 return parseIdentifierDefinition(dimension);
508 " in dimensional identifier list");
512 ParseResult AffineParser::parseSymbolIdList(
unsigned &numSymbols) {
515 return parseIdentifierDefinition(symbol);
523 AffineParser::parseDimAndOptionalSymbolIdList(
unsigned &numDims,
524 unsigned &numSymbols) {
525 if (parseDimIdList(numDims)) {
528 if (!getToken().is(Token::l_square)) {
532 return parseSymbolIdList(numSymbols);
538 unsigned numDims = 0, numSymbols = 0;
541 if (parseDimAndOptionalSymbolIdList(numDims, numSymbols))
544 if (consumeIf(Token::arrow))
545 return parseAffineMapRange(numDims, numSymbols, map);
547 if (parseToken(Token::colon,
"expected '->' or ':'"))
549 return parseIntegerSetConstraints(numDims, numSymbols, set);
555 dimsAndSymbols.assign(symbolSet.begin(), symbolSet.end());
556 expr = parseAffineExpr();
557 return success(expr !=
nullptr);
562 AffineParser::parseAffineMapOfSSAIds(
AffineMap &map,
567 auto elt = parseAffineExpr();
568 exprs.push_back(elt);
580 map =
AffineMap::get(numDimOperands, dimsAndSymbols.size() - numDimOperands,
587 expr = parseAffineExpr();
588 return success(expr !=
nullptr);
597 ParseResult AffineParser::parseAffineMapRange(
unsigned numDims,
602 auto elt = parseAffineExpr();
604 exprs.push_back(elt);
613 " in affine map range"))
634 AffineExpr AffineParser::parseAffineConstraint(
bool *isEq) {
640 if (consumeIf(Token::greater) && consumeIf(Token::equal)) {
645 return lhsExpr - rhsExpr;
649 if (consumeIf(Token::less) && consumeIf(Token::equal)) {
654 return rhsExpr - lhsExpr;
658 if (consumeIf(Token::equal) && consumeIf(Token::equal)) {
663 return lhsExpr - rhsExpr;
666 return emitError(
"expected '== affine-expr' or '>= affine-expr' at end of "
667 "affine constraint"),
678 ParseResult AffineParser::parseIntegerSetConstraints(
unsigned numDims,
685 auto elt = parseAffineConstraint(&isEq);
688 constraints.push_back(elt);
689 isEqs.push_back(isEq);
696 " in integer set constraint list"))
700 if (constraints.empty()) {
719 return AffineParser(
state).parseAffineMapOrIntegerSetInline(map, set);
727 return emitError(curLoc,
"expected AffineMap, but got IntegerSet");
732 return AffineParser(
state).parseAffineExprInline(symbolSet, expr);
740 return emitError(curLoc,
"expected IntegerSet, but got AffineMap");
750 return AffineParser(
state,
true, parseElement)
751 .parseAffineMapOfSSAIds(map, delimiter);
759 return AffineParser(
state,
true, parseElement)
760 .parseAffineExprOfSSAIds(expr);
765 llvm::SourceMgr sourceMgr;
766 auto memBuffer = llvm::MemoryBuffer::getMemBuffer(
767 inputStr,
"<mlir_parser_buffer>",
769 sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc());
772 ParserState state(sourceMgr, config, symbolState,
nullptr,
781 if (endTok.
isNot(Token::eof)) {
792 "expected string to represent AffineMap, but got IntegerSet instead");
801 "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 success/failure for parsing-like operations that find it important to chain tog...
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-...
Detect if any of the given parameter types has a sub-element handler.
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
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.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
@ 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.