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