Add some scaffolding for parsing affine maps:
- parsing affine map identifiers
- place-holder classes for AffineMap
- module contains a list of affine maps (defined at the top level).
PiperOrigin-RevId: 202336919
diff --git a/include/mlir/IR/AffineExpr.h b/include/mlir/IR/AffineExpr.h
new file mode 100644
index 0000000..4d8516c
--- /dev/null
+++ b/include/mlir/IR/AffineExpr.h
@@ -0,0 +1,36 @@
+//===- AffineMap.h - MLIR Affine Map Class ----------------------*- C++ -*-===//
+//
+// Copyright 2019 The MLIR Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// =============================================================================
+//
+// An affine expression is an affine combination of dimension identifiers and
+// symbols, including ceildiv/floordiv/mod by a constant integer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_IR_AFFINE_EXPR_H
+#define MLIR_IR_AFFINE_EXPR_H
+
+namespace mlir {
+
+class AffineExpr {
+ public:
+ AffineExpr();
+ // TODO(andydavis,bondhugula) Implement affine expressions.
+};
+
+} // end namespace mlir
+
+#endif // MLIR_IR_AFFINE_EXPR_H
diff --git a/include/mlir/IR/AffineMap.h b/include/mlir/IR/AffineMap.h
new file mode 100644
index 0000000..af1df96
--- /dev/null
+++ b/include/mlir/IR/AffineMap.h
@@ -0,0 +1,55 @@
+//===- AffineMap.h - MLIR Affine Map Class ----------------------*- C++ -*-===//
+//
+// Copyright 2019 The MLIR Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// =============================================================================
+//
+// Affine maps are mathematical functions which map a list of dimension
+// identifiers and symbols, to multidimensional affine expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_IR_AFFINE_MAP_H
+#define MLIR_IR_AFFINE_MAP_H
+
+#include <vector>
+
+#include "mlir/Support/LLVM.h"
+
+namespace mlir {
+
+class AffineExpr;
+
+class AffineMap {
+ public:
+ // Constructs an AffineMap with 'dimCount' dimension identifiers, and
+ // 'symbolCount' symbols.
+ // TODO(andydavis) Pass in ArrayRef<AffineExpr*> to populate list of exprs.
+ AffineMap(unsigned dimCount, unsigned symbolCount);
+
+ // Prints affine map to 'os'.
+ void print(raw_ostream &os) const;
+
+ private:
+ // Number of dimensional indentifiers.
+ const unsigned dimCount;
+ // Number of symbols.
+ const unsigned symbolCount;
+ // TODO(andydavis) Do not use std::vector here (array size is not dynamic).
+ std::vector<AffineExpr*> exprs;
+};
+
+} // end namespace mlir
+
+#endif // MLIR_IR_AFFINE_MAP_H
diff --git a/lib/IR/AffineExpr.cpp b/lib/IR/AffineExpr.cpp
new file mode 100644
index 0000000..63d8d7d
--- /dev/null
+++ b/lib/IR/AffineExpr.cpp
@@ -0,0 +1,23 @@
+//===- AffineExpr.cpp - MLIR Affine Expr Classes --------------------------===//
+//
+// Copyright 2019 The MLIR Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// =============================================================================
+
+#include "mlir/IR/AffineExpr.h"
+
+using namespace mlir;
+
+AffineExpr::AffineExpr() {
+}
diff --git a/lib/IR/AffineMap.cpp b/lib/IR/AffineMap.cpp
new file mode 100644
index 0000000..83d1d23
--- /dev/null
+++ b/lib/IR/AffineMap.cpp
@@ -0,0 +1,31 @@
+//===- AffineMap.cpp - MLIR Affine Map Classes ----------------------------===//
+//
+// Copyright 2019 The MLIR Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// =============================================================================
+
+#include "mlir/IR/AffineMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace mlir;
+
+AffineMap::AffineMap(unsigned dimCount, unsigned symbolCount)
+ : dimCount(dimCount), symbolCount(symbolCount) {
+}
+
+void AffineMap::print(raw_ostream &os) const {
+ // TODO(andydavis) Print out affine map based on dimensionCount and
+ // symbolCount: (d0, d1) [S0, S1] -> (d0 + S0, d1 + S1)
+}
diff --git a/lib/Parser/Lexer.cpp b/lib/Parser/Lexer.cpp
index 7f53886..209f988 100644
--- a/lib/Parser/Lexer.cpp
+++ b/lib/Parser/Lexer.cpp
@@ -25,6 +25,12 @@
using llvm::SMLoc;
using llvm::SourceMgr;
+// Returns true if 'c' is an allowable puncuation character: [$._-]
+// Returns false otherwise.
+static bool isPunct(char c) {
+ return c == '$' || c == '.' || c == '_' || c == '-';
+}
+
Lexer::Lexer(llvm::SourceMgr &sourceMgr,
const SMDiagnosticHandlerTy &errorReporter)
: sourceMgr(sourceMgr), errorReporter(errorReporter) {
@@ -92,6 +98,7 @@
case ';': return lexComment();
case '@': return lexAtIdentifier(tokStart);
+ case '#': return lexAffineMapId(tokStart);
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
@@ -174,6 +181,30 @@
return formToken(Token::at_identifier, tokStart);
}
+/// Lex an '#foo' identifier.
+///
+/// affine-map-id ::= `#` suffix-id
+/// suffix-id ::= digit+ | (letter|id-punct) (letter|id-punct|digit)*
+///
+// TODO(andydavis) Consider moving suffix-id parsing to a shared function
+// so it can be re-used to parse %suffix-id.
+Token Lexer::lexAffineMapId(const char *tokStart) {
+ // Parse suffix-id.
+ if (isdigit(*curPtr)) {
+ // If suffix-id starts with a digit, the rest must be digits.
+ while (isdigit(*curPtr)) {
+ ++curPtr;
+ }
+ } else if (isalpha(*curPtr) || isPunct(*curPtr)) {
+ do {
+ ++curPtr;
+ } while (isalpha(*curPtr) || isdigit(*curPtr) || isPunct(*curPtr));
+ } else {
+ return emitError(curPtr-1, "invalid affine map id");
+ }
+ return formToken(Token::affine_map_id, tokStart);
+}
+
/// Lex an integer literal.
///
/// integer-literal ::= digit+ | `0x` hex_digit+
diff --git a/lib/Parser/Lexer.h b/lib/Parser/Lexer.h
index 139dfa6..0301a35 100644
--- a/lib/Parser/Lexer.h
+++ b/lib/Parser/Lexer.h
@@ -60,6 +60,7 @@
Token lexComment();
Token lexBareIdentifierOrKeyword(const char *tokStart);
Token lexAtIdentifier(const char *tokStart);
+ Token lexAffineMapId(const char *tokStart);
Token lexNumber(const char *tokStart);
};
diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp
index 5a79f1e..0d24972 100644
--- a/lib/Parser/Parser.cpp
+++ b/lib/Parser/Parser.cpp
@@ -21,6 +21,7 @@
#include "mlir/Parser.h"
#include "Lexer.h"
+#include "mlir/IR/AffineMap.h"
#include "mlir/IR/Module.h"
#include "mlir/IR/CFGFunction.h"
#include "mlir/IR/Types.h"
@@ -68,6 +69,11 @@
// This is the result module we are parsing into.
std::unique_ptr<Module> module;
+ // A map from affine map identifier to AffineMap.
+ // TODO(andydavis) Remove use of unique_ptr when AffineMaps are bump pointer
+ // allocated.
+ llvm::StringMap<std::unique_ptr<AffineMap>> affineMaps;
+
private:
// Helper methods.
@@ -121,6 +127,9 @@
Type *parseType();
ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
+ // Polyhedral structures
+ ParseResult parseAffineMapDef();
+
// Functions.
ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
ParseResult parseExtFunc();
@@ -461,6 +470,33 @@
}
//===----------------------------------------------------------------------===//
+// Polyhedral structures.
+//===----------------------------------------------------------------------===//
+
+/// Affine map declaration.
+///
+/// affine-map-def ::= affine-map-id `=` affine-map-inline
+/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
+/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
+/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
+///
+ParseResult Parser::parseAffineMapDef() {
+ assert(curToken.is(Token::affine_map_id));
+
+ StringRef affineMapId = curToken.getSpelling().drop_front();
+ // Check that 'affineMapId' is unique.
+ // TODO(andydavis) Add a unit test for this case.
+ if (affineMaps.count(affineMapId) > 0)
+ return emitError("encountered non-unique affine map id");
+
+ consumeToken(Token::affine_map_id);
+
+ // TODO(andydavis,bondhugula) Parse affine map definition.
+ affineMaps[affineMapId].reset(new AffineMap(1, 0));
+ return ParseSuccess;
+}
+
+//===----------------------------------------------------------------------===//
// Functions
//===----------------------------------------------------------------------===//
@@ -701,6 +737,9 @@
case Token::kw_cfgfunc:
if (parseCFGFunc()) return nullptr;
break;
+ case Token::affine_map_id:
+ if (parseAffineMapDef()) return nullptr;
+ break;
// TODO: mlfunc, affine entity declarations, etc.
}
diff --git a/lib/Parser/Token.h b/lib/Parser/Token.h
index dde0722..8a654a1 100644
--- a/lib/Parser/Token.h
+++ b/lib/Parser/Token.h
@@ -34,6 +34,7 @@
// Identifiers.
bare_identifier, // foo
at_identifier, // @foo
+ affine_map_id, // #foo
// TODO: @@foo, etc.
integer, // 42